Symfony多个Ldap提供程序

问题描述 投票:0回答:1

我无法使用服务和安全配置(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。 I,E:

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

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

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

2个问题:

  1. 有没有办法在保持简单的同时验证用户对2个ldap库?
  2. 如果他们可以选择通过登录表单进行验证的库,那会更好,这会通过某种输入传递吗?

EG

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

提前致谢。

symfony security ldap symfony-3.3
1个回答
0
投票

我设法通过将request_matcher参数添加到安全性来使其工作:

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>

防火墙按顺序命中,因此首先检查基本防火墙,如果返回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。

© www.soinside.com 2019 - 2024. All rights reserved.