snok / django-auth-adfs

A Django authentication backend for Microsoft ADFS and AzureAD
http://django-auth-adfs.readthedocs.io/
BSD 2-Clause "Simplified" License
272 stars 99 forks source link

Azure AD Configuration - "Invalid Issuer" #110

Closed gunflap closed 3 years ago

gunflap commented 4 years ago

Following the installation guide found in the docs, I've run into some problems that were previously mentioned in issues #103 and #81.

Attempting to login returns: django_auth_adfs Invalid issuer Unauthorized: /oauth2/callback

This configuration demands that Django act as both Client and Resource Server. Within Azure AD B2C I have:

  1. A Native Web Application called django_native as my client.
    • With a CLIENT_ID which I will refer to as DJANGO_CLIENT_ID = ZZZZ-ZZZZ
  2. A Web Application called azure_tenant as my tenant.
    • With a TENANT_ID = AAAA-AAAA
    • With its own CLIENT_ID which I will refer to as the AZURE_CLIENT_ID = BBBB-BBBB

Naturally my demo/adfs/settings.py file looks something like:

AUTH_ADFS = {
    "TENANT_ID": "AAAA-AAAA",
    "DJANGO_CLIENT_ID": "ZZZZ-ZZZZ",    # Actually CLIENT_ID but changed for clarification.
    "RELYING_PARTY_ID": "https://<domain>.onmicrosoft.com/BBBB-BBBB",    # Ending matches AZURE_CLIENT_ID     
    "AUDIENCE": "https://<domain>.onmicrosoft.com/BBBB-BBBB",            # Same here
    "LOGIN_EXEMPT_URLS": ["^admin/$"],
}

Attempting to login I actually do get an authorization and an access token which when decoded using jwt.io shows:

{
  "aud": "BBBB-BBBB",      # AZURE_CLIENT_ID
  "iss": "https://login.microsoftonline.com/AAAA-AAAA/v2.0",     # TENANT_ID
   ...
  "name": "<nunyabeeswax>",
  "oid": "<stillnunya>",
  "preferred_username": "<nun>",
}

I've removed unnecessary fields to show that the aud tag correctly references my AZURE_CLIENT_ID. Similarly with iss, and the name fields show my user information is being accessed.

Conclusion: As you can see I've tried following the docs but as issue #81 points out they are quite outdated at this point and I'm unsure what else to do to resolve this issue. Any help is appreciated.

Side Notes: I am developing a larger Django Project similar to this, that I need to authenticate with Oauth2.0 rather than Django's default authentication. That's why django_auth_adfs seemed ideal because I figured I could just use the backend plugin to extend the larger project and minimize any changes to the existing structure. However, given the confusion in getting this simple implementation to work, I may look into an all_auth approach instead.

snowman2 commented 4 years ago

Do you mean django-allauth? That works great for me.

gunflap commented 4 years ago

I ended up scraping azure-adfs and implemented my own provider using all-auth and openid connect.

JonasKs commented 3 years ago

Closing due to inactivity.

Matyukh commented 3 years ago

I think I found what is the cause of an "Invalid issuer" problem. When a client get an access token it is a v2 version token and the iss claim in it is https://login.microsoftonline.com/<TENANT_ID>/v2.0 But when a web API application written with django_auth_adfs try to verify such token it tries to get openid connect config from an old v1 url https://login.microsoftonline.com/<TENANT_ID>/.well-known/openid-configuration?appid=<CLIENT_ID> and get an issuer claim https://sts.windows.net/<TENANT_ID>/. Thats why token validation fails. An actual OpenID Connect metadata document url can be found in Azure AD > App Registrations > Endpoints. The same issue mentioned here.

I suggest to update OpenID Connect config_url in _load_openid_config method of ProviderConfig class and replace it with https://login.microsoftonline.com/<TENANT_ID>/v2.0/.well-known/openid-configuration.

JonasKs commented 3 years ago

I see, thanks for investigating! Seems like this is based off how you register the app. See this SO thread. We use portal, so we've never had that issue.

Would you be interested in submitting a PR, allowing you to select which endpoint you want to use?
This would require updating the settings docs and azure docs to explain why this setting should be used.

Matyukh commented 3 years ago

I use portal too. I didn't get how Azure AD decides which token version to use but it seems it depends on whether you use confidential client with client secret or public client without it. For example such libraries as react-aad-msal or MSAL.js doesn't support confidential client and you can't use client secret with them. When I register such apps as single-page applications on azure portal I get v2 access tokens. But when I use MSAL Python library which supports confidential client and client secret I get v1 tokens. Which client library do you use?

I do not promise about PR, but I will try.

NaveenNirban commented 8 months ago

I am not able to understand clearly, what should be done to handle this. @Matyukh Can you help?