Search code examples
apisymfonyfosuserbundlews-securitywsse

WSSE Authentication using FOSUserBundle


I have a problem when I want to authenticate a user with WSSE from my REST API created with Symfony. I followed the guide on the site symfony wsse authentication (http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html) and have completed the tutorial (http://obtao.com/blog/2013/06/configure-wsse-on-symfony-with-fosrestbundle/) and user management is handled with FOSUserBundle.

By default, I wsse authenticates requests accessing the resource /api. So I in my security.yml

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: ROLE_ADMIN

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:
        wsse_secured:
            pattern:   /api/.*
            stateless: true
            wsse:      true
            anonymous : false

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


        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                csrf_provider: form.csrf_provider
            logout:       true
            anonymous:    true

    access_control:
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/, role: ROLE_ADMIN } 

And to access my resource /api/hello, I added to my request header:

Authorization: Authorization profile=”UsernameToken”
x-wsse: UsernameToken Username="foo", PasswordDigest="9/dyW92Vp+mWEbyXeblRMqTQSJc=", Nonce="MDc1MGNkZjAwMjNmZjk2YQ==", Created="2014-04-17T16:18:34Z"

But after sending the query I get an error that is returned to me:

WSSE Login failed for foo. Why? No Authentication Provider found for token of class "Acme \ UserBundle \ Security \ Authentication \ Token \ WsseUserToken".

This error message is an exception raised in my WsseListener Class:

try {
        $authToken = $this->authenticationManager->authenticate($token);
        $this->securityContext->setToken($authToken);
    return;
    } catch (AuthenticationException $failed) {
         $failedMessage = 'WSSE Login failed for '.$token->getUsername().'. Why ? '.$failed->getMessage();
         // Deny authentication with a '403 Forbidden' HTTP response
         $response = new Response();
         $response->setStatusCode(403);
         $response->setContent($failedMessage);
         $event->setResponse($response);
         return; 
    }

Solution

  • Ok, I just found the problem...

    In my authentificate method (WsseProvider Class), I did return nothing !

    BEFORE (doesn't works):

    public function authenticate(TokenInterface $token)
     {
        $user = $this->userProvider->loadUserByUsername($token->getUsername());
        if(!$user){
          throw new AuthenticationException("Bad credentials... Did you forgot your username ?");
        }
        if ($user && 
            $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) {
        }
    }
    

    AFTER(works):

        public function authenticate(TokenInterface $token)
        {
            $user = $this->userProvider->loadUserByUsername($token->getUsername());
            if(!$user){
                throw new AuthenticationException("Bad credentials... Did you forgot your username ?");
            }
            if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) {
            $authenticatedToken = new WsseUserToken($user->getRoles());
            $authenticatedToken->setUser($user);
    
            return $authenticatedToken;
        }
        throw new AuthenticationException('The WSSE authentication failed.');
    }
    

    Everything is OK now !