Skip to content

Commit

Permalink
refactor cosec-jwt (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahoo-Wang authored Dec 14, 2022
1 parent dcd1b34 commit 4a8d2b8
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package me.ahoo.cosec.jwt
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import me.ahoo.cosec.api.principal.CoSecPrincipal
import me.ahoo.cosec.api.principal.PolicyCapable
import me.ahoo.cosec.api.principal.RoleCapable
import me.ahoo.cosec.api.tenant.TenantCapable
import me.ahoo.cosec.api.token.CompositeToken
Expand Down Expand Up @@ -51,7 +52,8 @@ class JwtTokenConverter(
.withJWTId(accessTokenId)
.withSubject(principal.id)
.withClaim(CoSecPrincipal.NAME_KEY, principal.name)
.withClaim(RoleCapable.ROLE_KEY, principal.roles.joinToString(Jwts.ROLE_DELIMITER))
.withClaim(PolicyCapable.POLICY_KEY, principal.policies.toList())
.withClaim(RoleCapable.ROLE_KEY, principal.roles.toList())
.withPayload(payloadClaims)
.withIssuedAt(now)
.withExpiresAt(accessTokenExp)
Expand Down
9 changes: 4 additions & 5 deletions cosec-jwt/src/main/kotlin/me/ahoo/cosec/jwt/Jwts.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import me.ahoo.cosec.token.SimpleTokenTenantPrincipal
* @author ahoo wang
*/
object Jwts {
const val ROLE_DELIMITER = ","
const val AUTHORIZATION_KEY = "authorization"
const val TOKEN_PREFIX = "Bearer "
private val jwtParser = JWT()
Expand Down Expand Up @@ -74,11 +73,11 @@ object Jwts {
.claims
.filter { !isRegisteredClaim(it.key) }

val policyStr = decodedAccessToken.getClaim(PolicyCapable.POLICY_KEY).asString()
val policyClaim = decodedAccessToken.getClaim(PolicyCapable.POLICY_KEY)
val policies = if (policyClaim.isMissing) emptySet() else policyClaim.asList(String::class.java).toSet()

val policies = if (policyStr.isNullOrEmpty()) emptySet() else policyStr.split(ROLE_DELIMITER).toSet()
val rolesStr = decodedAccessToken.getClaim(RoleCapable.ROLE_KEY).asString()
val roles = if (rolesStr.isNullOrEmpty()) emptySet() else rolesStr.split(ROLE_DELIMITER).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, name, policies, roles, attrs)
val tenantId = decodedAccessToken.getClaim(RequestTenantIdParser.TENANT_ID_KEY).asString()
val tokenPrincipal = SimpleTokenPrincipal(accessTokenId, principal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package me.ahoo.cosec.jwt

import me.ahoo.cosec.api.token.CompositeToken
import me.ahoo.cosec.principal.SimplePrincipal
import me.ahoo.cosec.principal.SimpleTenantPrincipal
import me.ahoo.cosid.test.MockIdGenerator
import org.hamcrest.MatcherAssert.assertThat
Expand All @@ -26,8 +27,16 @@ internal class JwtTokenConverterTest {
var jwtTokenConverter = JwtTokenConverter(MockIdGenerator.INSTANCE, JwtFixture.ALGORITHM)

@Test
fun asToken() {
fun anonymousAsToken() {
val token: CompositeToken = jwtTokenConverter.asToken(SimpleTenantPrincipal.ANONYMOUS)
assertThat(token, notNullValue())
}

@Test
fun asToken() {
val principal =
SimplePrincipal("id", "name", setOf("policyId"), setOf("roleId"), mapOf("attr_key" to "attr_value"))
val token: CompositeToken = jwtTokenConverter.asToken(principal)
assertThat(token, notNullValue())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import me.ahoo.cosec.api.authorization.Authorization
import me.ahoo.cosec.api.authorization.AuthorizeResult
import me.ahoo.cosec.context.request.RequestTenantIdParser
import me.ahoo.cosec.jwt.Jwts
import me.ahoo.cosec.principal.SimplePrincipal
import me.ahoo.cosec.webflux.ServerWebExchanges.setSecurityContext
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
Expand Down Expand Up @@ -113,8 +114,10 @@ internal class ReactiveAuthorizationFilterTest {
ReactiveRequestParser(ReactiveRequestTenantIdParser.INSTANCE),
authorization
)
val principal = SimplePrincipal("id", "name")
val accessToken = SecurityContextParserSpec.createAccessToken(principal)
val tokenHeader =
Jwts.TOKEN_PREFIX + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJpZCIsInJvbGVzIjoiIiwibmFtZSI6Im5hbWUiLCJleHAiOjE2Njg4MjU3NzksImlhdCI6MTY2ODgyNTE3OSwianRpIjoidGVzdF8zUjg5bENYVkIifQ.EystLtgrZDr61K4pjOHsMn0M0FyXOfqdAxNmcK3Nqnw"
Jwts.TOKEN_PREFIX + accessToken
val exchange = mockk<ServerWebExchange>() {
every { request.headers.getFirst(Jwts.AUTHORIZATION_KEY) } returns tokenHeader
every { request.headers.getFirst(RequestTenantIdParser.TENANT_ID_KEY) } returns "tenantId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,15 @@ import org.springframework.web.server.ServerWebExchange

abstract class SecurityContextParserSpec {

val algorithm = Algorithm.HMAC256("FyN0Igd80Gas8stTavArGKOYnS9uLWGA_")
val jwtTokenConverter = JwtTokenConverter(MockIdGenerator.INSTANCE, algorithm)
companion object {
val algorithm = Algorithm.HMAC256("FyN0Igd80Gas8stTavArGKOYnS9uLWGA_")
val jwtTokenConverter = JwtTokenConverter(MockIdGenerator.INSTANCE, algorithm)
fun createAccessToken(principal: SimplePrincipal): String {
return jwtTokenConverter.asToken(principal).accessToken
}
}


val jwtTokenVerifier = JwtTokenVerifier(algorithm)
abstract fun createSecurityContextParser(): SecurityContextParser<ServerWebExchange>

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# limitations under the License.
#
group=me.ahoo.cosec
version=1.4.0
version=1.5.0
description=RBAC-based And Policy-based Multi-Tenant Reactive Security Framework
website=https://github.com/Ahoo-Wang/CoSec
issues=https://github.com/Ahoo-Wang/CoSec/issues
Expand Down

0 comments on commit 4a8d2b8

Please sign in to comment.