blob: bdaa0ec35105fd182ff7e1fdda431b4b1625e088 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
package tech.libeufin.nexus
import UtilError
import io.ktor.http.*
import io.ktor.server.request.*
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.transactions.transaction
import tech.libeufin.nexus.server.Permission
import tech.libeufin.nexus.server.PermissionQuery
import tech.libeufin.util.*
/**
* HTTP basic auth. Throws error if password is wrong,
* and makes sure that the user exists in the system.
*
* @return user entity
*/
fun authenticateRequest(request: ApplicationRequest): NexusUserEntity {
return transaction {
val (username, password) = getHTTPBasicAuthCredentials(request)
val user = NexusUserEntity.find {
NexusUsersTable.username eq username
}.firstOrNull()
if (user == null) {
throw UtilError(HttpStatusCode.Unauthorized,
"Unknown user '$username'",
LibeufinErrorCode.LIBEUFIN_EC_AUTHENTICATION_FAILED
)
}
CryptoUtil.checkPwOrThrow(password, user.passwordHash)
user
}
}
fun requireSuperuser(request: ApplicationRequest): NexusUserEntity {
return transaction {
val user = authenticateRequest(request)
if (!user.superuser) {
throw NexusError(HttpStatusCode.Forbidden, "must be superuser")
}
user
}
}
fun findPermission(p: Permission): NexusPermissionEntity? {
return transaction {
NexusPermissionEntity.find {
((NexusPermissionsTable.subjectType eq p.subjectType)
and (NexusPermissionsTable.subjectId eq p.subjectId)
and (NexusPermissionsTable.resourceType eq p.resourceType)
and (NexusPermissionsTable.resourceId eq p.resourceId)
and (NexusPermissionsTable.permissionName eq p.permissionName.lowercase()))
}.firstOrNull()
}
}
/**
* Require that the authenticated user has at least one of the listed permissions.
*
* Throws a NexusError if the authenticated user for the request doesn't have any of
* listed the permissions. It returns the username of the authorized user.
*/
fun ApplicationRequest.requirePermission(vararg perms: PermissionQuery): String {
val username = transaction {
val user = authenticateRequest(this@requirePermission)
if (user.superuser) {
return@transaction user.username
}
var foundPermission = false
for (pr in perms) {
val p = Permission("user", user.username, pr.resourceType, pr.resourceId, pr.permissionName.lowercase())
val existingPerm = findPermission(p)
if (existingPerm != null) {
foundPermission = true
break
}
}
if (!foundPermission) {
val possiblePerms =
perms.joinToString(" | ") { "${it.resourceId} ${it.resourceType} ${it.permissionName}" }
throw NexusError(
HttpStatusCode.Forbidden,
"User ${user.username} has insufficient permissions (needs $possiblePerms)."
)
}
user.username
}
return username
}
|