FOSOAuthServerBundle icon indicating copy to clipboard operation
FOSOAuthServerBundle copied to clipboard

Error accessing route fos_oauth_server_authorize - Call to a member function getUser() on null

Open faelp22 opened this issue 7 years ago • 10 comments

This problem is similar to #425, does anyone have an idea of what this might be?

faelp22 avatar Dec 11 '17 20:12 faelp22

My Settings:

app/config/config.yml

# FOSUserBundle config
fos_user:
    db_driver: orm 
    firewall_name: main
    user_class: path\bundle\Entity\User
    from_email:
        address: "%mailer_user%"
        sender_name: "%mailer_user%"

# FOSOauthServerBundle config
fos_oauth_server:
    db_driver:           orm
    client_class:        path\bundle\Entity\Client
    access_token_class:  path\bundle\Entity\AccessToken
    refresh_token_class: path\bundle\Entity\RefreshToken
    auth_code_class:     path\bundle\Entity\AuthCode
    service:
        user_provider: fos_user.user_provider.username

app/config/security.yml

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:

        oauth_token:
            pattern: ^/oauth/v2/token
            security: false

        oauth_authorize:
            pattern: ^/oauth/v2/auth
            security: false

        doc:
            pattern: ^/api/v1/doc
            fos_oauth: false
            stateless: true
            anonymous: true

        api:
            pattern: ^/api/v1
            fos_oauth: true
            stateless: true
            anonymous: false

        main:
            pattern: ^/
            fos_oauth: false
            form_login:
                provider: fos_userbundle
                csrf_token_generator: security.csrf.token_manager
            logout:
                path:   /logout
                target: /
            anonymous:    true

faelp22 avatar Dec 11 '17 20:12 faelp22

