Skip to content

Commit

Permalink
feat: merge service account id to subject id
Browse files Browse the repository at this point in the history
- if a client has service account enabled, the sub presented in the JWT is the service account id
- the client id is never used for authentication purposes and can then be dropped (a client cannot authenticate by itself if service account is not enabled)
  • Loading branch information
bobeal committed Apr 28, 2024
1 parent 3c80bbc commit ba7eafc
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ data class SubjectReferential(
val subjectId: Sub,
val subjectType: SubjectType,
val subjectInfo: Json,
val serviceAccountId: Sub? = null,
val globalRoles: List<GlobalRole>? = null,
val groupsMemberships: List<Sub>? = null
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,16 @@ class SubjectReferentialService(
.sql(
"""
INSERT INTO subject_referential
(subject_id, subject_type, subject_info, service_account_id, global_roles,
groups_memberships)
VALUES (:subject_id, :subject_type, :subject_info, :service_account_id, :global_roles,
:groups_memberships)
(subject_id, subject_type, subject_info, global_roles, groups_memberships)
VALUES (:subject_id, :subject_type, :subject_info, :global_roles, :groups_memberships)
ON CONFLICT (subject_id)
DO UPDATE SET service_account_id = :service_account_id,
global_roles = :global_roles,
DO UPDATE SET global_roles = :global_roles,
groups_memberships = :groups_memberships
""".trimIndent()
)
.bind("subject_id", subjectReferential.subjectId)
.bind("subject_type", subjectReferential.subjectType.toString())
.bind("subject_info", subjectReferential.subjectInfo)
.bind("service_account_id", subjectReferential.serviceAccountId)
.bind("global_roles", subjectReferential.globalRoles?.map { it.key }?.toTypedArray())
.bind("groups_memberships", subjectReferential.groupsMemberships?.toTypedArray())
.execute()
Expand All @@ -53,7 +49,7 @@ class SubjectReferentialService(
"""
SELECT *
FROM subject_referential
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", sub)
Expand All @@ -65,18 +61,15 @@ class SubjectReferentialService(
databaseClient
.sql(
"""
SELECT subject_id, service_account_id, groups_memberships
SELECT subject_id, groups_memberships
FROM subject_referential
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", (sub as Some).value)
.oneToResult(AccessDeniedException("No subject information found for ${sub.value}")) {
val subs = toOptionalList<Sub>(it["groups_memberships"]).orEmpty()
toOptionalList<Sub>(it["groups_memberships"]).orEmpty()
.plus(it["subject_id"] as Sub)
if (it["service_account_id"] != null)
subs.plus(it["service_account_id"] as Sub)
else subs
}

suspend fun getGroups(sub: Option<Sub>, offset: Int, limit: Int): List<Group> =
Expand All @@ -86,7 +79,7 @@ class SubjectReferentialService(
WITH groups_memberships AS (
SELECT unnest(groups_memberships) as groups
FROM subject_referential
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
)
SELECT subject_id AS group_id, (subject_info->'value'->>'name') AS name
FROM subject_referential
Expand Down Expand Up @@ -114,7 +107,7 @@ class SubjectReferentialService(
SELECT count(sr.g_m) as count
FROM subject_referential
CROSS JOIN LATERAL unnest(subject_referential.groups_memberships) as sr(g_m)
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", (sub as Some).value)
Expand All @@ -127,7 +120,7 @@ class SubjectReferentialService(
WITH groups_memberships AS (
SELECT distinct(unnest(groups_memberships)) as groups
FROM subject_referential
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
)
SELECT subject_id AS group_id, (subject_info->'value'->>'name') AS name,
(subject_id IN (SELECT groups FROM groups_memberships)) AS is_member
Expand Down Expand Up @@ -223,7 +216,7 @@ class SubjectReferentialService(
"""
UPDATE subject_referential
SET global_roles = :global_roles
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", sub)
Expand All @@ -237,7 +230,7 @@ class SubjectReferentialService(
"""
UPDATE subject_referential
SET global_roles = null
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", sub)
Expand All @@ -250,7 +243,7 @@ class SubjectReferentialService(
"""
UPDATE subject_referential
SET groups_memberships = array_append(groups_memberships, :group_id::text)
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", sub)
Expand All @@ -264,7 +257,7 @@ class SubjectReferentialService(
"""
UPDATE subject_referential
SET groups_memberships = array_remove(groups_memberships, :group_id::text)
WHERE (subject_id = :subject_id OR service_account_id = :subject_id)
WHERE subject_id = :subject_id
""".trimIndent()
)
.bind("subject_id", sub)
Expand All @@ -277,7 +270,7 @@ class SubjectReferentialService(
.sql(
"""
UPDATE subject_referential
SET service_account_id = :service_account_id
SET subject_id = :service_account_id
WHERE subject_id = :subject_id
""".trimIndent()
)
Expand Down Expand Up @@ -314,7 +307,6 @@ class SubjectReferentialService(
subjectId = row["subject_id"] as Sub,
subjectType = SubjectType.valueOf(row["subject_type"] as String),
subjectInfo = toJson(row["subject_info"]),
serviceAccountId = row["service_account_id"] as? Sub,
globalRoles = toOptionalList<String>(row["global_roles"])
?.mapNotNull { GlobalRole.forKey(it).getOrElse { null } },
groupsMemberships = toOptionalList(row["groups_memberships"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,30 +111,34 @@ class IAMListener(
val operationPayload = attributeAppendEvent.operationPayload.deserializeAsMap()
val subjectUuid = attributeAppendEvent.entityId.extractSub()
mono {
if (attributeAppendEvent.attributeName == AUTH_TERM_ROLES) {
val newRoles = (operationPayload[JSONLD_VALUE_TERM] as List<*>).map {
GlobalRole.forKey(it as String)
}.flattenOption()
if (newRoles.isNotEmpty())
subjectReferentialService.setGlobalRoles(subjectUuid, newRoles)
else
subjectReferentialService.resetGlobalRoles(subjectUuid)
} else if (attributeAppendEvent.attributeName == AUTH_TERM_SID) {
val serviceAccountId = operationPayload[JSONLD_VALUE_TERM] as String
subjectReferentialService.addServiceAccountIdToClient(
subjectUuid,
serviceAccountId.extractSub()
)
} else if (attributeAppendEvent.attributeName == AUTH_TERM_IS_MEMBER_OF) {
val groupId = operationPayload[JSONLD_OBJECT] as String
subjectReferentialService.addGroupMembershipToUser(
subjectUuid,
groupId.extractSub()
)
} else {
BadRequestDataException(
"Received unknown attribute name: ${attributeAppendEvent.attributeName}"
).left()
when (attributeAppendEvent.attributeName) {
AUTH_TERM_ROLES -> {
val newRoles = (operationPayload[JSONLD_VALUE_TERM] as List<*>).map {
GlobalRole.forKey(it as String)
}.flattenOption()
if (newRoles.isNotEmpty())
subjectReferentialService.setGlobalRoles(subjectUuid, newRoles)
else
subjectReferentialService.resetGlobalRoles(subjectUuid)
}
AUTH_TERM_SID -> {
val serviceAccountId = operationPayload[JSONLD_VALUE_TERM] as String
subjectReferentialService.addServiceAccountIdToClient(
subjectUuid,
serviceAccountId.extractSub()
)
}
AUTH_TERM_IS_MEMBER_OF -> {
val groupId = operationPayload[JSONLD_OBJECT] as String
subjectReferentialService.addGroupMembershipToUser(
subjectUuid,
groupId.extractSub()
)
}
else ->
BadRequestDataException(
"Received unknown attribute name: ${attributeAppendEvent.attributeName}"
).left()
}
}.writeContextAndSubscribe(tenantName, attributeAppendEvent)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
update subject_referential
set subject_id = service_account_id
where service_account_id is not null
and subject_type = 'CLIENT';

alter table subject_referential
drop column service_account_id;
Original file line number Diff line number Diff line change
Expand Up @@ -543,12 +543,7 @@ class EntityAccessRightsServiceTests : WithTimescaleContainer {
fun `it should get other subject rights for all kinds of subjects`() = runTest {
createSubjectReferential(subjectUuid, SubjectType.USER, getSubjectInfoForUser("stellio"))
createSubjectReferential(groupUuid, SubjectType.GROUP, getSubjectInfoForGroup("Stellio Team"))
createSubjectReferential(
UUID.randomUUID().toString(),
SubjectType.CLIENT,
getSubjectInfoForClient("IoT Device"),
clientUuid
)
createSubjectReferential(clientUuid, SubjectType.CLIENT, getSubjectInfoForClient("IoT Device"))

entityAccessRightsService.setRoleOnEntity(subjectUuid, entityId01, AccessRight.R_CAN_WRITE).shouldSucceed()
entityAccessRightsService.setRoleOnEntity(groupUuid, entityId01, AccessRight.R_CAN_READ).shouldSucceed()
Expand Down Expand Up @@ -588,15 +583,13 @@ class EntityAccessRightsServiceTests : WithTimescaleContainer {
private suspend fun createSubjectReferential(
subjectId: String,
subjectType: SubjectType,
subjectInfo: Json,
serviceAccountId: String? = null
subjectInfo: Json
) {
subjectReferentialService.create(
SubjectReferential(
subjectId = subjectId,
subjectType = subjectType,
subjectInfo = subjectInfo,
serviceAccountId = serviceAccountId
subjectInfo = subjectInfo
)
)
}
Expand Down
Loading

0 comments on commit ba7eafc

Please sign in to comment.