使用 Laravel 的 Azure Active Directory SSO [英] Azure Active Directory SSO with Laravel

查看:36
本文介绍了使用 Laravel 的 Azure Active Directory SSO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 azure 活动目录执行 sso.我已经在 azure 上完成了设置并打开了钥匙.我正在使用 Metrogistics/laravel-azure-ad-oauth (

我已将以下配置添加到 env 文件中,并执行了包要求的任何操作.

AZURE_AD_CLIENT_ID=XXXXXXXXXXXXXXXXXX(这是来自 azure 的应用程序 ID)AZURE_AD_CLIENT_SECRET=XXXXXXXXX(在 azure 上创建了一个新密钥)

我在互联网上搜索了两天,但找不到解决方案.我在这里遗漏了什么?

谢谢,

解决方案

对于那些仍在努力在 LaravelAzure Active Directory SSO 的人们.如果您愿意使用 SAML.这是他们可以使用的存储库.

d) 创建一个新文件 config/saml2/aad_idp_settings.php 并将 config/saml2/test_idp_settings.php 的内容复制到它.将 aad_idp_settings.php 中的 $this_idp_env_id 更改为 'AAD'.所以最终的 aad_idp_settings.php 将如下所示.

true,//@todo: 让它依赖于 laravel 配置//启用调试模式(打印错误)'调试' =>环境('APP_DEBUG',假),//我们正在部署的服务提供者数据'sp' =>大批(//指定对要使用的名称标识符的约束//代表请求的主题.//查看 lib/Saml2/Constants.php 以查看支持的 NameIdFormat'NameIDFormat' =>'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',//通常 SP 的 x509cert 和 privateKey 由放置在//证书文件夹.但是我们也可以为他们提供以下参数'x509cert' =>env('SAML2_'.$this_idp_env_id.'_SP_x509',''),'私钥' =>env('SAML2_'.$this_idp_env_id.'_SP_PRIVATEKEY',''),//SP实体的标识符(URI).//留空以使用 '{idpName}_metadata' 路由,例如'测试元数据'.'entityId' =>env('SAML2_'.$this_idp_env_id.'_SP_ENTITYID',''),//指定有关  的位置和方式的信息消息必须是//返回给请求者,在这种情况下是我们的 SP.'assertionConsumerService' =>大批(// 所在的 URL 位置从 IdP 将被退回,//使用 HTTP-POST 绑定.//留空以使用 '{idpName}_acs' 路由,例如'test_acs''网址' =>'',),//指定关于<注销响应>的位置和方式的信息消息必须是//返回给请求者,在这种情况下是我们的 SP.//删除此部分以在元数据中不包含任何 URL 位置.'singleLogoutService' =>大批(// 所在的 URL 位置从 IdP 将被退回,//使用 HTTP 重定向绑定.//留空以使用 '{idpName}_sls' 路由,例如'test_sls''网址' =>'',),),//我们想要与我们的 SP 连接的身份提供者数据'idp' =>大批(//IdP 实体的标识符(必须是 URI)'entityId' =>env('SAML2_'.$this_idp_env_id.'_IDP_ENTITYID', $idp_host .'/saml2/idp/metadata.php'),//IdP 的 SSO 端点信息.(认证请求协议)'singleSignOnService' =>大批(//SP 将发送身份验证请求消息的 IdP 的 URL 目标,//使用 HTTP 重定向绑定.'网址' =>env('SAML2_'.$this_idp_env_id.'_IDP_SSO_URL', $idp_host .'/saml2/idp/SSOService.php'),),//IdP 的 SLO 端点信息.'singleLogoutService' =>大批(//SP 将发送 SLO 请求的 IdP 的 URL 位置,//使用 HTTP 重定向绑定.'网址' =>env('SAML2_'.$this_idp_env_id.'_IDP_SL_URL', $idp_host .'/saml2/idp/SingleLogoutService.php'),),//IdP 的公共 x509 证书'x509cert' =>env('SAML2_'.$this_idp_env_id.'_IDP_x509', 'MIID/TCCAuWgAwIBAgIJAI4R3WyjjmB1MA0GCS'),/** 您可以使用指纹代替使用整个 x509cert* (openssl x509 -noout -fingerprint -in "idp.crt" 生成它)*///'certFingerprint' =>'',),/***** OneLogin 高级设置***///安全设定'安全' =>大批(/** 提供签名和加密 *///表示的nameID由该 SP 发送//将被加密.'nameIdEncrypted' =>错误的,//指示是否此 SP 发送的消息//将被签名.[SP 的元数据将提供此信息]'auhnRequestsSigned' =>错误的,//指示是否此 SP 发送的消息//将被签名.'logoutRequestSigned' =>错误的,//指示是否此 SP 发送的消息//将被签名.'logoutResponseSigned' =>错误的,/* 对元数据进行签名假||真(使用 sp 证书) ||大批 (密钥文件名 =>'元数据.key',certFileName =>'元数据.crt')*/'signMetadata' =>错误的,/** 需要签名和加密 **///表示对<samlp:Response>、<samlp:LogoutRequest>的要求和//<samlp:LogoutResponse>此 SP 接收到的要签名的元素.'wantMessagesSigned' =>错误的,//表示对 <saml:Assertion> 的要求接收到的元素//这个要签名的SP.[SP 的元数据将提供此信息]'wantAssertionsSigned' =>错误的,//表示对接收到的 NameID 的要求//这个要加密的SP.'wantNameIdEncrypted' =>错误的,//身份验证上下文.//设置为 false 并且不会在 AuthNRequest 中发送 AuthContext,//设置为 true 或不提供此参数,您将获得一个 AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'//使用可能的身份验证上下文值设置一个数组: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),'requestedAuthnContext' =>真的,),//联系方式模板,建议提供技术支持联系人'联系人' =>大批('技术' =>大批('给定名称' =>'姓名','电子邮件地址' =>'no@reply.com'),'支持' =>大批('给定名称' =>'支持','电子邮件地址' =>'no@reply.com'),),//组织信息模板,推荐en_US lang中的信息,如果需要可以添加更多'组织' =>大批('en-US' =>大批('名称' =>'姓名','显示名称' =>'显示名称','网址' =>'http://网址'),),/* 可互操作的 SAML 2.0 Web 浏览器 SSO 配置文件 [saml2int] http://saml2int.org/profile/current'auhnRequestsSigned' =>false,//SP 不应签署 <samlp:AuthnRequest>,//不得假设 IdP 验证了符号'wantAssertionsSigned' =>真的,'wantAssertionsEncrypted' =>true,//如果 SSL/HTTPs 被禁用,则必须启用'wantNameIdEncrypted' =>错误的,*/);

