flipboxfactory / saml-sp

SAML Service Provider (SP) Plugin for Craft CMS
https://saml-sp.flipboxfactory.com/
Other
19 stars 5 forks source link

Integration with Azure AD #37

Closed benjaminkohl closed 5 years ago

benjaminkohl commented 5 years ago

This might be an issue with me not being a SAML expert, but the people that are responsible for managing our client's Azure AD SSO are asking me for redirect URIs for: identity, callback and logout. They said once they get that, they can provide the application ID, client secrets, metadata and token endpoint.

Unless I am mistaken, these sound more like OAuth terms rather than SAML terms. But what do I know? I specifically mentioned SAML in my email to them so I am feeling a bit lost. Are there instructions online for configuring the plugin's settings with Azure AD?

Edit (by @dsmrt): For configuring Azure AD, follow these instructions 👉 Azure AD

dsmrt commented 5 years ago

Great question! Going to pin this because I've got a lot of AD questions lately.

I'm not sure what they mean by identity but here's what I found after some quick testing.

There are a few things you need to pass along:

  1. The certificate for your provider. You can download that from the "My Provider" security tab (/admin/saml-sp/metadata/my-provider#security)
  2. Assertion Consumer Service (ACS) Endpoint. I believe this is what they mean by the callback. It will be something like this: https://my-sp.domain.com/sso/login
  3. Single logout/SLO Endpoint: https://my-sp.domain.com/sso/logout

Once they create the App, ask them to send you the metadata (like normal) but also the Application ID. The application ID needs to be your entity id now. You can overwrite that system-wide by setting it here: /admin/saml-sp/settings (it can be an environmental variable). Once you set that, you need to recreate "My Provider" so the new entity id is picked up and saved in the plugin correctly.

I think that is it but let me know if you run into any issues.

dsmrt commented 5 years ago

Side note on mappings....

You can view the metadata to identify the attributes passed on to you. They will look like these:

You can configure the IdP like so:

Screen Shot 2019-10-02 at 1 07 02 PM

benjaminkohl commented 5 years ago

Great, thank you! We will definitely need to store some of the attributes to the user profile so that will be helpful as well. I'll get back to the client and see what they say and go from there.

benjaminkohl commented 5 years ago

The person responsible for our client's Azure AD SSO got back to me with an application ID (uuid), a client secret and a link to the XML metadata. I think all I need is that XML metadata, right? Otherwise I am not sure where that UUID or client secret play into SAML.

dsmrt commented 5 years ago

Application ID is important here. You need to make the Application ID your Entity ID now. Currently, the best way to overwrite this is to set it system wide here: /admin/saml-sp/settings. Note that you can set that as an environmental variable. Once that is set make sure to either resave or delete and save a new "My Provider".

benjaminkohl commented 5 years ago

I am unable to save the provided application ID to that entity field. I copy and paste it in then click the "Save" button to update the plugin settings and I get the following exception and stack trace:

2019-10-14 09:46:07 [-][9][e8c528f73c65c856b36b93190d958eeb][error][yii\base\InvalidConfigException] yii\base\InvalidConfigException: Object configuration must be an array containing a "class" element. in /home/user/site.com/hub/prod/vendor/yiisoft/yii2/BaseYii.php:353
Stack trace:
#0 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Component.php(750): yii\BaseYii::createObject(Array)
#1 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Component.php(734): yii\base\Component->attachBehaviorInternal('error', Array)
#2 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Component.php(603): yii\base\Component->ensureBehaviors()
#3 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Controller.php(274): yii\base\Component->trigger('beforeAction', Object(yii\base\ActionEvent))
#4 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/web/Controller.php(164): yii\base\Controller->beforeAction(Object(yii\base\InlineAction))
#5 /home/user/site.com/hub/prod/vendor/craftcms/cms/src/web/Controller.php(143): yii\web\Controller->beforeAction(Object(yii\base\InlineAction))
#6 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Controller.php(155): craft\web\Controller->beforeAction(Object(yii\base\InlineAction))
#7 /home/user/site.com/hub/prod/vendor/craftcms/cms/src/web/Controller.php(187): yii\base\Controller->runAction('save', Array)
#8 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('save', Array)
#9 /home/user/site.com/hub/prod/vendor/craftcms/cms/src/web/Application.php(299): yii\base\Module->runAction('saml-sp/setting...', Array)
#10 /home/user/site.com/hub/prod/vendor/craftcms/cms/src/web/Application.php(566): craft\web\Application->runAction('saml-sp/setting...', Array)
#11 /home/user/site.com/hub/prod/vendor/craftcms/cms/src/web/Application.php(278): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#12 /home/user/site.com/hub/prod/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
#13 /home/user/site.com/hub/prod/public/index.php(26): yii\base\Application->run()
#14 {main}
2019-10-14 09:46:07 [-][9][e8c528f73c65c856b36b93190d958eeb][info][application] $_GET = [
    'p' => 'admin/saml-sp/settings'
]

This is version 2.0.9 of the plugin and version 3.3.9 of Craft.

dsmrt commented 5 years ago

Working on a patch for this now.

dsmrt commented 5 years ago

@benjaminkohl Should be good now. Try running a composer update flipboxfactory/saml-sp. The core lib should update as well.

benjaminkohl commented 5 years ago

Ok, it let me save the settings and per these instructions (WARNING: If this value is changed, you must recreate "My Provider" and exchange the metadata or values with the other provider (IdP or SP).), I went into my provider and re-saved so now I have two providers in the Service Provider List on the Provider List page.

So now I need to grab the metadata XML provided by our client managing the IDP again and paste it into that box for this newly created service provider?

dsmrt commented 5 years ago

Nope. Just recreate the SP (your provider). So go back to my provider (here: /admin/saml-sp/metadata/my-provider) and save a new one. You'll probably see 2 now. You can delete the one that doesn't match the new entity id/azure AD application id which should be the old one.

Hopefully all of that makes a little sense. Azure wants the Entity ID to be the application id and currently the only way to do that is to set it system wide. When you set that value system-wide, you have to recreate you metadata and save (what happens when you save from /admin/saml-sp/metadata/my-provider) so everything in the craft db is updated.

benjaminkohl commented 5 years ago

There is a read-only field for Login Path and it instructed me to place that value as the loginPath item in the general config file. I grabbed the relative URI from that value and placed it in there. When I try to access the site and it redirects to that login path, I just see the 404 page.

The URL it told me to use looks like: sso/login/{uuid}

dsmrt commented 5 years ago

Ok ... try adding request into the path like so: /sso/login/request/{uid}

I'll push a patch for that readonly field.

benjaminkohl commented 5 years ago

Ok, thanks. Now I see it performing some redirects but I end up at the Craft error screen for "Bad Request" with the following message:

Identity Provider is not found. Possibly a configuration problem. Issuer/EntityId: https://sts.windows.net/{different uuid that came from provider metadata xml}/

dsmrt commented 5 years ago

Do you see that entity id in the provider list under IdPs? If not, create the idp in the craft plugin with the Azure AD metadata. You should see the entity id there: Screen Shot 2019-10-15 at 2 56 05 PM

benjaminkohl commented 5 years ago

I think I needed to recreate the IDP because now the Entity ID changed and I updated the loginPath accordingly and I also recreated the SAML assertion attribute mappings on the IDP like you outlined in a previous comment. It appears to be authenticating now but I am getting the following exception while it attempts to save the user to Craft which results in a 500 error on the site:

2019-10-16 11:03:49 [-][-][c4ad7e583eff0d8d7cd98a1206f39f8e][error][saml-sp] User save failed: {"email":["Email cannot be blank."]} 2019-10-16 11:03:49 [-][-][c4ad7e583eff0d8d7cd98a1206f39f8e][error][yii\base\UserException] yii\base\UserException: User save failed: {"email":["Email cannot be blank."]} in /home/user/domain/hub/prod/vendor/flipboxfactory/saml-sp/src/services/login/User.php:124 Stack trace:

0 /home/user/domain/hub/prod/vendor/flipboxfactory/saml-sp/src/services/login/User.php(99): flipbox\saml\sp\services\login\User->save(Object(craft\elements\User))

1 /home/user/domain/hub/prod/vendor/flipboxfactory/saml-sp/src/services/Login.php(62): flipbox\saml\sp\services\login\User->sync(Object(craft\elements\User), Object(SAML2\Response))

2 /home/user/domain/hub/prod/vendor/flipboxfactory/saml-sp/src/controllers/LoginController.php(85): flipbox\saml\sp\services\Login->login(Object(SAML2\Response))

3 [internal function]: flipbox\saml\sp\controllers\LoginController->actionIndex()

4 /home/user/domain/hub/prod/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)

