Completed
Pull Request — master (#44)
by Brian
10:36
created

AbstractProvider::config()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 9
rs 9.6666
cc 1
eloc 6
nc 1
nop 1
1
<?php
2
3
namespace SocialiteProviders\Manager\OAuth1;
4
5
use SocialiteProviders\Manager\SocialiteWasCalled;
6
use Symfony\Component\HttpFoundation\RedirectResponse;
7
use SocialiteProviders\Manager\ConfigTrait;
8
9
abstract class AbstractProvider extends \Laravel\Socialite\One\AbstractProvider
10
{
11
    use ConfigTrait;
12
13
    /**
14
     * Indicates if the session state should be utilized.
15
     *
16
     * @var bool
17
     */
18
    protected $stateless = true;
19
20
    /**
21
     * @var array
22
     */
23
    protected $credentialsResponseBody;
24
25
    public static function serviceContainerKey($providerName)
26
    {
27
        return SocialiteWasCalled::SERVICE_CONTAINER_PREFIX.$providerName;
28
    }
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function user()
34
    {
35
        if (!$this->hasNecessaryVerifier()) {
36
            throw new \InvalidArgumentException('Invalid request. Missing OAuth verifier.');
37
        }
38
39
        $token = $this->getToken();
40
        $tokenCredentials = $token['tokenCredentials'];
41
42
        $user = $this->mapUserToObject((array) $this->server->getUserDetails($tokenCredentials));
0 ignored issues
show
Bug introduced by
The method mapUserToObject() does not seem to exist on object<SocialiteProvider...Auth1\AbstractProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
43
44
        $user->setToken($tokenCredentials->getIdentifier(), $tokenCredentials->getSecret());
45
46
        if ($user instanceof User) {
47
            parse_str($token['credentialsResponseBody'], $credentialsResponseBody);
48
49
            if (!$credentialsResponseBody || !is_array($credentialsResponseBody)) {
50
                throw new CredentialsException('Unable to parse token credentials response.');
51
            }
52
53
            $user->setAccessTokenResponseBody($credentialsResponseBody);
54
        }
55
56
        return $user;
57
    }
58
59
    /**
60
     * Redirect the user to the authentication page for the provider.
61
     *
62
     * @return RedirectResponse
63
     */
64
    public function redirect()
65
    {
66
        if (!$this->isStateless()) {
67
            $this->request->getSession()->set(
68
                'oauth.temp', $temp = $this->server->getTemporaryCredentials()
69
            );
70
        } else {
71
            $temp = $this->server->getTemporaryCredentials();
72
            setcookie('oauth_temp', serialize($temp));
73
        }
74
75
        return new RedirectResponse($this->server->getAuthorizationUrl($temp));
76
    }
77
78
    /**
79
     * Get the token credentials for the request.
80
     *
81
     * @return \League\OAuth1\Client\Credentials\TokenCredentials
82
     */
83
    protected function getToken()
0 ignored issues
show
Coding Style introduced by
getToken uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
84
    {
85
        if (!$this->isStateless()) {
86
            $temp = $this->request->getSession()->get('oauth.temp');
87
88
            return $this->server->getTokenCredentials(
89
                $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
90
            );
91
        } else {
92
            $temp = unserialize($_COOKIE['oauth_temp']);
93
94
            return $this->server->getTokenCredentials(
95
                $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
96
            );
97
        }
98
    }
99
100
    /**
101
     * Indicates that the provider should operate as stateless.
102
     *
103
     * @return $this
104
     */
105
    public function stateless()
106
    {
107
        $this->stateless = true;
108
109
        return $this;
110
    }
111
112
    /**
113
     * Determine if the provider is operating as stateless.
114
     *
115
     * @return bool
116
     */
117
    protected function isStateless()
118
    {
119
        if (defined('SOCIALITEPROVIDERS_STATELESS')) {
120
            return true;
121
        }
122
123
        return $this->stateless;
124
    }
125
126
    /**
127
     * Set the scopes of the requested access.
128
     *
129
     * @param array $scopes
130
     *
131
     * @return $this
132
     */
133
    public function scopes(array $scopes)
134
    {
135
        $this->server = $this->server->scopes($scopes);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\OAuth1\Client\Server\Server as the method scopes() does only exist in the following sub-classes of League\OAuth1\Client\Server\Server: SocialiteProviders\Manager\OAuth1\Server. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
136
137
        return $this;
138
    }
139
140
    /**
141
     * Set the custom parameters of the request.
142
     *
143
     * @param array $parameters
144
     *
145
     * @return $this
146
     */
147
    public function with(array $parameters)
148
    {
149
        $this->server = $this->server->with($parameters);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class League\OAuth1\Client\Server\Server as the method with() does only exist in the following sub-classes of League\OAuth1\Client\Server\Server: SocialiteProviders\Manager\OAuth1\Server. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
150
151
        return $this;
152
    }
153
}
154