e) 现在我们需要放置以下 ENV 变量

SAML2_AAD_IDP_ENTITYID=SAML2_AAD_IDP_SSO_URL=SAML2_AAD_IDP_SL_URL=SAML2_AAD_IDP_x509=

前 3 个环境变量的值将来自此处.

最后一个环境变量将来自以下

f) 运行 php artisan make:provider SAML2ServiceProvider.这将在 app/Providers/SAML2ServiceProvider.php 中创建一个文件.

boot 方法中粘贴以下代码段

Event::listen('AacotroneoSaml2EventsSaml2LoginEvent', function (Saml2LoginEvent $event) {$messageId = $event->getSaml2Auth()->getLastMessageId();//添加您自己的代码,防止重用 $messageId 以阻止重放攻击$user = $event->getSaml2User();$用户数据 = ['id' =>$user->getUserId(),'属性' =>$user->getAttributes(),'断言' =>$user->getRawSamlAssertion()];$输入 = ['sso_user_id' =>$user->getUserId(),'用户名' =>self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),'电子邮件' =>self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),'first_name' =>self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),'姓氏' =>self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),'密码' =>Hash::make('任何东西'),];$user = User::where('sso_user_id', $inputs['sso_user_id'])->where('email', $inputs['email'])->first();如果(!$用户){$res = PortalUser::store($inputs);if($res['status'] == 'success'){$user = $res['data'];Auth::guard('web')->login($user);}别的{Log::info('SAML 用户错误'.$res['messages']);}}别的{Auth::guard('web')->login($user);}});

最后在config/app.phpproviders数组中注册这个提供者.

.

测试 SAML AAD SSO

<小时>

https://my-laravel-website.com/saml2/aad/login

I'm doing sso with azure active directory. I have done the setup on azure and go the keys. I'm using metrogistics/laravel-azure-ad-oauth (https://packagist.org/packages/metrogistics/laravel-azure-ad-oauth) package on laravel to do this. However, when I hit the url http://localhost:8000/login/microsoft , I got redirected to microsoft login page and given an error message.

I have added following configurations to env file and did whatever package has demanded.

AZURE_AD_CLIENT_ID=XXXXXXXXXXXXXXXXXX (this is application id from azure) AZURE_AD_CLIENT_SECRET=XXXXXXXXX (created a new key on azure)

It's been two days I'm searching the internet but could not find a solution. What is it I'm missing here?

Thanks,

解决方案

For those people who are still struggling to Azure Active Directory SSO in Laravel. And if you are willing to use SAML. Here is the repo they can use.

https://github.com/aacotroneo/laravel-saml2

It's very simple to use provided you have done SSO setup correctly on Azure portal.

It is two step process

Step 1- Setup SSO project on Azure Portal


a) Go to Azure Active Directory and then Enterprise Application

b) Add New Application and choose Non-gallery Application

c) Click Set up single sign on and then click on SAML Box

