Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfa50a1e

Browse files
committed
Allow to use ldap in a chain provider
1 parent532dcda commitfa50a1e

File tree

6 files changed

+260
-16
lines changed

6 files changed

+260
-16
lines changed

‎src/Symfony/Component/Ldap/Security/CheckLdapCredentialsListener.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ public function onCheckPassport(CheckPassportEvent $event)
4848

4949
/** @var LdapBadge $ldapBadge */
5050
$ldapBadge =$passport->getBadge(LdapBadge::class);
51-
if ($ldapBadge->isResolved()) {
52-
return;
53-
}
5451

5552
if (!$passport->hasBadge(PasswordCredentials::class)) {
5653
thrownew \LogicException(sprintf('LDAP authentication requires a passport containing password credentials, authenticator "%s" does not fulfill these requirements.',$event->getAuthenticator()::class));
@@ -72,6 +69,9 @@ public function onCheckPassport(CheckPassportEvent $event)
7269
}
7370

7471
$user =$passport->getUser();
72+
if (!$userinstanceof LdapUser) {
73+
return;
74+
}
7575

7676
/** @var LdapInterface $ldap */
7777
$ldap =$this->ldapLocator->get($ldapBadge->getLdapServiceId());
@@ -105,7 +105,6 @@ public function onCheckPassport(CheckPassportEvent $event)
105105
}
106106

107107
$passwordCredentials->markResolved();
108-
$ldapBadge->markResolved();
109108
}
110109

111110
publicstaticfunctiongetSubscribedEvents():array

‎src/Symfony/Component/Ldap/Security/LdapAuthenticator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function supports(Request $request): ?bool
6060
publicfunctionauthenticate(Request$request):Passport
6161
{
6262
$passport =$this->authenticator->authenticate($request);
63-
$passport->addBadge(newLdapBadge($this->ldapServiceId,$this->dnString,$this->searchDn,$this->searchPassword,$this->queryString));
63+
$passport->addBadge(newLdapBadge($this->ldapServiceId,$this->dnString,$this->searchDn,$this->searchPassword,$this->queryString,true));
6464

6565
return$passport;
6666
}

‎src/Symfony/Component/Ldap/Security/LdapBadge.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
*/
2525
class LdapBadgeimplements BadgeInterface
2626
{
27-
privatebool$resolved =false;
27+
privatebool$resolved =true;
2828
privatestring$ldapServiceId;
2929
privatestring$dnString;
3030
privatestring$searchDn;
3131
privatestring$searchPassword;
3232
private ?string$queryString;
3333

34-
publicfunction__construct(string$ldapServiceId,string$dnString ='{user_identifier}',string$searchDn ='',string$searchPassword ='',string$queryString =null)
34+
publicfunction__construct(string$ldapServiceId,string$dnString ='{user_identifier}',string$searchDn ='',string$searchPassword ='',string$queryString =null,bool$resolved =false)
3535
{
3636
$this->ldapServiceId =$ldapServiceId;
3737
$dnString =str_replace('{username}','{user_identifier}',$dnString,$replaceCount);
@@ -46,6 +46,10 @@ public function __construct(string $ldapServiceId, string $dnString = '{user_ide
4646
trigger_deprecation('symfony/ldap','6.2','Using "{username}" parameter in LDAP configuration is deprecated, consider using "{user_identifier}" instead.');
4747
}
4848
$this->queryString =$queryString;
49+
$this->resolved =$resolved;
50+
if (false ===$this->resolved) {
51+
trigger_deprecation('symfony/ldap','6.4','Passing false as resolved initial value is deprecated, use true instead.');
52+
}
4953
}
5054

5155
publicfunctiongetLdapServiceId():string
@@ -75,6 +79,8 @@ public function getQueryString(): ?string
7579

7680
publicfunctionmarkResolved():void
7781
{
82+
trigger_deprecation('symfony/ldap','6.4','Calling %s is deprecated.',__METHOD__);
83+
7884
$this->resolved =true;
7985
}
8086

‎src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
useSymfony\Component\Ldap\LdapInterface;
2424
useSymfony\Component\Ldap\Security\CheckLdapCredentialsListener;
2525
useSymfony\Component\Ldap\Security\LdapBadge;
26+
useSymfony\Component\Ldap\Security\LdapUser;
2627
useSymfony\Component\Security\Core\Authentication\Token\TokenInterface;
2728
useSymfony\Component\Security\Core\Exception\AuthenticationException;
2829
useSymfony\Component\Security\Core\Exception\BadCredentialsException;
@@ -62,9 +63,10 @@ public static function provideShouldNotCheckPassport()
6263
yield [newTestAuthenticator(),newPassport(newUserBadge('test'),newPasswordCredentials('s3cret'))];
6364

6465
// ldap already resolved
65-
$badge =newLdapBadge('app.ldap');
66-
$badge->markResolved();
67-
yield [newTestAuthenticator(),newPassport(newUserBadge('test'),newPasswordCredentials('s3cret'), [$badge])];
66+
$ldapBadge =newLdapBadge('app.ldap','{user_identifier}','','',null,true);
67+
$userBadge =newUserBadge('test');
68+
$userBadge->setUserLoader(function () {returnnewInMemoryUser('test','pass', ['ROLE_USER']); });
69+
yield [newTestAuthenticator(),newPassport($userBadge,newPasswordCredentials('s3cret'), [$ldapBadge])];
6870
}
6971

