Symfony多个Ldap提供程序

时间:2017-12-13 13:43:54

标签: symfony security ldap symfony-3.3

我无法使用服务和安全配置(Symfony 3.3)针对多个ldap库验证用户。

我正在使用Ldap symfony组件并为两个不同的主机创建2个ldap配置服务。

services.yml:

ldap1:
    class: Symfony\Component\Ldap\Ldap
    arguments: ['@ldap_adapter1']
ldap_adapter1:
    class: Symfony\Component\Ldap\Adapter\ExtLdap\Adapter
    arguments:
        -   host: serldap.abc.fr
            port: 389
            options:
                protocol_version: 3
                referrals: false
ldap2:
    class: Symfony\Component\Ldap\Ldap
    arguments: ['@ldap_adapter2']
ldap_adapter2:
    class: Symfony\Component\Ldap\Adapter\ExtLdap\Adapter
    arguments:
        -   host: ldap.xyz.fr
            port: 389
            options:
                protocol_version: 3
                referrals: false

security.yml:

security:
    providers:
        chain_provider:
            chain:
                providers: [ldap_1, ldap_2]
        ldap_1:
            ldap:
                service: ldap1
                base_dn: ou=abcaccount,dc=abc,dc=fr
                search_dn: uid=a1,ou=abcaccount,dc=abc,dc=fr
                search_password: pass1
                default_roles: ROLE_USER
                uid_key: uid
        ldap_2:
            ldap:
                service: ldap2
                base_dn: ou=xyzaccount,dc=xyz,dc=fr
                search_dn: uid=a2,ou=xyzaccount,dc=xyz,dc=fr
                search_password: pass2
                default_roles: ROLE_USER
                uid_key: uid
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            pattern: ^/
            anonymous: ~
            provider: chain_provider
            form_login_ldap:
                login_path: login
                check_path: login


    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_USER }

如果我在form_login_ldap下添加dn_string。我,e:

dn_string: 'uid={username},ou=xyzaccount,dc=xyz,dc=fr'

这样可行,问题是这只能为一个Ldap配置。如果没有这行,我会收到以下错误:

  

php.DEBUG:警告:ldap_bind():无法绑定到服务器:无效的DN   语法

2个问题:

  1. 是否有任何方法可以验证用户对2个ldap库的影响 保持简单?

  2. 如果他们可以选择,那就更好了 它们通过登录表单进行验证的库 通过作为某种输入传递?

  3. e.g。

    dn_string: 'uid={username},ou={chosenOUInForm},dc={chosenDC1InForm},dc={chosenDC2InForm}'
    

    提前致谢。

1 个答案:

答案 0 :(得分:0)

我设法通过将request_matcher param添加到安全性来实现它:

security:
    providers:
        chain_provider:
            chain:
                providers: [ldap_1, ldap_2]
        ldap_1:
            ldap:
                service: ldap1
                base_dn: ou=abcaccount,dc=abc,dc=fr
                search_dn: ~
                search_password: ~
                default_roles: ROLE_USER
                uid_key: uid
        ldap_2:
            ldap:
                service: ldap2
                base_dn: ou=xyzaccount,dc=xyz,dc=fr
                search_dn: ~
                search_password: ~
                default_roles: ROLE_USER
                uid_key: uid

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false


        base:
            pattern: ^/
            request_matcher: app.base_firewall_matcher
            anonymous: ~
            form_login_ldap:
                service: ldap1 # this doesn't matter for the base firewall as it is never passed with no check_path
                login_path: login


        one:
            pattern: ^/
            request_matcher: app.first_firewall_matcher
            anonymous: ~
            provider: ldap_1
            form_login_ldap:
                service: ldap1
                login_path: login
                check_path: login_1_check
                dn_string: 'uid={username},ou=abcaccount,dc=abc,dc=fr'

        two:
            pattern: ^/
            request_matcher: app.second_firewall_matcher
            anonymous: ~
            provider: ldap_2
            form_login_ldap:
                service: ldap2
                login_path: login
                check_path: login_2_check
                dn_string: 'uid={username},ou=xyzaccount,dc=xyz,dc=fr'

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_USER }

表单页面(登录路径返回的twig页面)将有一个按钮将表单提交到login_1_check,一个按钮将表单提交到login_2_check:



 <form action="{{ path('login_1_check') }}" method="post">
                <input type="text" id="username" name="_username"/>
                <input type="password" id="password" name="_password" />
	<button type="submit">login to LDAP 1</button>
    <button type="submit" formaction="{{ path('login_2_check') }}">login to LDAP 2</button>
</form>
&#13;
&#13;
&#13;

防火墙按顺序命中,因此首先检查基本防火墙,如果返回true(如果用户尚未通过身份验证或登录表单未提交),则会转到登录路径。

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;


class BaseFirewallMatcher implements RequestMatcherInterface
{

    // Should only be matched on login page when user first arrives to GET the form, if already validated with one
    // of the other two security providers, they will be checked against their respective firewalls.
    public function matches(Request $request){

        $session = $request->getSession();
        $oneValidated = $session->get("_security_one", null);
        $twoValidated = $session->get("_security_two", null);


        // If already validated with another security provider
        if($oneValidated or $twoValidated){
            return false;
        }
        else{

            $url = $request->getPathInfo();
            // If these two logins are not matched
            if($url != "/login_1_check" && $url != "/login_2_check"){
                return true;
            }
            else{

                return false;
            }

        }

    }
}

当用户通过按其中一个按钮提交时,基本防火墙将不会被触发,因为BaseFirewallMatcher将返回false。然后完成第一次LDAP检查,转到以下请求匹配器。

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

class FirstFirewallMatcher implements RequestMatcherInterface
{

    public function matches(Request $request){


        $session = $request->getSession();
        $oneValidated = $session->get("_security_one", null);
        $twoValidated = $session->get("_security_two", null);



        if($twoValidated){
            return false;
        }

        else{
            if($oneValidated){
                return true;
            }
            $url = $request->getPathInfo();
            if ($url == "/login_1_check"){
                return true;
            }
            else{
                return false;
            }
        }

    }
}

返回true,即如果用户已使用ldap1进行了身份验证,或者用户已选择登录ldap1。然后触发防火墙。

如果这返回false,例如当用户选择登录ldap2或已经使用ldap2进行身份验证时 - 它将转到下一个请求匹配器:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;

class SecondFirewallMatcher implements RequestMatcherInterface
{


    public function matches(Request $request){

        $session = $request->getSession();
        $oneValidated = $session->get("_security_one", null);
        $twoValidated = $session->get("_security_two", null);



        if($oneValidated){
            return false;
        }
        else{
            if($twoValidated){
                return true;
            }
            $url = $request->getPathInfo();
            dump($url);

            if ($url == "/login_2_check"){
                return true;
            }
            else{
                return false;
            }
        }

    }
}

请记住为每个request_matcher设置服务:

app.base_firewall_matcher:
    class: {pathtofirewallmatcher}\BaseFirewallMatcher
app.first_firewall_matcher:
    class: {pathtofirewallmatcher}\FirstFirewallMatcher
app.second_firewall_matcher:
    class: {pathtofirewallmatcher}\SecondFirewallMatcher

代码可能不完美,因为最后我转向了不同类型的身份验证。但这似乎在当时有效,我假设您可以根据需要添加尽可能多的ldaps。