d) Edit the basic SAML configuration and add the following

Identifier (Entity ID) - https://my-laravel-website.com/saml2/aad/metadata

Reply URL (Assertion Consumer Service URL) - https://my-laravel-website.com/saml2/aad/acs

(From where these urls are coming, I will explain in Step 2. For now just save it.)

e) Download Federation Metadata XML from SAML Signing Certificate section, on your system

f) Next assign users to your current SAML SSO project.

Note- If there is no user exist in your account. Then you need to create one and assign some role(it's necessary).

This is the tutorial to setup step 1 https://www.youtube.com/watch?v=xn_8Fm7S7y8

.

Step 2- Install and configure Laravel SAML 2 package in your Project


a) run composer require aacotroneo/laravel-saml2

b) run php artisan vendor:publish --provider="AacotroneoSaml2Saml2ServiceProvider"

c) config/saml2_settings.php

<?php

return $settings = array(

    /**
     * Array of IDP prefixes to be configured e.g. 'idpNames' => ['test1', 'test2', 'test3'],
     * Separate routes will be automatically registered for each IDP specified with IDP name as prefix
     * Separate config file saml2/<idpName>_idp_settings.php should be added & configured accordingly
     */
    'idpNames' => ['aad'],

    /**
     * If 'useRoutes' is set to true, the package defines five new routes for reach entry in idpNames:
     *
     *    Method | URI                                | Name
     *    -------|------------------------------------|------------------
     *    POST   | {routesPrefix}/{idpName}/acs       | saml_acs
     *    GET    | {routesPrefix}/{idpName}/login     | saml_login
     *    GET    | {routesPrefix}/{idpName}/logout    | saml_logout
     *    GET    | {routesPrefix}/{idpName}/metadata  | saml_metadata
     *    GET    | {routesPrefix}/{idpName}/sls       | saml_sls
     */
    'useRoutes' => true,

    /**
     * Optional, leave empty if you want the defined routes to be top level, i.e. "/{idpName}/*"
     */
    'routesPrefix' => 'saml2',

    /**
     * which middleware group to use for the saml routes
     * Laravel 5.2 will need a group which includes StartSession
     */
    'routesMiddleware' => ['saml'],

    /**
     * Indicates how the parameters will be
     * retrieved from the sls request for signature validation
     */
    'retrieveParametersFromServer' => false,

    /**
     * Where to redirect after logout
     */
    'logoutRoute' => '/login',

    /**
     * Where to redirect after login if no other option was provided
     */
    'loginRoute' => '/dashboard',

    /**
     * Where to redirect after login if no other option was provided
     */
    'errorRoute' => '/login',

    // If 'proxyVars' is True, then the Saml lib will trust proxy headers
    // e.g X-Forwarded-Proto / HTTP_X_FORWARDED_PROTO. This is useful if
    // your application is running behind a load balancer which terminates
    // SSL.
    'proxyVars' => true,

    /**
     * (Optional) Which class implements the route functions.
     * If commented out, defaults to this lib's controller (AacotroneoSaml2HttpControllersSaml2Controller).
     * If you need to extend Saml2Controller (e.g. to override the `login()` function to pass
     * a `$returnTo` argument), this value allows you to pass your own controller, and have
     * it used in the routes definition.
     */
     'saml2_controller' => 'AppHttpControllersAuthSAML2LoginController',
);

Note - Part d) of Step 1 is coming from the following