7072
publicfunctiontestPasswordCredentialsAlreadyResolvedThrowsException()
@@ -74,7 +76,7 @@ public function testPasswordCredentialsAlreadyResolvedThrowsException()
7476

7577
$badge =newPasswordCredentials('s3cret');
7678
$badge->markResolved();
77-
$passport =newPassport(newUserBadge('test'),$badge, [newLdapBadge('app.ldap')]);
79+
$passport =newPassport(newUserBadge('test'),$badge, [newLdapBadge('app.ldap','{user_identifier}','','',null,true)]);
7880

7981
$listener =$this->createListener();
8082
$listener->onCheckPassport(newCheckPassportEvent(newTestAuthenticator(),$passport));
@@ -86,7 +88,7 @@ public function testInvalidLdapServiceId()
8688
$this->expectExceptionMessage('Cannot check credentials using the "not_existing_ldap_service" ldap service, as such service is not found. Did you maybe forget to add the "ldap" service tag to this service?');
8789

8890
$listener =$this->createListener();
89-
$listener->onCheckPassport($this->createEvent('s3cr3t',newLdapBadge('not_existing_ldap_service')));
91+
$listener->onCheckPassport($this->createEvent('s3cr3t',newLdapBadge('not_existing_ldap_service','{user_identifier}','','',null,true)));
9092
}
9193

