Login with EntraID (Azure)

Hello!

We are using the latest all in one docker setup and it’s working fine.

I’m just wondering regarding login. Is there a possibility to be able to let users authenticate against Microsoft Entra (aka Azure AD) some way?

I read somewhere that SAML is possible (but i dont find a documentation/howto). It would be great to have a Tutorial like this ones that covers the topic regarding specify7:

Hi @dfernandez,

At this time, we only support identity providers (IdPs) that have an OpenID endpoints.

It looks like Azure AD provides an OpenID Connect endpoint that you can use to authenticate users and obtain identity information.

If you need help getting this configured in Specify, just let me know!

Hello @Specify ! Thank you for your reply

In fact, yes. How to configure this (so adding a idP) this mentioned specify_settings.py in Docker compose or elswhere? I dont find any information about this part. I’m using the “all-in-one” docker template.

Hi Dfernandez –

Thanks for your follow-up. Grant and our back end developer are both out this week, they may chirp in here, but likely it will be next week before we can try to help. Thanks for your patience.

Jim Beach.

Great, thank you!

Hey, you’ll need to override the settings file with the SSO information.
Here is an example from our GitHub repository https://github.com/specify/specify7/blob/34301626534618aeb4c9e831a12ca87f1eab4f88/specifyweb/settings/specify_settings.py#L90
Here is an example nmbe_settings.py file:

import os
DATABASE_NAME = os.environ['DATABASE_NAME']
DATABASE_HOST = os.environ['DATABASE_HOST']
DATABASE_PORT = os.environ.get('DATABASE_PORT', '')
MASTER_NAME = os.environ['MASTER_NAME']
MASTER_PASSWORD = os.environ['MASTER_PASSWORD']
DEPOSITORY_DIR = '/volumes/static-files/depository'
REPORT_RUNNER_HOST = os.getenv('REPORT_RUNNER_HOST', '')
REPORT_RUNNER_PORT = os.getenv('REPORT_RUNNER_PORT', '')
WEB_ATTACHMENT_URL = os.getenv('ASSET_SERVER_URL', None)
WEB_ATTACHMENT_KEY = os.getenv('ASSET_SERVER_KEY', None)
WEB_ATTACHMENT_COLLECTION = os.getenv('ASSET_SERVER_COLLECTION', None)
CELERY_BROKER_URL = os.getenv('CELERY_BROKER_URL', None)
CELERY_RESULT_BACKEND = os.getenv('CELERY_RESULT_BACKEND', None)
CELERY_TASK_DEFAULT_QUEUE = os.getenv('CELERY_TASK_QUEUE', DATABASE_NAME)
ANONYMOUS_USER = os.getenv('ANONYMOUS_USER', None)

OAUTH_LOGIN_PROVIDERS = {
    'nmbe': {
        'title': " NMBE",
        'config': " https://login.microsoftonline.com/8605a91a-efbc-4eb5-84c9-0aed78380fa6/v2.0",
        'scope': "openid email",
        'client_id': "your-client-id",
        'client_secret': "your-client-secret",
    },
}

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

In you docker-compose.yml file, add this settings file in the volumes section so that it overwrites the local_settings.py file:

...
specify7:
    restart: unless-stopped
    image: specifyconsortium/specify7-service:v7
    init: true
    volumes:
      - "specify6:/opt/Specify:ro"
      - "static-files:/volumes/static-files"
      - "nmbe_settings.py:/opt/specify7/settings/local_specify_settings.py:ro"
...

Hi @alec.white !

Thank you for this instruction/example. Im almost there. At login im getting an error now:

Blockquote
The redirect URI ‘http://myurl.mydomain.ch/accounts/oic_callback/’ specified in the request does not match the redirect URIs configured for the application ‘d008201f-ec04-46cb-873a-de5662b509da’. Make sure the redirect URI sent in the request matches

  1. I configured the callbackurl as https://myurl.mydomain.ch/accounts/oic_callback/ (with https)

  2. I call https://myurl.mydomain.ch for login in with the browser

Do im missing something? This piece here:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

needs to be there or in nginx-config?

Just a little follow up. Specify does not send https as redirect uri in the oauth request atm:

oauth

So maybe i have something missing somewhere in the configuration.

Hi @alec.white, is there maybe a way to allow to configure/ovveride/force the redirect_uri protocol in the provider configuration? If im right, the composition of the callback_uri happens here: specify7/specifyweb/accounts/views.py at 0a47efcd66919958dad31e46bebdbc31b2ff436e · specify/specify7 · GitHub

OAUTH_LOGIN_PROVIDERS = {
    'nmbe': {
        'title': " NMBE",
        'config': " https://login.microsoftonline.com/8605a91a-efbc-4eb5-84c9-0aed78380fa6/v2.0",
        'scope': "openid email",
        'client_id': "your-client-id",
        'client_secret': "your-client-secret",
        'callback_uri_proto': "https", #something like this?
    },
}

I dont see a way to fix that otherwise. As mentioned

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

this does nothing in my case

Hey, I was able to look into the problem with the redirect_url not using https. I made a code change on a branch named sso-https. I hoping that will work for you. If you are using docker, pull this image specifyconsortium/specify7-service:sso-https. Try it with and without SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') in your config. Let me know if this fixes your issue and I’ll make sure to add the code to the next release.

Hello @alec.white !

Sorry for the late reply, i tested this branch and now i can confirm that i works (somehow). No matter if i add or not the

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

part. The callback uri is now with https. When i come back from microsoft online, i get following error:

{"exception": "KeyError", "message": "id_token", "data": "None", "traceback": "Traceback (most recent call last):\n File \"/opt/specify7/ve/lib/python3.8/site-packages/django/core/handlers/base.py\", line 181, in _get_response\n response = wrapped_callback(request, *callback_args, **callback_kwargs)\n File \"/opt/specify7/ve/lib/python3.8/site-packages/django/views/decorators/http.py\", line 40, in inner\n return func(request, *args, **kwargs)\n File \"/opt/specify7/specifyweb/accounts/views.py\", line 183, in oic_callback\n id_token = get_token.json()['id_token']\nKeyError: 'id_token'\n"}

It could be because the user is not existent in specify somehow yet? do i need to setup first in specify? I followed the guide here:

  1. created a user withou password and send invitation link. Results in same error mentioned.

I believe that issue comes when your OAuth provider’s authorized redirect URIs are not setup to allow redirects to Specify. When I did a test setup with Google’s OAuth service, I needed to add https://sp7test.specifycloud.org/auth/complete/google-oauth2/ to the list of Authorized redirect URIs. Let me know if that doesn’t solve your problem. For you the redirect should be something like https://nmbe.specifycloud.org/auth/complete/azure-oauth2/

Well, the redirect uri i defined as https://www.mydomain.ch/accounts/oic_callback/ - then i get the mentioned error

if i call directly https://www.mydomain.ch/auth/complete/azure-oauth2/ i get a 404 … is there documented somewhere what the possible urls could be?

If i take a look here:

the https://www.mydomain.ch/accounts/oic_callback/ is the only that makes sense.

if i go to this endpoint: https://www.mydomain.ch/accounts/oic_providers/

i get back

grafik

in the logs i see following unspecific error:

2024-02-05T15:15:30.562964260Z [05/Feb/2024 15:15:30] [ERROR] [django.request:224] Internal Server Error: /accounts/oic_callback/

Could you run specify in debug mode so we could get more info?

In .env file, set SP7_DEBUG=true