DependencyTrack / dependency-track

Dependency-Track is an intelligent Component Analysis platform that allows organizations to identify and reduce risk in the software supply chain.
https://dependencytrack.org/
Apache License 2.0
2.69k stars 578 forks source link

Group Sync with Azure AD via graph.windows.net does not seem to work anymore. #2150

Open Breee opened 1 year ago

Breee commented 1 year ago

Current Behavior

Basic Information

Configs

    - name: ALPINE_OIDC_ENABLED
       value: "true"
    - name: ALPINE_OIDC_CLIENT_ID
       value: <CLIENT_ID>
    - name: ALPINE_OIDC_ISSUER
      value: https://login.microsoftonline.com/<TENNANT_ID>/v2.0
    - name: ALPINE_OIDC_USERNAME_CLAIM
      value: preferred_username
    - name: ALPINE_OIDC_USER_PROVISIONING
      value: "true"
    - name: ALPINE_OIDC_TEAMS_CLAIM
       value: groups
    - name: ALPINE_OIDC_TEAM_SYNCHRONIZATION
      value: "true"

Claims + Logs

Logs:

2022-11-14 10:35:30,845 DEBUG [OidcConfigurationResolver] OIDC configuration loaded from cache
2022-11-14 10:35:30,845 DEBUG [OidcIdTokenAuthenticator] JWK set loaded from cache
2022-11-14 10:35:30,846 DEBUG [OidcIdTokenAuthenticator] ID token claims: {"sub":"<SUBJECT>","ver":"2.0","_claim_names":{"groups":"src1"},"aio":"<AIO>","roles":["admin"],"iss":"https:\/\/login.microsoftonline.com\/<TENANT_ID>\/v2.0","oid":"<USER_ID>","preferred_username":"Bree@example.com","uti":"<UTI>","tid":"<TENANT_ID>","aud":"<CLIENT_ID>","nbf":1668421830,"rh":"<RH>","wids":["<WID1>"],"_claim_sources":{"src1":{"endpoint":"https:\/\/graph.windows.net\/<TENANT_ID>\/users\/<USER_ID>\/getMemberObjects"}},"name":"Breesson, Bree","exp":1668425730,"iat":1668421830,"email":"Bree@example.com"}
2022-11-14 10:35:30,847 DEBUG [OidcAuthenticationService] ID token profile: OidcProfile{subject='<SUBJECT>', username='Bree@example.com', groups=null, email='Bree@example.com'}
2022-11-14 10:35:31,089 DEBUG [OidcUserInfoAuthenticator] UserInfo response: {"sub":"<SUBJECT>","name":"Breesson, Bree","given_name":"Julian","family_name":"Loeffler","picture":"https:\/\/graph.microsoft.com\/v1.0\/me\/photo\/$value","email":"Bree@example.com"}
2022-11-14 10:35:31,089 DEBUG [OidcAuthenticationService] UserInfo profile: OidcProfile{subject='<SUBJECT>', username='null', groups=null, email='Bree@example.com'}
2022-11-14 10:35:31,089 DEBUG [OidcAuthenticationService] Merged profile: OidcProfile{subject='<SUBJECT>', username='Bree@example.com', groups=null, email='Bree@example.com'}
2022-11-14 10:35:31,090 ERROR [OidcAuthenticationService] Unable to assemble complete profile (ID token: OidcProfile{subject='<SUBJECT>', username='Bree@example.com', groups=null, email='Bree@example.com'}, UserInfo: OidcProfile{subject='<SUBJECT>', username='null', groups=null, email='Bree@example.com'}, Merged: OidcProfile{subject='<SUBJECT>', username='Bree@example.com', groups=null, email='Bree@example.com'})
2022-11-14 10:35:31,090 INFO [UserResource] Unauthorized OpenID Connect login attempt / IP Address: xxxxxxxxxxxxxxx / User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36

Dependency track received ID token contains something similar to:

