Skip to content

Commit

Permalink
Feature: support context.principal.attributes. for `DefaultPartExtr…
Browse files Browse the repository at this point in the history
…actor` (#51)
  • Loading branch information
Ahoo-Wang authored Jan 4, 2023
1 parent 8f7302e commit 26e78b2
Show file tree
Hide file tree
Showing 9 changed files with 27 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ interface CoSecPrincipal : Principal, PolicyCapable, RoleCapable {
return id
}

val attrs: Map<String, Any>
val attributes: Map<String, String>
fun anonymous(): Boolean {
return ANONYMOUS_ID == id
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CoSecPrincipalTest {
throw UnsupportedOperationException()
}

override val attrs: Map<String, Any>
override val attributes: Map<String, String>
get() = throw UnsupportedOperationException()
override val policies: Set<String>
get() = throw UnsupportedOperationException()
Expand All @@ -50,7 +50,7 @@ class CoSecPrincipalTest {
throw UnsupportedOperationException()
}

override val attrs: Map<String, Any>
override val attributes: Map<String, String>
get() = throw UnsupportedOperationException()
override val policies: Set<String>
get() = throw UnsupportedOperationException()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object SecurityContextParts {
const val TENANT_ID = PREFIX + "tenantId"
const val PRINCIPAL_PREFIX = PREFIX + "principal."
const val PRINCIPAL_ID = PRINCIPAL_PREFIX + "id"
const val PRINCIPAL_NAME = PRINCIPAL_PREFIX + "name"
const val PRINCIPAL_ATTRIBUTES_PREFIX = PRINCIPAL_PREFIX + "attributes."
}

data class DefaultPartExtractor(val part: String) : PartExtractor {
Expand All @@ -51,12 +51,16 @@ data class DefaultPartExtractor(val part: String) : PartExtractor {
RequestParts.REFERER -> request.referer
SecurityContextParts.TENANT_ID -> securityContext.tenant.tenantId
SecurityContextParts.PRINCIPAL_ID -> securityContext.principal.id
SecurityContextParts.PRINCIPAL_NAME -> securityContext.principal.name
else -> {
if (part.startsWith(RequestParts.HEADER_PREFIX)) {
val headerKey = part.substring(RequestParts.HEADER_PREFIX.length)
return request.getHeader(headerKey)
}
if (part.startsWith(SecurityContextParts.PRINCIPAL_ATTRIBUTES_PREFIX)) {
val headerKey = part.substring(SecurityContextParts.PRINCIPAL_ATTRIBUTES_PREFIX.length)
return securityContext.principal.attributes[headerKey].orEmpty()
}

throw IllegalArgumentException("Unsupported part: $part")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ data class SimplePrincipal(
override val id: String,
override val policies: Set<String> = emptySet(),
override val roles: Set<String> = emptySet(),
override val attrs: Map<String, Any> = emptyMap()
override val attributes: Map<String, String> = emptyMap()
) : CoSecPrincipal {

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,18 @@ class DefaultPartExtractorTest {
}

@Test
fun extractContextPrincipalName() {
fun extractContextPrincipalAttributes() {
val context: SecurityContext = mockk {
every { principal.name } returns "principal.name"
every { principal.attributes["key"] } returns "value"
every { principal.attributes["not_exist"] } returns null
}
assertThat(
DefaultPartExtractor(SecurityContextParts.PRINCIPAL_NAME).extract(mockk(), context),
equalTo("principal.name")
DefaultPartExtractor(SecurityContextParts.PRINCIPAL_ATTRIBUTES_PREFIX + "key").extract(mockk(), context),
equalTo("value")
)
assertThat(
DefaultPartExtractor(SecurityContextParts.PRINCIPAL_ATTRIBUTES_PREFIX + "not_exist").extract(mockk(), context),
equalTo("")
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class JwtTokenConverter(
val accessTokenId = idGenerator.generateAsString()
val now = Date()
val accessTokenExp = Date(System.currentTimeMillis() + accessTokenValidity.toMillis())
val payloadClaims: Map<String, *> = principal.attrs
val payloadClaims: Map<String, *> = principal.attributes
.filter {
!Jwts.isRegisteredClaim(it.key)
}
Expand Down
8 changes: 5 additions & 3 deletions cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/Jwts.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,18 @@ object Jwts {
fun <T : TokenPrincipal> asPrincipal(decodedAccessToken: DecodedJWT): T {
val accessTokenId = decodedAccessToken.id
val principalId = decodedAccessToken.subject
val attrs = decodedAccessToken
val attributes = decodedAccessToken
.claims
.filter { !isRegisteredClaim(it.key) }

.mapValues {
it.value.asString()
}
val policyClaim = decodedAccessToken.getClaim(PolicyCapable.POLICY_KEY)
val policies = if (policyClaim.isMissing) emptySet() else policyClaim.asList(String::class.java).toSet()

val rolesClaim = decodedAccessToken.getClaim(RoleCapable.ROLE_KEY)
val roles = if (rolesClaim.isMissing) emptySet() else rolesClaim.asList(String::class.java).toSet()
val principal = SimplePrincipal(principalId, policies, roles, attrs)
val principal = SimplePrincipal(principalId, policies, roles, attributes)
val tenantId = decodedAccessToken.getClaim(TENANT_ID_KEY).asString()
val tokenPrincipal = SimpleTokenPrincipal(accessTokenId, principal)
if (tenantId.isNullOrEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object DirectOAuthClientPrincipalConverter : OAuthClientPrincipalConverter {
id = asClientUserId(client, authUser),
policies = emptySet(),
roles = emptySet(),
attrs = authUser.rawInfo
attributes = authUser.rawInfo.mapValues { it.value.toString() }
).toMono()
}

Expand Down
2 changes: 1 addition & 1 deletion document/cosec-policy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"request.header.",
"context.tenantId",
"context.principal.id",
"context.principal.name"
"context.principal.attributes."
]
},
"pathOptions": {
Expand Down

0 comments on commit 26e78b2

Please sign in to comment.