5 /home/user/domain/hub/prod/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)

6 /home/user/domain/hub/prod/vendor/craftcms/cms/src/web/Controller.php(187): yii\base\Controller->runAction('', Array)

7 /home/user/domain/hub/prod/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('', Array)

8 /home/user/domain/hub/prod/vendor/craftcms/cms/src/web/Application.php(299): yii\base\Module->runAction('saml-sp/login', Array)

9 /home/user/domain/hub/prod/vendor/yiisoft/yii2/web/Application.php(103): craft\web\Application->runAction('saml-sp/login', Array)

10 /home/user/domain/hub/prod/vendor/craftcms/cms/src/web/Application.php(284): yii\web\Application->handleRequest(Object(craft\web\Request))

11 /home/user/domain/hub/prod/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))

12 /home/user/domain/hub/prod/public/index.php(26): yii\base\Application->run()

13 {main}

dsmrt commented 5 years ago

Are you sure the fields are configured correctly? Is the email address point to Email in the craft property column like so? I've made the mistake of not setting that correctly and seeing this error.

Screen Shot 2019-10-02 at 1 07 02 PM

benjaminkohl commented 5 years ago

Yes, that is set correctly. I've also proofread the Attribute Name a few times to make sure I typed it correctly. I'm not spotting any inconsistencies but just in case, here it is:

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress

benjaminkohl commented 5 years ago

I am currently looking at this documentation. Perhaps the people managing the account haven't configured it to provide the email address. I'll get in touch with them and see what they say.

dsmrt commented 5 years ago

Ok cool ... Also try using this tail grep command. You should be able to see the attributes or the plugin debug looking for the attributes in there.

tail -f storage/logs/web.log | grep -A 10 -n '\[saml-'

benjaminkohl commented 5 years ago

I found that they are sending the email address in the "name" attribute so I updated the plugin settings and I was able to successfully log in. Thanks for all the help with this! It has been very much appreciated.

dsmrt commented 5 years ago

I'm going to close this but feel free to reopen if needed, on AD specific stuff.

tonyclemmey commented 4 years ago

Hi @dsmrt

I am following some of the steps mentioned here in regards to Integration with Azure AD.

I have a question regarding the possibility of mapping Groups via a Role claim - https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-enterprise-app-role-management

The desired result would be to fetch the role of the SSO user in AD and then map it to a Craft group id/name, so the user would be assigned to a Craft group by default, but the one which it would be mapped to depending on the role.

For example :

adRole1 => craftGroup1 adRole2 => craftGroup2 adRole3 => craftGroup3

A new SSO user with an AD role of "adRole1" would get assigned to Craft group "craftGroup1" by default.

I hope this sounds clear enough.

tonyclemmey commented 4 years ago

Hi @dsmrt

I am following some of the steps mentioned here in regards to Integration with Azure AD.

I have a question regarding the possibility of mapping Groups via a Role claim - https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-enterprise-app-role-management

The desired result would be to fetch the role of the SSO user in AD and then map it to a Craft group id/name, so the user would be assigned to a Craft group by default, but the one which it would be mapped to depending on the role.

For example :

adRole1 => craftGroup1 adRole2 => craftGroup2 adRole3 => craftGroup3

A new SSO user with an AD role of "adRole1" would get assigned to Craft group "craftGroup1" by default.

I hope this sounds clear enough.

dsmrt commented 4 years ago

:wave: @tonyclemmey ,

Quick note: The Craft User group must already exist in Craft for any this mapping to work. We used to create groups automatically (if the implementer wanted) but since that breaks with the project config, we can no longer do this.

Thanks for the link. I'm not too familiar with AD role claims but it looks like they come through Assertion Attributes, which should work.

Another thing I notice with your example is the naming from AD roles should map to a Craft group with a different name/handle (ie, adRole1 => craftGroup1). Unfortunately the plugin doesn't have support for this.

The logic is pretty simple: Screen Shot 2020-09-10 at 10 06 58 AM

BUT, you can hook into the plugin using a Yii Event: https://saml-sp.flipboxfactory.com/configure/events.html#examples

If the mapping needed is as described, feel free to put in an enhancement issue in for this feature request. Just be warned, feature requests these days take some time to push out (up to a few months).

espensgr commented 3 years ago

We have a setup with Craft as a admin backend, with multisite, that acts like an api for generated static Nuxt as frontend. All of the sites (1 backend and 2 frontend) have different domains and the users should only login to the backend. How do i setup so the loginPath goes to the backend? When i have tried to set it up it goes to the frontend domain with /sso/login. My first time adding an SSO, and the costumer haven't used Azure that much either :flushed:

dsmrt commented 3 years ago

@espensgr moved your question to it's own issue. I think this is more of a static site issue to tackle than an Azure AD issue.

See #101

dsmrt commented 3 years ago

This issue is no longer the best "instructions" when configuring Azure AD. I've updated the docs based on updates to the plugin here 👉 Azure AD. Please follow those instructions moving forward.

espensgr commented 3 years ago

I still think the steps and documentation is a bit confusing for someone that hasen't setup SSO before. Is it possible to make a video click-walkthrough/screencast on how to setup this with Azure AD, or maybe other ones too? It may just be my peanut sized brain though 🤣

dsmrt commented 3 years ago

That would be nice. I think i could get something like that going.

Also, lack of understanding has nothing to do with size of brain. SAML was built by alien’s to confuse humans and hinder progress. It’s confusing.

I’ll look into the video thing. I think it’d be nice to have a resource like that. Especially with Azure AD.

espensgr commented 3 years ago

Nice!

Yeah, i actually think that SAML stands for Sampling Alien Management Licence, so you are correct.