{
    "sub": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "ver": "2.0",
    "_claim_names": {
        "groups": "src1"
    },
    "aio": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "roles": [
        "admin"
    ],
    "iss": "https:\/\/login.microsoftonline.com\/xxxxxxxxxxxxxxxxxxxxxxxxx\/v2.0",
    "oid": "xxxxxxxxxxxxxxxxxxxxxxxx",
    "preferred_username": "Bree@example.com",
    "uti": "xxxxxxxxxxxxxxxxxxxxxxxxx",
    "tid": "xxxxxxxxxxxxxxxxxxxxxxxxx",
    "aud": "xxxxxxxxxxxxxxxxxxxxxxxxx",
    "nbf": 1668420930,
    "rh": "xxxxxxxxxxxxxxxxxxxxxxxxx",
    "wids": [
        "xxxxxxxxxxxxxxxxxxxxxxxxxx"
    ],
    "_claim_sources": {
        "src1": {
            "endpoint": "https:\/\/graph.windows.net\/xxxxxxxxxx\/users\/xxxxxxxxxxxx\/getMemberObjects"
        }
    },
    "name": "Breesson, Bree",
    "exp": 1668424830,
    "iat": 1668420930,
    "email": "Bree@example.com"
}

The interesting part here is

    "_claim_sources": {
        "src1": {
            "endpoint": "https:\/\/graph.windows.net\/xxxxxxxxxx\/users\/xxxxxxxxxxxx\/getMemberObjects"
        }
    },

I was not able to query this API endpoint myself successfully, so maybe something changed in the old graph.windows.net endpoint. Maybe you guys want to consider to migrate to graph.microsoft.com

Steps to Reproduce

  1. Create an Azure AD app registration
  2. Configure a groups claim for ID/Access tokens
  3. Configure DTrack to use the Azure AD app as OIDC client and activate group sync
  4. Login

Expected Behavior

groups are synced successfully

Dependency-Track Version

4.6.2

Dependency-Track Distribution

Container Image

Database Server

PostgreSQL

Database Server Version

13.8

Browser

N/A

Checklist

muellerst-hg commented 1 year ago

Regression in 4.6? The same setup works with 4.5.0

2022-11-14 11:05:52,231 DEBUG [OidcConfigurationResolver] OIDC configuration loaded from cache
2022-11-14 11:05:52,311 DEBUG [OidcConfigurationResolver] OIDC configuration loaded from cache
2022-11-14 11:05:52,377 DEBUG [OidcIdTokenAuthenticator] Fetching JWK set from https://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys
2022-11-14 11:05:52,763 DEBUG [OidcIdTokenAuthenticator] Storing JWK set in cache
2022-11-14 11:05:52,804 DEBUG [OidcIdTokenAuthenticator] ID token claims: {"sub":"<SUBJECT>","ver":"2.0","aio":"<AIO>","iss":"https:\/\/login.microsoftonline.com\/<TENANT_ID>\/v2.0","groups":["MY_TEST_GROUP"],"oid":"<USER_ID>","preferred_username":"john@example.com","uti":"<UTI>","tid":"<TENANT_ID>","aud":"<CLIENT_ID>","nbf":1668423651,"rh":"<RH>","wids":["<WID1>"],"name":"John Doe","exp":1668427551,"iat":1668423651,"email":"john.doe@example.com"}
2022-11-14 11:05:52,812 DEBUG [OidcAuthenticationService] ID token profile: OidcProfile{subject='<SUBJECT>', username='john@example.com', groups=MY_TEST_GROUP], email='john.doe@example.com'}
2022-11-14 11:05:52,812 DEBUG [OidcAuthenticationService] ID token profile is complete, proceeding to authenticate
2022-11-14 11:05:52,830 DEBUG [OidcAuthenticationService] Attempting to authenticate user: john@example.com
nscuro commented 1 year ago

To me this part seems off:

"_claim_names": {
  "groups": "src1"
},

The groups claim should be on the root level of the JSON object, instead it is wrapped in a _claim_names object. In @muellerst-hg's case it is not this way.

We did not (knowingly) change anything related to OIDC in 4.6. But of course it's always possible that the library we leverage for OIDC is causing a different ID Token layout to be returned for Azure AD.

Breee commented 1 year ago

To me this part seems off:

"_claim_names": {
  "groups": "src1"
},

The groups claim should be on the root level of the JSON object, instead it is wrapped in a _claim_names object. In @muellerst-hg's case it is not this way.

We did not (knowingly) change anything related to OIDC in 4.6. But of course it's always possible that the library we leverage for OIDC is causing a different ID Token layout to be returned for Azure AD.

Yep, in both cases we used the same Azure AD app registration

Breee commented 1 year ago

In 4.6: oauth2-oidc-sdk version 9.43 In 4.5: oauth2-oidc-sdk version: 9.35

I did not dig into the code / releases tho. I mean we could build DT maybe with the alpine version that contains 9.35 and see if this fixes it. I can probably test that locally. Just have to figure out where your tool uses the oauth2 sdk. (You guys are probably much faster)

nscuro commented 1 year ago

Changelogs are here, but nothing obvious between those versions that could cause this behavior.

Found this regarding the _claim_names claim:

The claim you're getting back as part of json shared in question is an overage indicator claim.

It means that the user is member of many groups and instead of including information about all the groups as part of token (which would make the token too big), you will need to query that information separately.

Breee commented 1 year ago

Changelogs are here, but nothing obvious between those versions that could cause this behavior.

Found this regarding the _claim_names claim:

The claim you're getting back as part of json shared in question is an overage indicator claim. It means that the user is member of many groups and instead of including information about all the groups as part of token (which would make the token too big), you will need to query that information separately.

Yes, this is known behaviour of Azure AD. Seems this happens for people that are in over a certain amount of groups in Azure AD.

nscuro commented 1 year ago

In the current OIDC logic we don't handle any non-standard cases. In order to resolve this issue with Azure AD, we'd need to have extra logic in the profile creation to fetch groups from the AAD API if we encounter _claim_names claims.

Breee commented 1 year ago

Would highly appreciate that, currently this is a massive blocker for us to push mass adoption of the tool within the company

colbyprior commented 1 year ago

@Breee I am trying to get this working for a new install. I did notice that there is an option in Azure AD to limit the groups passed through in the claim. Does this work for you?

image
Breee commented 1 year ago

Technically: I guess In a large company for mass adoption: with organizational overhead or some Self Service Tool/automation that can assign groups to the application.

I have to test it out next week, i got a week off atm

setchy commented 1 year ago

@Breee I am trying to get this working for a new install. I did notice that there is an option in Azure AD to limit the groups passed through in the claim. Does this work for you?

image

We had the same issue for a subset of our users. I can confirm that selectingGroups assigned to the application rather than Security groups did the trick for us.

yaadkarim commented 1 year ago

@Breee any workarounds or solutions to this issue?

Breee commented 1 year ago

Solutions, not really yet.

But you can explictly assign groups to your azure ad App registration and only pass those to dependencytrack I guess

On Fri, Aug 18, 2023, 14:08 yaadkarim @.***> wrote:

@Breee https://github.com/Breee any workarounds or solutions to this issue?

— Reply to this email directly, view it on GitHub https://github.com/DependencyTrack/dependency-track/issues/2150#issuecomment-1683824928, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC3JPMKO6OQN2IO6QRMA4RLXV5LNBANCNFSM6AAAAAAR7V5OIY . You are receiving this because you were mentioned.Message ID: @.***>

Jasper-Ben commented 7 months ago

Solutions, not really yet. But you can explictly assign groups to your azure ad App registration and only pass those to dependencytrack I guess

Just FYI, this workaround has a drawback though, as per Entra ID docs it does not support nested groups, which kind of sucks in more complex permission schemas:

To emit only groups assigned to the application, select Groups assigned to the application.

Screenshot that shows the Group Claims window, with the option for groups assigned to the application selected.

Groups assigned to the application will be included in the token. Other groups that the user is a member of will be omitted. With this option, nested groups are not included and the user must be a direct member of the group assigned to the application.

https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-fed-group-claims

akos-balla commented 3 months ago

@Breee I am trying to get this working for a new install. I did notice that there is an option in Azure AD to limit the groups passed through in the claim. Does this work for you?

image

We had the same issue for a subset of our users. I can confirm that selecting Groups assigned to the application rather than Security groups did the trick for us.

For us (also a large organization) it was exactly the opposite way around. All options together and Groups assigned to the application didn't work, but works with Security groups. On the other hand, one of our users has 84 security groups and can't log in (one other with 42 can, so I suspect we're hitting the too-many-groups issue)