oroinc / platform

Main OroPlatform package with core functionality.
Other
627 stars 351 forks source link

Oauth2 Get Access Token Error when have a Master/Slave Database #1030

Open Briones opened 4 years ago

Briones commented 4 years ago

Summary
I was trying the Oauth2 authentication with Oro and it worked well localy, but when I tried in a production environment it started to throw errors like this:

League\OAuth2\Server\Exception\OAuthServerException

The resource owner or authorization server denied the request.

So after several tests I realize that the difference between environments is that in production we have a "master" database and a "slave" database for replication. So the problem was that I the access token is generated succesfuly, but when the system tries to use the generated token it fails, because Oro is trying to match the token with the "Slave DB", and the replication in the DB takes a few seconds, so it doesn't find the token and throws the error.

Steps to reproduce

  1. Is needed to have a crm-application with "master/slave" configuration in the doctrine section of the config.yml, something like this:

    doctrine:
    dbal:
        default_connection:   default
        connections:
            default:
                driver:       "%database_driver%"
                host:         "%database_host%"
                port:         "%database_port%"
                dbname:       "%database_name%"
                user:         "%database_user%"
                password:     "%database_password%"
                charset:      utf8mb4
                default_table_options:
                    charset: utf8mb4
                    collate: utf8mb4_unicode_ci
    
                slaves:
                    slave1:
                        dbname: "%database_name%"
                        host: "%database_slave1_host%"
                        port: "%database_port%"
                        user: "%database_user%"
                        password: "%database_password%"
                        charset: utf8mb4
  2. Have an external system that generates an Access Token for Oro through the /oauth2-token oro Endpoint.

  3. Use the token in another Oro endpoint with the 'Authorization' => 'Bearer ' . $accessToken

Actual Result The system will throw an error:

The resource owner or authorization server denied the request.

Expected Result
There should be no errors in a request with a new access token.

Proposed solution I fixed in my system overriding the Class vendor/oro/oauth2-server/src/Oro/Bundle/OAuth2ServerBundle/League/Repository/AccessTokenRepository.php and forcing to use master DB when it tries to get the access tokens, like this:

 public function findAccessTokenEntity($tokenId): ?AccessToken
    {
        // To get always the token from the master db and avoid the delay of slave replication
        $this->getEntityManager()->getConnection()->connect('master');

        return $this->getEntityManager()->getRepository(AccessToken::class)
            ->findOneBy(['identifier' => $tokenId]);
    }

I think that solution could be easily implemented on Oro's side, since it makes sense to always have consistency for recently created tokens.

Details about your environment