ecphp / cas-bundle

CAS Bundle, a standard Symfony bundle for authentication using CAS protocol.
https://ecphp-cas-bundle.readthedocs.io
BSD 3-Clause "New" or "Revised" License
43 stars 9 forks source link

Load roles from CAS attribute #6

Closed crifi closed 4 years ago

crifi commented 4 years ago

How can I load the user roles from a CAS attribute? I'm currently only getting the standard role "ROLE_CAS_AUTHENTICATED". Thank you for the nice bundle.

drupol commented 4 years ago

Hi,

AFAIK, the CAS protocol is not supposed to return ROLES. It only handles the authentication.

crifi commented 4 years ago

As you can see in the workflow diagram of the specification in the completly left yellow box, the CAS server can return optionally attributes to the app. I want to use such an attribute as array of user roles. How can I hook into the process of your bundle to get this response?

drupol commented 4 years ago

Hi,

I will investigate but I have doubts that it would end up in this package anytime soon. Unless I'm mistaken, I don't see a clear, simple and standard way to do that, unless you have a better idea? There could be many different ways to retrieve that.

Here are two examples that comes in my mind:

1) You create a custom UserProvider (just like in the ecphp/eu-login-bundle). I would recommend this method, this is the one used at European Commission. 2) You create a custom listener that will alter the user. I never tested that solution but it seems also valid.

Let me know how it goes.

crifi commented 4 years ago

Here is how I've done this now:

Link to an own UserProvider class in config/packages/cas_services.yaml:

    cas.userprovider:
        class: App\Security\CasUserProvider

This is the UserProvider class:

...
class CasUserProvider extends \EcPhp\CasBundle\Security\Core\User\CasUserProvider
{
    public function loadUserByResponse(ResponseInterface $response): CasUserInterface
    {
        ...
        if ($introspect instanceof ServiceValidate) {
            return new \App\Security\CasUser($introspect->getCredentials());
        }
        ...
    }
    ...
    public function supportsClass(string $class)
    {
        return \App\Security\CasUser::class === $class;
    }
}

Inside my own CasUser class which implements the CasUserInterface I've done this:

    ...
    public function getRoles()
    {
        $casRoles = explode(',', $this->getAttribute('roles'));
        $roles = ['ROLE_CAS_AUTHENTICATED'];
        foreach ($casRoles as $role) {
            $roles[] = 'ROLE_' .strtoupper($role);
        }
        return $roles;
    }
    ...

I can also handle all other CAS attributes now by accessing the storage attributes.

drupol commented 4 years ago

Nice, this is exactly how it should be done :-)

Feel free to close the issue if you think this is resolved and thanks for using the package!

DavidDelehelle commented 3 years ago

Hello, Thanks for your publications, it is very useful. Nevertheless I am facing a problem that I can't solved: Like advised, I have made a copy of the eu-login-bundle to manage my own authenticator/provider. I have added the private attribute "roles" and the setter "setRoles" and the getter "getRoles". In my provider I set the roles ('ROLE_USER') with "setRoles" coming from the database ("utilisateur" table) Inside the provider, the getRoles return the values 'ROLE_USER' injected (var_dump). The Identification is OK and I go through the CAS. But Symfony only find the default roles ('ROLE_CAS_AUTHENTICATED','ROLE_ADMIN' set directly in getRoles) and not the 'ROLE_USER' added in the provider with the setter. I am not able to find the reason of this behaviour; may be you could bring me some help. Thanks if you could. Delehelle David - Reims University (FR)