composer show  friendsofsymfony/*
friendsofsymfony/oauth-server-bundle 1.5.2  Symfony2 OAuth Server Bundle
friendsofsymfony/oauth2-php          1.2.1  OAuth2 library
friendsofsymfony/rest-bundle         2.3.0  This Bundle provides various tools to rapidly develop RESTful API's with Symfony
friendsofsymfony/user-bundle         v2.0.2 Symfony FOSUserBundle

faelp22 avatar Dec 11 '17 20:12 faelp22

@faelp22 could you provide a full stacktrace?

dkarlovi avatar Dec 12 '17 11:12 dkarlovi

@dkarlovi Thanks.

Call to a member function getUser() on null 500 Internal Server Error - FatalThrowableError
Stack Trace
in vendor/friendsofsymfony/oauth-server-bundle/Controller/AuthorizeController.php at line 58

$user = $this->getTokenStorage()->getToken()->getUser();
---------------------------------------
Log
CRITICAL - Uncaught PHP Exception Symfony\Component\Debug\Exception\FatalThrowableError: "Call to a member function getUser() on null" at .../api/vendor/friendsofsymfony/oauth-server-bundle/Controller/AuthorizeController.php line 58

is this call ...->getToken() the same is returning null

faelp22 avatar Dec 12 '17 13:12 faelp22

@dkarlovi

I've already tried calling the user in other ways like:

$user = $this->getUser();

Or

$user = $this->get('security.token_storage')->getToken()->getUser();

But all of them are returning null and this form that is placed in the AuthorizeController is the best way.

Another observation: I am logged into the system, but it is as if the authentication registered in the session was not reached.

And even if the system was not logged in, I should be directed to the login page, I have used this system before and it worked.

faelp22 avatar Dec 12 '17 13:12 faelp22

@faelp22, I have noticed that you left the authorization end-point unprotected. This is why you have a problem with the user object not being populated. It's the same problem as in #425.

Note that documentation clearly states you should use an authentication mechanism.

To help you better understand the flow, here's how it works like:

  1. the USER want's to use APP and wants to login using an account from WEB
  2. APP tries to obtain authorization code from WEB
  3. WEB requires USER login, so APP redirects the user to WEB login form
  4. the USER logs into the WEB application
  5. he agrees the APP should have access to his account and be able to do stuff on his behalf
  6. WEB sends authorization code to APP
  7. APP requests access token
  8. APP uses access token to do stuff on user's behalf

Legend:

  • APP - 3rd party application. It could be a web application, mobile application or any other entity that could perform stuff on user's behalf.
  • WEB - A web application using FOSOAuthServerBundle.
  • USER - the person using APP and WEB.

I hope this is helpful.

dinamic avatar Jan 26 '18 12:01 dinamic

@dinamic Thank you for your help.

You could be clearer about the solution, I didn't understand where I went wrong. Could you show me an example of a solution?

faelp22 avatar Jan 26 '18 13:01 faelp22

Sure.

As mentioned in the documentation, you should have a firewall guarding the auth end-point:

        oauth_authorize:
            pattern:    ^/oauth/v2/auth
            # Add your favorite authentication process here

You could use form_login or the Symfony Guard component.

Here's how I have configured it for an application I am currently working on:

        oauth_login:
            pattern: '^/oauth/v2/auth_login$'
            security: false

        oauth_token:
            pattern:    '^/oauth/v2/token'
            security:   false

        oauth_authorize:
            pattern:    '^/oauth/v2/auth'
            guard:
              authenticators:
                - 'my_service.login_form_authenticator'

...

    access_control:
        - { path: ^/oauth/v2/auth_login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/oauth/v2/auth, role: ROLE_USER }

Translated this would mean:

  1. Don't use a firewall when the user is accessing /oauth/v2/auth_login. This makes sense, because on this URL I am showing a login form, so the user could enter his username and password.

  2. Don't use a firewall when the user is accessing /oauth/v2/token*. This is used for token renewals, so it should be available without requiring user login.

  3. Enable the firewall if the user accesses /oauth/v2/auth*. This is the call that you should put security on. As seen in the access_control section, it requires a user having the ROLE_USER role in order to access the URL.

As you can see, I am making use of the Symfony Guard component, but you can use the form_login feature as well. There's no limitation on what you are going to use to secure the end-point.

If you are keen on giving the Guard component a go, here's a nice tutorial on KnP University:

  • https://knpuniversity.com/screencast/symfony-security

PS: I used to have the same problem as you - not knowing how to proceed, despite the fact that I have followed the documentation and ended up in the middle of nowhere. I think the documentation is to blame and we should definitely improve it.

dinamic avatar Jan 26 '18 15:01 dinamic

Thank you very much I managed to solve.

The problem was:

csrf_token_generator: security.csrf.token_manager

Traded for

csrf_provider: form.csrf_provider

New Setup was like this:

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

    role_hierarchy:
        ROLE_FORCEPASSWORDCHANGE: ROLE_FORCEPASSWORDCHANGE
        ROLE_USER:          [ROLE_USER, ROLE_TEACHER]
        ROLE_SUPER_ADMIN:   [ROLE_ROOT, ROLE_ADMIN]

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username

    firewalls:

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

        oauth_token:
            pattern: ^/oauth/v2/token
            security: false

        oauth_authorize:
            pattern: ^/oauth/v2/auth
            form_login:
                provider: fos_userbundle
                check_path: /oauth/v2/auth/login_check
                login_path: /oauth/v2/auth/login
            anonymous: true

        api:
            pattern: ^/api/v1
            fos_oauth: true
            stateless: true
            anonymous: false

        doc:
            pattern: ^/api/v1/doc
            fos_oauth: false
            stateless: true
            anonymous: true

    access_control:
        - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/oauth/v2/auth, role: IS_AUTHENTICATED_FULLY }
        - { path: ^/internal*, roles: IS_AUTHENTICATED_FULLY }
        - { path: ^/api/v1*, roles: IS_AUTHENTICATED_FULLY }

faelp22 avatar Jan 26 '18 17:01 faelp22

Please, feel free to close the ticket if the matter is resolved :)

dinamic avatar Jan 26 '18 21:01 dinamic