I am trying to debug an issue with `groups` claim ...
# troubleshoot
m
I am trying to debug an issue with
groups
claim in Azure OIDC and I can't figure out where my error is coming from. My Azure OIDC integration works until I enable
groups
to be present in an ID token. When
groups
claim is present, I get a
502 Bad Gateway
and I can't login to DataHub. I have looked at both frontend and gms logs (info & debug) and I can't see what would be causing a
502
. If you look at the attached screenshot, the
GET https://<dh_server>/authenticate?redirect_uri=%2F
returns a
303
to
<https://login.microsoftonline.com/{tenant> id}/oauth2/v2.0/authorize?response_type=code&redirect_uri=https://<dh_server>%2Fcallback%2Foidc
, which returns a
302
to the expected callback URL
https://<dh_server>/callback/oidc?code=0...
, which causes a
502
... (
dh_server
is the DataHub server). The authentication is a success since I can find the user with its profile. I added extra debug statements in
auth.sso.oidc.OidcCallbackLogic
and all looks good. I thought that class would be the one handling the OIDC callback, but looks like I'm wrong. In order to debug further, can someone tell me which class is handling the
https://<dh_server>/callback/oidc?code=0...
request? @big-carpet-38439 probably knows this, but I think he is on vacation 🥳. Anyone else?
Here is the screenshot
When
groups
claim is not in ID token, DataHub loads just fine with a
303
to the home page instead of a
502
b
Are you changing DataHub’s configuration at all to include ‘groups’ in the requested scope?
Also, we recently added more debug logging in this flow.. are you able to extract the debug logs from that container?
m
So I really went down the rabbit hole on this one. Debug logs didn't reveal anything, so I created a custom frontend image and I tried things... long story short, the request was being handled well by the DataHub OidcCallbackLogic class, but it created a HTTP header (I suppose a Set-Cookie) that was too large and rejected by the nginx proxy (I have DataHub deployed on a k8s cluster, behind an ingress). I saw an error about it in the nginx logs. I increased the buffers and now the user can login, but I am stuck into an infinite 401 loop with graphql... We talked about this a few weeks ago while I worked on the OIDC Azure documentation page and we never found a solution. I decided then to put that issue on ice, but seems like I need to solve that puzzle now. Once I do, I'll open a PR to update the Azure docs since I found 2 or 3 misleading things. I'll try to get to the bottom of this, but I might request some help from you @big-carpet-38439 if you don't mind. But I'll give it a shot alone first.
I now understand what is going on and why I get a 401 error, but I'm not sure how to fix it. In a nutshell, the
PLAY_SESSION
cookie returned by the DataHub OIDC callback is larger than 4096 bytes and it is rejected by the browser. This only happens when I have the
groups
claim turned on in my OIDC token configuration, My user is a member of a few groups in Azure AD and I suppose those groups are encoded in the cookie, which makes the cookie too large. If I don't return the
groups
in my OIDC token, all is good and the cookie is smaller than 4k. I have attached a few screenshots that show the play-by-play when
groups
claim is enabled. Play-by-play by screenshot number: 1. The
authenticate?redirect_uri
endpoint returns a
PLAY_SESSION
cookie (
fce12e...
) which has no permission since we have not authenticated yet. 2. The
callback/oidc?
endpoint receives the
PLAY_SESSION
cookie
fce12e...
and since it was able to authenticate with Azure AD, it returns a new
PLAY_SESSION
cookie (
52dcc...
), but it is rejected (malformed) since its size is 6884 bytes, which is greater than 4k. 3. The
graphql
endpoint is called with the only valid
PLAY_SESSION
cookie
fce12e...
it can find, and it returns 401 since that cookie is not authenticated... And here goes the infinite loop... I have no clue what is in the
PLAY_SESSION
cookie. That's what I will try to figure out, but if someone knows how to fix this, please let me know! The solution I see when Googling is to make the cookie smaller. I'm curious to see if others have ran into the same problem.
l
This is fantastic sleuthing! Thanks @modern-monitor-81461
m
Sharing some more from my investigation. Taking a closer look at the
PLAY_SESSION
cookie, I can see that
pac4j_pac4jUserProfiles
is responsible for much of the bytes used (5549 bytes to be precise). The profile is built by this class (OidcProfileCreator), as configured here. The OidcProfileCreator saves the ID and access tokens, so it explains why the cookie only gets too large when the
groups
claims is enabled. I guess that for most of the users, the tokens will be small enough to fit within the 4k limit, but for others like my user account, it won't. Any advice on how to resolve this?
o
Hey Eric! Have you tried messing with the Play settings? There are a couple of properties that configure whether the
groups
claim gets extracted for the token or not: https://github.com/linkedin/datahub/blob/master/datahub-frontend/conf/application.conf#L122-L123 We base our authorization on in-app groups, so I don't think we should need the full set of groups returned in the token. Setting the groups extraction to false I don't think would cause issues.
m
Hi @orange-night-91387, yes I'm aware of those settings and have played with them. It doesn't matter if
AUTH_OIDC_EXTRACT_GROUPS_ENABLED
is
true
or
false
since the problem is with the size of the ID token. I'll try to explain it better. In Azure, I create an App Registration and in that registration, I can configure the claims returned in the tokens. If
groups
is configured to be returned, and a user (like me) is a member of many groups, that ID token can grow to a size where it gets too big. They way Pac4J deals with User profiles, it saves the ID and access tokens in the profile and that profile is saved as a
Set-Cookie
HTTP header. Browsers rejects any cookie larger than 4k, so if the ID token gets too large and goes over the 4k limit, I end up in the situation I described earlier. One solution I think would be to use the browser local storage instead of cookies, but it is not as convenient as cookies since you need to check every time the local storage as opposed to relying on the cookie (
PLAY_SESSION
) being automatically sent on every request. I'm not an expert when it comes down to this, but that's my understanding of how it works. Probably the way it is setup right works works for 95% (maybe more?) of the users, but I'm an admin and I'm a member of many groups... My plan was to use the JIT provisioning of the groups and define policies using those groups. This was my way to populate groups in DataHub instead of ingesting users and groups from Azure AD. While reading DataHub's Slack, I stumbled on a post where @chilly-analyst-561 described how he made it work using Keycloak. That was an eye opener and I replicated what he did, but using Azure AD. I basically defined an Enterprise Application in Azure where I created
Roles
and mapped groups to those. I removed the
groups
claim from the token configuration to avoid having too large ID tokens. So now in my ID token, I have something like
Copy code
{
  "aud": "90f653ef-7028-4a48-b4d5-ed0ed6ff68ab",
  "iss": "<https://login.microsoftonline.com/da9cbxxxxxxxx-xxx-xxxxxxx/v2.0>",
  "iat": 1645121813,
  "nbf": 1645121813,
  "exp": 1645125713,
  "email": "Eric.L@xxxxxxx",
  "name": "L, Eric",
  "oid": "40744a8d-1ec4-4df3-9254-d0553f825a70",
  "preferred_username": "Eric.L@xxxxxxxx",
  "rh": "0.ASwAQL6c2h7sl0mvsxfYdXRXGu9T9pAocEhKtNXtDtb_aKssAO4.",
  "roles": [
    "User",
    "Admin"
  ],
  "sub": "Y7PaMTczbNx74t04-IoCtlnZawX7uHcRnFzFggOGLq0",
  "tid": "da9cbe40-ec1e-4997-afb3-17d87574571a",
  "uti": "aF2LDaWZ50WFD2ekBc84AA",
  "ver": "2.0"
}
So I have defined a group in Azure AD mapped to the
User
role and another group that is mapped to the
Admin
role. To leverage those roles in DataHub, I cheated and set
AUTH_OIDC_GROUPS_CLAIM
to
roles
. I ended with 2 groups in DataHub (User and Admin) with my user as a member of both and I can then apply policies on those groups. I think in an Enterprise environment, that is the way to do things (leverage roles mapped in your Active Directory, or the equivalent in Google or AWS). I don't know if role mapping should be added to DataHub, but that's how I hacked it. I don't mind updating the Azure OIDC user docs in DataHub, but I'm not sure if my solution is the right one. Any thoughts? (and sorry for the loooooong posts! I'm simply trying to be thorough 😃)
The more I think about it, maybe it's me that got it wrong from the start? I was so focused on having an Azure group be mapped as a group in DataHub, but maybe the role thing is not a hack after all, but it's just the way to do this in Azure... or any cloud provider. Let me know what you think and then I can update the docs accordingly.
o
I think this makes sense. We really appreciate the thoroughness! Definitely want this captured so others don't have to struggle in the same ways so updating the docs makes sense to me. I think it's probably still worthwhile to still look into how to exclude groups from the auth token at some point as they're not really necessary, but this sounds like a pretty solid way of handling it from the OIDC side.