OIDC with Azure | akhq doesn't map roles coming from azure ad to groups | no debug logs
We are a bit on pressure to deliver this and i would really appreciate some help.
When mapping individual users all is good. However when using the groups as in the commented sections the mapping doesn't really work and i kept being redirected to the login page. What makes it harder to debug is that there is no logging i tried to set the level to debug but it still only showing warn and info, so i'm not sure which part is causing the problem and how to debug it.
oidc:
enabled: true
providers:
azure:
label: "Click here to Login with Azure"
username-field: email
groups-field: roles
users:
- username: [email protected]
groups:
- admin
# default-group: topic-admin
# groups:
# - name: reader
# groups:
# - admin
Do you have a sample of the claim provided by Azure ? The only reason that it works for user mapping and not for group mapping should be the groups-fields that is not referencing the right field from the claim
hey @AlexisSouquiere , Thanks a bunch for getting back to me, i try to give a detailed explanation. Long story short: based on my mimictions it looks like the first senario doesn't include any roles/groups in the claim, but the second scenario does include roles/claims
Senario 1 (akhq undestand this flow, but no roles/groups included in the claim)
When i mimic the config below, which leads to construct the following url, the grenerated jwt token doesn't include roles or groups, it only include email with other info, i attached the genrated jwt sample below.
Example auth url
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize?client_id=<client_id>&response_type=code&redirect_uri=http://localhost:9091/oauth/callback/azure&scope=openid profile email
example config
oauth2:
enabled: true
debug: true
clients:
azure:
client-id: "<client-id>"
client-secret: "<client_secret>"
scopes:
- openid
- email
- profile
openid:
issuer: "https://login.microsoftonline.com/<tenant-id>/v2.0"
generated jwt structure from the config
{
"typ": "JWT",
"nonce": "<nonce>",
"alg": "RS256",
"x5t": "<x5t>",
"kid": "<kid>"
}.{
"aud": "<audience>",
"iss": "https://sts.windows.net/<tenant-id>/",
"iat": <issued-at>,
"nbf": <not-before>,
"exp": <expiration>,
"acct": <account>,
"acr": "<acr>",
"acrs": [
"<acr-values>"
],
"aio": "<aio>",
"altsecid": "<altsecid>",
"amr": [
"<authentication-methods>"
],
"app_displayname": "<app-display-name>",
"appid": "<app-id>",
"appidacr": "<app-id-acr>",
"email": "<email>",
"idp": "https://sts.windows.net/<idp-tenant-id>/",
"idtyp": "<id-type>",
"ipaddr": "<ip-address>",
"name": "<name>",
"oid": "<object-id>",
"platf": "<platform>",
"puid": "<puid>",
"rh": "<rh>",
"scp": "<scopes>",
"sid": "<session-id>",
"sub": "<subject>",
"tenant_region_scope": "<tenant-region-scope>",
"tid": "<tenant-id>",
"unique_name": "<unique-name>",
"uti": "<uti>",
"ver": "<version>",
"wids": [
"<wids>"
],
"xms_ftd": "<xms-ftd>",
"xms_idrel": "<xms-idrel>",
"xms_st": {
"sub": "<xms-st-sub>"
},
"xms_tcdt": <xms-tcdt>,
"xms_tdbr": "<xms-tdbr>"
}.[Signature]
Senario 2 (akhq doesn't understand this flow, roles/groups are included in the claim)
When i mimic the second senario and expose my entra app under this URI api://client-id/.default and then request authorization with uri scope, i do receive roles and groups in the claim
Example auth url
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize?client_id=<client_id>&response_type=code&redirect_uri=http://localhost:9091/oauth/callback/azure&scope=client-id/.default
Example config used
oauth2:
enabled: true
debug: true
clients:
azure:
client-id: "<client-id>"
client-secret: "<client-secret>"
scopes:
- client-id/.default
openid:
issuer: "https://login.microsoftonline.com/2efewfwef/v2.0"
Example Generated jwt structre, (akhq did not worked with the above config)
{
"typ": "JWT",
"alg": "RS256",
"kid": "<key-id>"
}.{
"aud": "<audience>",
"iss": "https://login.microsoftonline.com/<tenant-id>/v2.0",
"iat": <issued-at>,
"nbf": <not-before>,
"exp": <expiration>,
"aio": "<aio>",
"azp": "<authorized-party>",
"azpacr": "<authorized-party-acr>",
"groups": [
"<group-id-1>",
"<group-id-2>"
],
"idp": "https://sts.windows.net/<idp-tenant-id>/",
"name": "<name>",
"oid": "<object-id>",
"preferred_username": "<preferred-username>",
"rh": "<rh>",
"roles": [
"<role-1>"
],
"scp": "<scopes>",
"sid": "<session-id>",
"sub": "<subject>",
"tid": "<tenant-id>",
"uti": "<uti>",
"ver": "<version>",
"wids": [
"<wids-1>",
"<wids-2>",
"<wids-3>"
]
}.[Signature]
However with this example config, akhq doesn't understand this flow and i receive the following error:
message 'Internal Server Error: Cannot invoke "String.contains(java.lang.CharSequence)" because "token" is null'
_links
self
href "/oauth/callback/azure?code=gowrhgowrhgowhwvgworhgiwuhgfuwrgh379t6735yg3ty78n0%3d&session_state=c34ct34t35ty3"
templated false
_embedded
stacktrace
0
message 'java.lang.NullPointerException: Cannot invoke "String.contains(java.lang.CharSequence)" because "token" is null\n\tat io.micronaut.security.token.jwt.validator.JwtValidator.hasAtLeastTwoDots(JwtValidator.java:101)\n\tat io.micronaut.security.token.jwt.validator.JwtValidator.validate(JwtValidator.java:79)\n\tat io.micronaut.security.oauth2.endpoint.token.response.validation.DefaultOpenIdTokenResponseValidator.parseJwtWithValidSignature(DefaultOpenIdTokenResponseValidator.java:162)\n\tat io.micronaut.security.oauth2.endpoint.token.response.validation.DefaultOpenIdTokenResponseValidator.validate(DefaultOpenIdTokenResponseValidator.java:90)\n\tat io.micronaut.security.oauth2.endpoint.authorization.response.DefaultOpenIdAuthorizationResponseHandler.validateOpenIdTokenResponse(DefaultOpenIdAuthorizationResponseHandler.java:238)\n\tat io.micronaut.security.oauth2.endpoint.authorization.response.DefaultOpenIdAuthorizationResponseHandler.createAuthenticationResponse(DefaultOpenIdAuthorizationResponseHandler.java:198)\n\tat io.micronaut.security.oauth2.endpoint.authorization.response.DefaultOpenIdAuthorizationResponseHandler.lambda$handle$0(DefaultOpenIdAuthorizationResponseHandler.java:133)\n\tat reactor.core.publisher.FluxSwitchMapNoPrefetch$SwitchMapMain.subscribeInner(FluxSwitchMapNoPrefetch.java:210)\n\tat reactor.core.publisher.FluxSwitchMapNoPrefetch$SwitchMapMain.onNext(FluxSwitchMapNoPrefetch.java:164)\n\tat reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.runAsync(FluxPublishOn.java:446)\n\tat reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.run(FluxPublishOn.java:533)\n\tat io.micronaut.core.propagation.PropagatedContext.lambda$wrap$3(PropagatedContext.java:211)\n\tat reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)\n\tat reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)\n\tat io.micronaut.core.propagation.PropagatedContext.lambda$wrap$4(PropagatedContext.java:228)\n\tat io.micrometer.core.instrument.composite.CompositeTimer.recordCallable(CompositeTimer.java:129)\n\tat io.micrometer.core.instrument.Timer.lambda$wrap$1(Timer.java:203)\n\tat io.micronaut.core.propagation.PropagatedContext.lambda$wrap$4(PropagatedContext.java:228)\n\tat io.micrometer.core.instrument.composite.CompositeTimer.recordCallable(CompositeTimer.java:129)\n\tat io.micrometer.core.instrument.Timer.lambda$wrap$1(Timer.java:203)\n\tat java.base/java.util.concurrent.FutureTask.run(Unknown Source)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)\n\tat java.base/java.lang.Thread.run(Unknown Source)\n
hey @AlexisSouquiere, any update concerning this one? Thank you!
I just tried and I'm able to make it works on my side. Your scenario 1 looks good except that you need to add the groups claim in the tokens.
My config looks like this (the micronaut.security.oauth2.client is the same as yours):
akhq:
security:
oidc:
providers:
azure:
label: "Login with Azure"
username-field: preferred_username
groups-field: groups
groups:
- name: <my_group_guid>
groups:
- admin
In Azure, I added the groups claim (doc here):
When login I can see in the id_token that it contains a list of all my groups (guid in the test I did) and it maps it with the one I put in my AKHQ configuration
why the use-oidc-claim: true is not used for your configuration
I just tried and I'm able to make it works on my side. Your scenario 1 looks good except that you need to add the groups claim in the tokens.
My config looks like this (the micronaut.security.oauth2.client is the same as yours):
akhq: security: oidc: providers: azure: label: "Login with Azure" username-field: preferred_username groups-field: groups groups: - name: <my_group_guid> groups: - admin
In Azure, I added the groups claim (doc here):
When login I can see in the id_token that it contains a list of all my groups (guid in the test I did) and it maps it with the one I put in my AKHQ configuration
hey @AlexisSouquiere, thanks for your support, i was missing the GUID of the group, it works perfectly thanks for your support.