d) Create a new file config/saml2/aad_idp_settings.php and copy the contents of config/saml2/test_idp_settings.php into it. Change $this_idp_env_id in aad_idp_settings.php to 'AAD'. So the final aad_idp_settings.php will look like the following.

<?php

// If you choose to use ENV vars to define these values, give this IdP its own env var names
// so you can define different values for each IdP, all starting with 'SAML2_'.$this_idp_env_id
$this_idp_env_id = 'AAD';

//This is variable is for simplesaml example only.
// For real IdP, you must set the url values in the 'idp' config to conform to the IdP's real urls.
$idp_host = env('SAML2_'.$this_idp_env_id.'_IDP_HOST', 'http://localhost:8000/simplesaml');

return $settings = array(

    /*****
     * One Login Settings
     */

    // If 'strict' is True, then the PHP Toolkit will reject unsigned
    // or unencrypted messages if it expects them signed or encrypted
    // Also will reject the messages if not strictly follow the SAML
    // standard: Destination, NameId, Conditions ... are validated too.
    'strict' => true, //@todo: make this depend on laravel config

    // Enable debug mode (to print errors)
    'debug' => env('APP_DEBUG', false),

    // Service Provider Data that we are deploying
    'sp' => array(

        // Specifies constraints on the name identifier to be used to
        // represent the requested subject.
        // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported
        'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',

        // Usually x509cert and privateKey of the SP are provided by files placed at
        // the certs folder. But we can also provide them with the following parameters
        'x509cert' => env('SAML2_'.$this_idp_env_id.'_SP_x509',''),
        'privateKey' => env('SAML2_'.$this_idp_env_id.'_SP_PRIVATEKEY',''),

        // Identifier (URI) of the SP entity.
        // Leave blank to use the '{idpName}_metadata' route, e.g. 'test_metadata'.
        'entityId' => env('SAML2_'.$this_idp_env_id.'_SP_ENTITYID',''),

        // Specifies info about where and how the <AuthnResponse> message MUST be
        // returned to the requester, in this case our SP.
        'assertionConsumerService' => array(
            // URL Location where the <Response> from the IdP will be returned,
            // using HTTP-POST binding.
            // Leave blank to use the '{idpName}_acs' route, e.g. 'test_acs'
            'url' => '',
        ),
        // Specifies info about where and how the <Logout Response> message MUST be
        // returned to the requester, in this case our SP.
        // Remove this part to not include any URL Location in the metadata.
        'singleLogoutService' => array(
            // URL Location where the <Response> from the IdP will be returned,
            // using HTTP-Redirect binding.
            // Leave blank to use the '{idpName}_sls' route, e.g. 'test_sls'
            'url' => '',
        ),
    ),

    // Identity Provider Data that we want connect with our SP
    'idp' => array(
        // Identifier of the IdP entity  (must be a URI)
        'entityId' => env('SAML2_'.$this_idp_env_id.'_IDP_ENTITYID', $idp_host . '/saml2/idp/metadata.php'),
        // SSO endpoint info of the IdP. (Authentication Request protocol)
        'singleSignOnService' => array(
            // URL Target of the IdP where the SP will send the Authentication Request Message,
            // using HTTP-Redirect binding.
            'url' => env('SAML2_'.$this_idp_env_id.'_IDP_SSO_URL', $idp_host . '/saml2/idp/SSOService.php'),
        ),
        // SLO endpoint info of the IdP.
        'singleLogoutService' => array(
            // URL Location of the IdP where the SP will send the SLO Request,
            // using HTTP-Redirect binding.
            'url' => env('SAML2_'.$this_idp_env_id.'_IDP_SL_URL', $idp_host . '/saml2/idp/SingleLogoutService.php'),
        ),
        // Public x509 certificate of the IdP
        'x509cert' => env('SAML2_'.$this_idp_env_id.'_IDP_x509', 'MIID/TCCAuWgAwIBAgIJAI4R3WyjjmB1MA0GCS'),
        /*
         *  Instead of use the whole x509cert you can use a fingerprint
         *  (openssl x509 -noout -fingerprint -in "idp.crt" to generate it)
         */
        // 'certFingerprint' => '',
    ),



    /***
     *
     *  OneLogin advanced settings
     *
     *
     */
    // Security settings
    'security' => array(

        /** signatures and encryptions offered */

        // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
        // will be encrypted.
        'nameIdEncrypted' => false,

        // Indicates whether the <samlp:AuthnRequest> messages sent by this SP
        // will be signed.              [The Metadata of the SP will offer this info]
        'authnRequestsSigned' => false,

        // Indicates whether the <samlp:logoutRequest> messages sent by this SP
        // will be signed.
        'logoutRequestSigned' => false,

        // Indicates whether the <samlp:logoutResponse> messages sent by this SP
        // will be signed.
        'logoutResponseSigned' => false,

        /* Sign the Metadata
         False || True (use sp certs) || array (
                                                    keyFileName => 'metadata.key',
                                                    certFileName => 'metadata.crt'
                                                )
        */
        'signMetadata' => false,


        /** signatures and encryptions required **/

        // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
        // <samlp:LogoutResponse> elements received by this SP to be signed.
        'wantMessagesSigned' => false,

        // Indicates a requirement for the <saml:Assertion> elements received by
        // this SP to be signed.        [The Metadata of the SP will offer this info]
        'wantAssertionsSigned' => false,

        // Indicates a requirement for the NameID received by
        // this SP to be encrypted.
        'wantNameIdEncrypted' => false,

        // Authentication context.
        // Set to false and no AuthContext will be sent in the AuthNRequest,
        // Set true or don't present thi parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
        // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'),
        'requestedAuthnContext' => true,
    ),

    // Contact information template, it is recommended to suply a technical and support contacts
    'contactPerson' => array(
        'technical' => array(
            'givenName' => 'name',
            'emailAddress' => 'no@reply.com'
        ),
        'support' => array(
            'givenName' => 'Support',
            'emailAddress' => 'no@reply.com'
        ),
    ),

    // Organization information template, the info in en_US lang is recomended, add more if required
    'organization' => array(
        'en-US' => array(
            'name' => 'Name',
            'displayname' => 'Display Name',
            'url' => 'http://url'
        ),
    ),

/* Interoperable SAML 2.0 Web Browser SSO Profile [saml2int]   http://saml2int.org/profile/current

   'authnRequestsSigned' => false,    // SP SHOULD NOT sign the <samlp:AuthnRequest>,
                                      // MUST NOT assume that the IdP validates the sign
   'wantAssertionsSigned' => true,
   'wantAssertionsEncrypted' => true, // MUST be enabled if SSL/HTTPs is disabled
   'wantNameIdEncrypted' => false,
*/

);