9294
/**
@@ -104,7 +106,10 @@ public function testWrongPassport($passport)
104106
publicstaticfunctionprovideWrongPassportData()
105107
{
106108
// no password credentials
107-
yield [newSelfValidatingPassport(newUserBadge('test'), [newLdapBadge('app.ldap')])];
109+
yield [newSelfValidatingPassport(
110+
newUserBadge('test'),
111+
[newLdapBadge('app.ldap','{user_identifier}','','',null,true)]
112+
)];
108113
}
109114

110115
publicfunctiontestEmptyPasswordShouldThrowAnException()
@@ -198,7 +203,7 @@ public function toArray(): array
198203
$this->ldap->expects($this->once())->method('query')->with('{user_identifier}','wouter_test')->willReturn($query);
199204

200205
$listener =$this->createListener();
201-
$listener->onCheckPassport($this->createEvent('s3cr3t',newLdapBadge('app.ldap','{user_identifier}','elsa','test1234A$','{user_identifier}_test')));
206+
$listener->onCheckPassport($this->createEvent('s3cr3t',newLdapBadge('app.ldap','{user_identifier}','elsa','test1234A$','{user_identifier}_test',true)));
202207
}
203208

204209
publicfunctiontestEmptyQueryResultShouldThrowAnException()
@@ -226,14 +231,16 @@ public function testEmptyQueryResultShouldThrowAnException()
226231
$this->ldap->expects($this->once())->method('query')->willReturn($query);
227232

228233
$listener =$this->createListener();
229-
$listener->onCheckPassport($this->createEvent('s3cr3t',newLdapBadge('app.ldap','{user_identifier}','elsa','test1234A$','{user_identifier}_test')));
234+
$listener->onCheckPassport($this->createEvent('s3cr3t',newLdapBadge('app.ldap','{user_identifier}','elsa','test1234A$','{user_identifier}_test',true)));
230235
}
231236

232237
privatefunctioncreateEvent($password ='s3cr3t',$ldapBadge =null)
233238
{
239+
$ldapUser =newLdapUser(newEntry('cn=Wouter,dc=example,dc=com'),'Wouter',null, ['ROLE_USER']);
240+
234241
returnnewCheckPassportEvent(
235242
newTestAuthenticator(),
236-
newPassport(newUserBadge('Wouter',fn () =>newInMemoryUser('Wouter',null, ['ROLE_USER'])),newPasswordCredentials($password), [$ldapBadge ??newLdapBadge('app.ldap')])
243+
newPassport(newUserBadge('Wouter',fn () =>$ldapUser),newPasswordCredentials($password), [$ldapBadge ??newLdapBadge('app.ldap','{user_identifier}','','',null,true)])
237244
);
238245
}
239246

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSecurity;
13+
14+
usePHPUnit\Framework\TestCase;
15+
useSymfony\Bridge\PhpUnit\ExpectDeprecationTrait;
16+
useSymfony\Component\Ldap\Security\LdapBadge;
17+
18+
finalclass LdapBadgeTestextends TestCase
19+
{
20+
use ExpectDeprecationTrait;
21+
22+
/**
23+
* @group legacy
24+
*/
25+
publicfunctiontestDeprecationOnResolvedInitialValue()
26+
{
27+
$this->expectDeprecation('Since symfony/ldap 6.4: Passing false as resolved initial value is deprecated, use true instead.');
28+
29+
newLdapBadge('foo');
30+
}
31+
32+
/**
33+
* @group legacy
34+
*/
35+
publicfunctiontestDeprecationOnMarkAsResolved()
36+
{
37+
$this->expectDeprecation('Since symfony/ldap 6.4: Calling Symfony\Component\Ldap\Security\LdapBadge::markResolved is deprecated.');
38+
39+
$sut =newLdapBadge('foo','{user_identifier}','','',null,true);
40+
$sut->markResolved();
41+
}
42+
}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespaceSymfony\Component\Security\Core\Tests\Authentication\Provider;
13+
14+
usePHPUnit\Framework\TestCase;
15+
usePsr\Container\ContainerInterface;
16+
useSymfony\Component\EventDispatcher\EventDispatcher;
17+
useSymfony\Component\HttpFoundation\Request;
18+
useSymfony\Component\HttpFoundation\Response;
19+
useSymfony\Component\HttpFoundation\Session\Session;
20+
useSymfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
21+
useSymfony\Component\Ldap\Adapter\AdapterInterface;
22+
useSymfony\Component\Ldap\Adapter\CollectionInterface;
23+
useSymfony\Component\Ldap\Adapter\ConnectionInterface;
24+
useSymfony\Component\Ldap\Adapter\QueryInterface;
25+
useSymfony\Component\Ldap\Entry;
26+
useSymfony\Component\Ldap\Exception\ConnectionException;
27+
useSymfony\Component\Ldap\Ldap;
28+
useSymfony\Component\Ldap\Security\CheckLdapCredentialsListener;
29+
useSymfony\Component\Ldap\Security\LdapAuthenticator;
30+
useSymfony\Component\Ldap\Security\LdapUserProvider;
31+
useSymfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
32+
useSymfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
33+
useSymfony\Component\Security\Core\User\ChainUserProvider;
34+
useSymfony\Component\Security\Core\User\InMemoryUserProvider;
35+
useSymfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
36+
useSymfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
37+
useSymfony\Component\Security\Http\Authentication\AuthenticatorManager;
38+
useSymfony\Component\Security\Http\Authenticator\FormLoginAuthenticator;
39+
useSymfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
40+
useSymfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
41+
useSymfony\Component\Security\Http\Event\CheckPassportEvent;
42+
useSymfony\Component\Security\Http\EventListener\UserProviderListener;
43+
useSymfony\Component\Security\Http\HttpUtils;
44+
45+
class ChainProviderWithLdapTestextends TestCase
46+
{
47+
publicfunctionprovideChainWithLdapAndInMemory():array
48+
{
49+
return [
50+
'in memory' => ['foo','foopass'],
51+
'ldap' => ['bar','barpass'],
52+
];
53+
}
54+
55+
/**
56+
* @dataProvider provideChainWithLdapAndInMemory
57+
*/
58+
publicfunctiontestChainWithLdapAndInMemory(string$userIdentifier,string$pass)
59+
{
60+
$inMemoryProvider =newInMemoryUserProvider([
61+
'foo' => ['password' =>'foopass','roles' => ['ROLE_USER']],
62+
]);
63+
64+
$ldapAdapteur =$this->createMock(AdapterInterface::class);
65+
$ldapAdapteur
66+
->method('getConnection')
67+
->willReturn($connection =$this->createMock(ConnectionInterface::class))
68+
;
69+
70+
$connection
71+
->method('bind')
72+
->willReturnCallback(staticfunction (?string$user, ?string$pass):void {
73+
if ('admin' ===$user &&'adminpass' ===$pass) {
74+
return;
75+
}
76+
77+
if ('bar' ===$user &&'barpass' ===$pass) {
78+
return;
79+
}
80+
81+
thrownewConnectionException('failure when binding');
82+
})
83+
;
84+
85+
$ldapAdapteur
86+
->method('escape')
87+
->willReturnArgument(0)
88+
;
89+
90+
$ldapAdapteur
91+
->method('createQuery')
92+
->willReturn($query =$this->createMock(QueryInterface::class))
93+
;
94+
95+
$query
96+
->method('execute')
97+
->willReturn($collection =$this->createMock(CollectionInterface::class));
98+
99+
$collection
100+
->method('count')
101+
->willReturn(1)
102+
;
103+
104+
$collection
105+
->method('offsetGet')
106+
->with(0)
107+
->willReturn(newEntry('cn=bar,dc=example,dc=com', ['sAMAccountName' => ['bar'],'userPassword' => ['barpass']]))
108+
;
109+
110+
$ldapProvider =newLdapUserProvider($ldap =newLdap($ldapAdapteur),'dc=example,dc=com','admin','adminpass', [],null,null,'userPassword');
111+
112+
$chainUserProvider =newChainUserProvider([$inMemoryProvider,$ldapProvider]);
113+
114+
$httpUtils =$this->createMock(HttpUtils::class);
115+
$httpUtils
116+
->method('checkRequestPath')
117+
->willReturn(true)
118+
;
119+
120+
$failureHandler =$this->createMock(AuthenticationFailureHandlerInterface::class);
121+
$failureHandler
122+
->method('onAuthenticationFailure')
123+
->willReturn(newResponse())
124+
;
125+
126+
$formLoginAuthenticator =newFormLoginAuthenticator(
127+
$httpUtils,
128+
$chainUserProvider,
129+
$this->createMock(AuthenticationSuccessHandlerInterface::class),
130+
$failureHandler,
131+
[]
132+
);
133+
134+
$ldapAuthenticator =newLdapAuthenticator($formLoginAuthenticator,'ldap-id');
135+
136+
$ldapLocator =newclass($ldap)implements ContainerInterface {
137+
private$ldap;
138+
139+
publicfunction__construct(Ldap$ldap)
140+
{
141+
$this->ldap =$ldap;
142+
}
143+
144+
publicfunctionget(string$id):Ldap
145+
{
146+
return$this->ldap;
147+
}
148+
149+
publicfunctionhas(string$id):bool
150+
{
151+
return'ldap-id' ===$id;
152+
}
153+
};
154+
155+
$eventDispatcher =newEventDispatcher();
156+
$eventDispatcher->addListener(CheckPassportEvent::class, [newUserProviderListener($chainUserProvider),'checkPassport']);
157+
$eventDispatcher->addListener(CheckPassportEvent::class, [newCheckLdapCredentialsListener($ldapLocator),'onCheckPassport']);
158+
$eventDispatcher->addListener(CheckPassportEvent::class,function (CheckPassportEvent$event):void {
159+
$passport =$event->getPassport();
160+
$userBadge =$passport->getBadge(UserBadge::class);
161+
if (null ===$userBadge ||null ===$userBadge->getUser()) {
162+
return;
163+
}
164+
$credentials =$passport->getBadge(PasswordCredentials::class);
165+
if ($credentials->isResolved()) {
166+
return;
167+
}
168+
169+
if ($credentials &&'foopass' ===$credentials->getPassword()) {
170+
$credentials->markResolved();
171+
}
172+
});
173+
174+
$authenticatorManager =newAuthenticatorManager(
175+
[$ldapAuthenticator],
176+
$tokenStorage =newTokenStorage(),
177+
$eventDispatcher,
178+
'main'
179+
);
180+
181+
$request = Request::create('/login','POST', ['_username' =>$userIdentifier,'_password' =>$pass]);
182+
$request->setSession(newSession(newMockArraySessionStorage()));
183+
184+
$this->assertTrue($authenticatorManager->supports($request));
185+
$authenticatorManager->authenticateRequest($request);
186+
187+
$this->assertInstanceOf(UsernamePasswordToken::class,$token =$tokenStorage->getToken());
188+
$this->assertSame($userIdentifier,$token->getUserIdentifier());
189+
}
190+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp