Reputation: 6816
I'm trying to configure ldap authentication on cakephp 3.8 using the new cakephp/authentication plugin, and I'm not sure how to match the authenticated ldap user with a local entity.
My config closely follows the documentation and is available in full here.
in my Application.php
the Application
class implements both the AuthenticationServiceProviderInterface
and the AuthorizationServiceProviderInterface
public function getAuthenticationService(ServerRequestInterface $request,
ResponseInterface $response)
{
$service = new AuthenticationService();
$service->loadIdentifier('Authentication.Password', [...]),
$service->loadIdentifier('Authentication.Ldap', [
'fields' => [
'username' => 'username',
'password' => 'password'
],
'host' => 'ldap.forumsys.com',
'port' => '389',
'bindDN' => function($username) {
return 'uid='.$username.',DC=example,DC=com';
},
'options' => [LDAP_OPT_PROTOCOL_VERSION => 3]
]);
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'email',
'password' => 'password'
],
'loginUrl' => '/users/login'
]);
return $service;
}
In my middleware, I'm trying decorate the identity with authorization stuff. When authenticating using the regular local system the $identity
is a App\Model\Entity\User
, but when logging in with a ldap user it's a Authentication\Identity
So when I call setAuthorization
'identityDecorator' => function (AuthorizationServiceInterface $authorization,
ArrayAccess $identity) {
$identity->setAuthorization($authorization);
}
it fails with a Call to undefined method Authentication\Identity::setAuthorization()
since all I have in $identity
is
object(Authentication\Identity) {
'config' => [
'fieldMap' => [
'id' => 'id'
]
],
'data' => object(ArrayObject) {
username => 'einstein'
}
}
How would I match an authenticated ldap user with their local counterpart, and transform from Authentication\Identity
to App\Model\Entity\User
?
The final goal is to also optionally generate local users from ldap data if they don't exist.
middleware attempt
Application.php
public function middleware($middlewareQueue)
{
...
$middlewareQueue->add($authentication);
$middlewareQueue->add($ldap_matcher);
$middlewareQueue->add($authorization);
return $middlewareQueue;
}
LdapMatcherMiddleware.php
class LdapMatcherMiddleware
{
public function __invoke(ServerRequestInterface $request,
ResponseInterface $response, $next)
{
$identity = $request->getAttribute('identity');
if ($identity !== null) {
$identity = $this->buildIdentity($identity);
$request = $request->withAttribute('identity', $identity);
}
$response = $next($request, $response);
return $response;
}
public function buildIdentity($identity)
{
$Users = TableRegistry::getTableLocator()->get('Users');
$username = $identity->getOriginalData()['username'];
$user = $Users->find()->where(['username' => $username])->first();
if (is_null($identity)) {
$user = $this->createLocalUserFromLdap($identity);
}
return $user;
}
public function createLocalUserFromLdap($identity)
{
$Users = TableRegistry::getTableLocator()->get('Users');
$user = $Users->newEntity([
'username' => $identity->getOriginalData()['username']
]);
$Users->save($user);
return $user;
}
}
Upvotes: 2
Views: 584
Reputation: 25698
How would I match an authenticated ldap user with their local counterpart, and transform from Authentication\Identity to App\Model\Entity\User?
I would add another middleware after the authentication middleware and do that step there.
$users = TableRegistry::getTableLocator()->get('Users');
$entity = $users->newEntity($identity->getOriginalData());
Then do whatever you need to do for authorization with this entity.
The final goal is to also optionally generate local users from ldap data if they don't exist.
Just implement your logic somewhere and get the entity the same way as shown above from the identity.
$users = TableRegistry::getTableLocator()->get('Users');
$entity = $users->newEntity($identity->getOriginalData());
// Check if it exists inside this method and if not just create it
$users->createLocalUserFromLDAP($entity);
Upvotes: 1