e) Now we need to put following ENV vars

SAML2_AAD_IDP_ENTITYID=
SAML2_AAD_IDP_SSO_URL=
SAML2_AAD_IDP_SL_URL=
SAML2_AAD_IDP_x509=

The value of first 3 env vars will be coming from here.

The last Env var will come from following

f) run php artisan make:provider SAML2ServiceProvider. This will create a file in app/Providers/SAML2ServiceProvider.php.

In the boot method paste the following snippet

Event::listen('AacotroneoSaml2EventsSaml2LoginEvent', function (Saml2LoginEvent $event) {
            $messageId = $event->getSaml2Auth()->getLastMessageId();
            // Add your own code preventing reuse of a $messageId to stop replay attacks

            $user = $event->getSaml2User();
            $userData = [
                'id' => $user->getUserId(),
                'attributes' => $user->getAttributes(),
                'assertion' => $user->getRawSamlAssertion()
            ];

            $inputs = [
                'sso_user_id'  => $user->getUserId(),
                'username'     => self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),
                'email'        => self::getValue($user->getAttribute('http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name')),
                'first_name'   => self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),
                'last_name'    => self::getValue($user->getAttribute('http://schemas.microsoft.com/identity/claims/displayname')),
                'password'     => Hash::make('anything'),
             ];

            $user = User::where('sso_user_id', $inputs['sso_user_id'])->where('email', $inputs['email'])->first();
            if(!$user){
                $res = PortalUser::store($inputs);
                if($res['status'] == 'success'){
                    $user  = $res['data'];
                    Auth::guard('web')->login($user);
                }else{
                    Log::info('SAML USER Error '.$res['messages']);
                }
            }else{
                Auth::guard('web')->login($user);
            }

        });

and finally register this provider in providers array of config/app.php.

.

Test the SAML AAD SSO


https://my-laravel-website.com/saml2/aad/login

这篇关于使用 Laravel 的 Azure Active Directory SSO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