From 1a59df461489ca4d625c5747c55d01c102bdb4bb Mon Sep 17 00:00:00 2001 From: Peyman Date: Wed, 11 Jun 2025 12:38:30 +0330 Subject: [PATCH] Fix api key token exchange error Assign role manually in auth-gateway instead of keycloak default roles --- .../opex/auth/config/KeycloakAdminConfig.kt | 14 +- .../nilin/opex/auth/config/WebClientConfig.kt | 8 +- .../co/nilin/opex/auth/proxy/KeycloakProxy.kt | 15 +- .../co/nilin/opex/auth/service/UserService.kt | 1 + .../keycloak-setup/realms/opex-realm.json | 293 ++++++++++++++++-- .../spi/ForcedRoleProtocolMapper.java | 73 +++++ .../org.keycloak.protocol.ProtocolMapper | 3 +- .../common/security/CustomJwtAuthConverter.kt | 19 +- 8 files changed, 377 insertions(+), 49 deletions(-) create mode 100644 auth-gateway/keycloak-setup/spi/src/main/java/co/nilin/opex/keycloak/spi/ForcedRoleProtocolMapper.java diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/KeycloakAdminConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/KeycloakAdminConfig.kt index ae9fa7633..4f87db169 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/KeycloakAdminConfig.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/KeycloakAdminConfig.kt @@ -1,6 +1,7 @@ package co.nilin.opex.auth.config import org.keycloak.admin.client.Keycloak +import org.keycloak.admin.client.KeycloakBuilder import org.keycloak.admin.client.resource.RealmResource import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -10,12 +11,13 @@ class KeycloakAdminConfig { @Bean fun keycloak(config: KeycloakConfig): Keycloak { - return Keycloak.getInstance( - config.url, - config.realm, - config.adminClient.id, - config.adminClient.secret, - ) + return KeycloakBuilder.builder() + .serverUrl(config.url) + .realm(config.realm) + .clientId(config.adminClient.id) + .clientSecret(config.adminClient.secret) + .grantType("client_credentials") + .build() } @Bean diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/WebClientConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/WebClientConfig.kt index 48ca6178e..88d8140e9 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/WebClientConfig.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/WebClientConfig.kt @@ -4,14 +4,20 @@ import org.springframework.beans.factory.annotation.Qualifier import org.springframework.cloud.client.loadbalancer.LoadBalanced import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.http.client.reactive.ReactorClientHttpConnector import org.springframework.web.reactive.function.client.WebClient +import org.zalando.logbook.Logbook +import org.zalando.logbook.netty.LogbookClientHandler +import reactor.netty.http.client.HttpClient @Configuration class WebClientConfig { @Bean("keycloakWebClient") - fun keycloakWebClient(keycloakConfig: KeycloakConfig): WebClient { + fun keycloakWebClient(keycloakConfig: KeycloakConfig, logbook: Logbook): WebClient { + val client = HttpClient.create().doOnConnected { it.addHandlerLast(LogbookClientHandler(logbook)) } return WebClient.builder() + .clientConnector(ReactorClientHttpConnector(client)) .baseUrl(keycloakConfig.url) .build() } diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/proxy/KeycloakProxy.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/proxy/KeycloakProxy.kt index 4699c8b6f..eb3a0cc42 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/proxy/KeycloakProxy.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/proxy/KeycloakProxy.kt @@ -3,9 +3,11 @@ package co.nilin.opex.auth.proxy import co.nilin.opex.auth.config.KeycloakConfig import co.nilin.opex.auth.model.* import co.nilin.opex.common.OpexError +import co.nilin.opex.common.utils.LoggerDelegate import kotlinx.coroutines.reactive.awaitFirstOrElse import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull +import org.keycloak.admin.client.resource.RealmResource import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus @@ -15,11 +17,14 @@ import org.springframework.web.reactive.function.client.* @Service class KeycloakProxy( - @Qualifier("keycloakWebClient") private val keycloakClient: WebClient, - private val keycloakConfig: KeycloakConfig + @Qualifier("keycloakWebClient") + private val keycloakClient: WebClient, + private val keycloakConfig: KeycloakConfig, + private val opexRealm: RealmResource ) { private val adminClient = keycloakConfig.adminClient + private val logger by LoggerDelegate() suspend fun getAdminAccessToken(): String { val tokenUrl = "${keycloakConfig.url}/realms/${keycloakConfig.realm}/protocol/openid-connect/token" @@ -196,6 +201,12 @@ class KeycloakProxy( .awaitSingle() } + suspend fun assignDefaultRoles(user: KeycloakUser) { + val role = opexRealm.roles().get("user-1").toRepresentation() + val u = opexRealm.users().get(user.id) + u.roles().realmLevel().add(mutableListOf(role)) + } + suspend fun createExternalIdpUser(email: String, username: Username, password: String): String { val userUrl = "${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users" val userRequest = mapOf( diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/service/UserService.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/service/UserService.kt index e78b061c6..7c55e5aca 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/service/UserService.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/service/UserService.kt @@ -74,6 +74,7 @@ class UserService( throw OpexError.BadRequest.exception() keycloakProxy.confirmCreateUser(user, request.password) + keycloakProxy.assignDefaultRoles(user) // Send event to let other services know a user just registered val event = UserCreatedEvent(user.id, user.username, user.email, user.mobile, user.firstName, user.lastName) diff --git a/auth-gateway/keycloak-setup/realms/opex-realm.json b/auth-gateway/keycloak-setup/realms/opex-realm.json index b91c909cf..c26448246 100644 --- a/auth-gateway/keycloak-setup/realms/opex-realm.json +++ b/auth-gateway/keycloak-setup/realms/opex-realm.json @@ -106,9 +106,6 @@ "description": "${role_default-roles}", "composite": true, "composites": { - "realm": [ - "user-1" - ], "client": { "account": [ "manage-account", @@ -389,7 +386,16 @@ } ], "ios-app": [], - "opex-api-key": [], + "opex-api-key": [ + { + "id": "95d01e3b-1442-415c-9f86-4d86187558ca", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "d2f0f1b6-46b7-4678-842a-8c67524ea2da", + "attributes": {} + } + ], "security-admin-console": [], "admin-cli": [], "account-console": [], @@ -405,7 +411,16 @@ "attributes": {} } ], - "opex-admin": [], + "opex-admin": [ + { + "id": "cd0dca5f-aa89-4a97-8cb7-6525f919c3b6", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "fb5f91c4-42fa-4769-b45d-febef22b4976", + "attributes": {} + } + ], "account": [ { "id": "8daa8096-d14e-4d1c-ad1f-83f822016aa1", @@ -601,8 +616,12 @@ ], "clientRoles": { "realm-management": [ + "realm-admin", "manage-users" ], + "opex-admin": [ + "uma_protection" + ], "account": [ "manage-account", "view-profile" @@ -611,6 +630,27 @@ "notBefore": 0, "groups": [] }, + { + "id": "4bb55f60-faa0-464a-b0a3-04a18f421dff", + "username": "service-account-opex-api-key", + "emailVerified": false, + "createdTimestamp": 1749460715817, + "enabled": true, + "totp": false, + "serviceAccountClientId": "opex-api-key", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-opex" + ], + "clientRoles": { + "opex-api-key": [ + "uma_protection" + ] + }, + "notBefore": 0, + "groups": [] + }, { "id": "854a5e2b-1e45-4ff7-bd1c-d9764d41a5bd", "username": "service-account-realm-management", @@ -891,7 +931,10 @@ "id": "13d76feb-d762-4409-bb84-7a75bc395a61", "clientId": "admin-cli", "name": "${client_admin-cli}", + "description": "", "rootUrl": "", + "adminUrl": "", + "baseUrl": "", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, @@ -911,24 +954,36 @@ "frontchannelLogout": false, "protocol": "openid-connect", "attributes": { - "saml.assertion.signature": "false", + "request.object.signature.alg": "any", "saml.multivalued.roles": "false", "saml.force.post.binding": "false", - "saml.encrypt": "false", "post.logout.redirect.uris": "+", - "saml.server.signature": "false", + "oauth2.device.authorization.grant.enabled": "false", "backchannel.logout.revoke.offline.tokens": "false", "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", + "use.refresh.tokens": "true", "realm_client": "false", - "client.use.lightweight.access.token.enabled": "true", + "oidc.ciba.grant.enabled": "false", "backchannel.logout.session.required": "false", "client_credentials.use_refresh_token": "false", - "saml_force_name_id_format": "false", "saml.client.signature": "false", + "require.pushed.authorization.requests": "false", + "request.object.encryption.enc": "any", + "saml.assertion.signature": "false", + "client.secret.creation.time": "1749563219", + "request.object.encryption.alg": "any", + "client.introspection.response.allow.jwt.claim.enabled": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "exclude.session.state.from.auth.response": "false", + "client.use.lightweight.access.token.enabled": "true", + "request.object.required": "not required", + "saml_force_name_id_format": "false", "tls.client.certificate.bound.access.tokens": "false", + "acr.loa.map": "{}", "saml.authnstatement": "false", "display.on.consent.screen": "false", + "token.response.type.bearer.lower-case": "false", "saml.onetimeuse.condition": "false" }, "authenticationFlowBindingOverrides": {}, @@ -1223,7 +1278,10 @@ "id": "fb5f91c4-42fa-4769-b45d-febef22b4976", "clientId": "opex-admin", "name": "${client_opex-admin}", + "description": "", "rootUrl": "${authBaseUrl}", + "adminUrl": "", + "baseUrl": "", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, @@ -1240,6 +1298,7 @@ "implicitFlowEnabled": false, "directAccessGrantsEnabled": true, "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", @@ -1251,11 +1310,13 @@ "saml.force.post.binding": "false", "saml.encrypt": "false", "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", "backchannel.logout.revoke.offline.tokens": "false", "saml.server.signature": "false", "saml.server.signature.keyinfo.ext": "false", "exclude.session.state.from.auth.response": "false", "realm_client": "false", + "oidc.ciba.grant.enabled": "false", "backchannel.logout.session.required": "false", "client_credentials.use_refresh_token": "false", "saml_force_name_id_format": "false", @@ -1324,6 +1385,7 @@ } ], "defaultClientScopes": [ + "service_account", "trust", "web-origins", "acr", @@ -1335,11 +1397,56 @@ "address", "offline_access", "microprofile-jwt" - ] + ], + "authorizationSettings": { + "allowRemoteResourceManagement": true, + "policyEnforcementMode": "ENFORCING", + "resources": [ + { + "name": "Default Resource", + "type": "urn:opex-admin:resources:default", + "ownerManagedAccess": false, + "attributes": {}, + "uris": [ + "/*" + ] + } + ], + "policies": [ + { + "name": "Default Policy", + "description": "A policy that grants access only for users within this realm", + "type": "js", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n" + } + }, + { + "name": "Default Permission", + "description": "A permission that applies to the default resource type", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "defaultResourceType": "urn:opex-admin:resources:default", + "applyPolicies": "[\"Default Policy\"]" + } + } + ], + "scopes": [], + "decisionStrategy": "UNANIMOUS" + } }, { "id": "d2f0f1b6-46b7-4678-842a-8c67524ea2da", "clientId": "opex-api-key", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, @@ -1355,23 +1462,26 @@ "standardFlowEnabled": true, "implicitFlowEnabled": false, "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, "publicClient": false, "frontchannelLogout": false, "protocol": "openid-connect", "attributes": { "saml.assertion.signature": "false", "access.token.lifespan": "43200", - "client.secret.creation.time": "1745062711", + "client.secret.creation.time": "1749460384", "saml.multivalued.roles": "false", "saml.force.post.binding": "false", "saml.encrypt": "false", "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", "backchannel.logout.revoke.offline.tokens": "false", "saml.server.signature": "false", "saml.server.signature.keyinfo.ext": "false", "exclude.session.state.from.auth.response": "false", "realm_client": "false", + "oidc.ciba.grant.enabled": "false", "backchannel.logout.session.required": "true", "client_credentials.use_refresh_token": "false", "saml_force_name_id_format": "false", @@ -1386,17 +1496,53 @@ "nodeReRegistrationTimeout": -1, "defaultClientScopes": [ "trust", - "web-origins", - "acr", - "profile", + "Forced_Roles", "basic", - "email" + "role_permission_attribute" ], "optionalClientScopes": [ - "address", - "offline_access", - "microprofile-jwt" - ] + "offline_access" + ], + "authorizationSettings": { + "allowRemoteResourceManagement": true, + "policyEnforcementMode": "ENFORCING", + "resources": [ + { + "name": "Default Resource", + "type": "urn:opex-api-key:resources:default", + "ownerManagedAccess": false, + "attributes": {}, + "uris": [ + "/*" + ] + } + ], + "policies": [ + { + "name": "Default Policy", + "description": "A policy that grants access only for users within this realm", + "type": "js", + "logic": "POSITIVE", + "decisionStrategy": "AFFIRMATIVE", + "config": { + "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n" + } + }, + { + "name": "Default Permission", + "description": "A permission that applies to the default resource type", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "defaultResourceType": "urn:opex-api-key:resources:default", + "applyPolicies": "[\"Default Policy\"]" + } + } + ], + "scopes": [], + "decisionStrategy": "UNANIMOUS" + } }, { "id": "6a4bfbd0-576d-4778-af56-56f876647355", @@ -2177,7 +2323,7 @@ "frontchannelLogout": true, "protocol": "openid-connect", "attributes": { - "access.token.lifespan": "600", + "access.token.lifespan": "3600", "request.object.signature.alg": "any", "frontchannel.logout.session.required": "true", "oauth2.device.authorization.grant.enabled": "false", @@ -2195,6 +2341,7 @@ "client.secret.creation.time": "1747492073", "request.object.encryption.alg": "any", "client.introspection.response.allow.jwt.claim.enabled": "false", + "standard.token.exchange.enabled": "false", "exclude.session.state.from.auth.response": "false", "client.use.lightweight.access.token.enabled": "false", "request.object.required": "not required", @@ -2208,6 +2355,7 @@ "nodeReRegistrationTimeout": -1, "defaultClientScopes": [ "trust", + "audience-opex-api-key", "basic", "role_permission_attribute" ], @@ -2520,6 +2668,63 @@ } ] }, + { + "id": "d1debc5e-632b-4c2e-863b-2f5b2b1572d5", + "name": "user-roles", + "description": "", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "gui.order": "", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "d8aa4645-5f5b-41e7-b7e6-b12739ca0cca", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "dbb7860d-fba0-4c05-8b99-f2f9cdd3ffb4", + "name": "audience-opex-api-key", + "description": "", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "gui.order": "", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "627885b9-1bb8-465a-9125-e9603ac1dcd5", + "name": "audience-opex-api-key", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "included.client.audience": "opex-api-key", + "id.token.claim": "false", + "lightweight.claim": "false", + "access.token.claim": "true", + "introspection.token.claim": "true" + } + } + ] + }, { "id": "51d49314-b511-43e0-9258-bfb873758a78", "name": "web-origins", @@ -2577,6 +2782,17 @@ "claim.name": "auth_time", "jsonType.label": "long" } + }, + { + "id": "f4b67796-04fa-49b5-846f-a5ab81587c55", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } } ] }, @@ -2913,6 +3129,32 @@ } } ] + }, + { + "id": "60575b8d-b5ab-47c3-a2fa-b14e77d4f392", + "name": "Forced_Roles", + "description": "", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "gui.order": "", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "a2ffe329-0ed7-4861-a6aa-e72a25b98770", + "name": "roles", + "protocol": "openid-connect", + "protocolMapper": "forced-role-mapper", + "consentRequired": false, + "config": { + "claim.name": "roles", + "jsonType.label": "String", + "key.name": "roles" + } + } + ] } ], "defaultDefaultClientScopes": [ @@ -2924,7 +3166,10 @@ "web-origins", "role_permission_attribute", "role_list", - "realm-roles" + "realm-roles", + "audience-opex-api-key", + "user-roles", + "Forced_Roles" ], "defaultOptionalClientScopes": [ "offline_access", diff --git a/auth-gateway/keycloak-setup/spi/src/main/java/co/nilin/opex/keycloak/spi/ForcedRoleProtocolMapper.java b/auth-gateway/keycloak-setup/spi/src/main/java/co/nilin/opex/keycloak/spi/ForcedRoleProtocolMapper.java new file mode 100644 index 000000000..f858bd900 --- /dev/null +++ b/auth-gateway/keycloak-setup/spi/src/main/java/co/nilin/opex/keycloak/spi/ForcedRoleProtocolMapper.java @@ -0,0 +1,73 @@ +package co.nilin.opex.keycloak.spi; + +import org.keycloak.models.*; +import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper; +import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper; +import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.representations.AccessToken; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class ForcedRoleProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper { + + private static final String PROVIDER_ID = "forced-role-mapper"; + private static final String ROLE_ATTRIBUTES_CLAIM = "forced_role"; + + public static final String KEY_NAME = "key.name"; + + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public String getDisplayCategory() { + return "Forced Role"; + } + + @Override + public String getDisplayType() { + return "Forced Role Mapper"; + } + + @Override + public String getHelpText() { + return "Forces the addition of roles to the token."; + } + + @Override + public List getConfigProperties() { + List configProperties = new ArrayList<>(); + OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties); + OIDCAttributeMapperHelper.addJsonTypeConfig(configProperties); + + ProviderConfigProperty attributeName = new ProviderConfigProperty(); + attributeName.setName(KEY_NAME); + attributeName.setLabel("Key Name"); + attributeName.setType(ProviderConfigProperty.STRING_TYPE); + attributeName.setHelpText("The name of the role to include in the token."); + configProperties.add(attributeName); + return configProperties; + } + + @Override + public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel user, ClientSessionContext clientSessionCtx) { + String claimName = mappingModel.getConfig().get(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME); + var finalList = new HashSet<>(); + + user.getUser().getRealmRoleMappingsStream().forEach(role -> { + finalList.add(role.getName()); + role.getCompositesStream().forEach(r -> finalList.add(r.getName())); + }); + + if (!finalList.isEmpty()) { + token.getOtherClaims().put(claimName != null && !claimName.isEmpty() ? claimName : ROLE_ATTRIBUTES_CLAIM, finalList); + } + + return token; + } + +} diff --git a/auth-gateway/keycloak-setup/spi/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper b/auth-gateway/keycloak-setup/spi/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper index b6cb236ff..842ee10be 100644 --- a/auth-gateway/keycloak-setup/spi/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper +++ b/auth-gateway/keycloak-setup/spi/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper @@ -1 +1,2 @@ -co.nilin.opex.keycloak.spi.RoleAttributesProtocolMapper \ No newline at end of file +co.nilin.opex.keycloak.spi.RoleAttributesProtocolMapper +co.nilin.opex.keycloak.spi.ForcedRoleProtocolMapper \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/security/CustomJwtAuthConverter.kt b/common/src/main/kotlin/co/nilin/opex/common/security/CustomJwtAuthConverter.kt index 47cf021cd..a08de7b5e 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/security/CustomJwtAuthConverter.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/security/CustomJwtAuthConverter.kt @@ -11,26 +11,15 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtGra import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtGrantedAuthoritiesConverterAdapter import reactor.core.publisher.Mono -class CustomJwtAuthConverter : JwtAuthenticationConverter() { - - override fun extractAuthorities(jwt: Jwt): MutableCollection { - val authorities = JwtGrantedAuthoritiesConverter().convert(jwt) - val permissions = jwt.getClaimAsStringList("permissions") - if (permissions != null && permissions.isNotEmpty()) - authorities?.addAll(permissions.map { SimpleGrantedAuthority("PERM_${it}") }) - return authorities ?: super.extractAuthorities(jwt) - } -} - class ReactiveCustomJwtConverter : Converter> { override fun convert(source: Jwt): Mono { val permissions = source.getClaimAsStringList("permissions") - .map { SimpleGrantedAuthority("PERM_${it}") } - .toList() + ?.map { SimpleGrantedAuthority("PERM_${it}") } + ?.toList() ?: emptyList() val roles = source.getClaimAsStringList("roles") - .map { SimpleGrantedAuthority("ROLE_${it}") } - .toList() + ?.map { SimpleGrantedAuthority("ROLE_${it}") } + ?.toList() ?: emptyList() return Mono.just(JwtAuthenticationToken(source, roles + permissions)) } } \ No newline at end of file