Completed
Push — master ( 054f6d...b0bfec )
by Brian
10:01
created

AbstractProvider::serviceContainerKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace SocialiteProviders\Manager\OAuth1;
4
5
use SocialiteProviders\Manager\Config;
6
use SocialiteProviders\Manager\SocialiteWasCalled;
7
use Symfony\Component\HttpFoundation\RedirectResponse;
8
9
abstract class AbstractProvider extends \Laravel\Socialite\One\AbstractProvider
10
{
11
    /**
12
     * Indicates if the session state should be utilized.
13
     *
14
     * @var bool
15
     */
16
    protected $stateless = true;
17
18
    /**
19
     * @var array
20
     */
21
    protected $credentialsResponseBody;
22
23
    public static function serviceContainerKey($providerName)
24
    {
25
        return SocialiteWasCalled::SERVICE_CONTAINER_PREFIX.$providerName;
26
    }
27
28
    /**
29
     * @param Config $config
30
     *
31
     * @return $this
32
     */
33
    public function config(Config $config)
34
    {
35
        $config = $config->get();
36
        $this->clientId = $config['client_id'];
0 ignored issues
show
Bug introduced by
The property clientId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
37
        $this->redirectUrl = $config['redirect'];
0 ignored issues
show
Bug introduced by
The property redirectUrl does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
38
        $this->clientSecret = $config['client_secret'];
0 ignored issues
show
Bug introduced by
The property clientSecret does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
39
40
        return $this;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function user()
47
    {
48
        if (!$this->hasNecessaryVerifier()) {
49
            throw new \InvalidArgumentException('Invalid request. Missing OAuth verifier.');
50
        }
51
52
        $token = $this->getToken();
53
        $tokenCredentials = $token['tokenCredentials'];
54
55
        $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...
56
57
        $user->setToken($tokenCredentials->getIdentifier(), $tokenCredentials->getSecret());
58
59
        if ($user instanceof User) {
60
            parse_str($token['credentialsResponseBody'], $credentialsResponseBody);
61
62
            if (!$credentialsResponseBody || !is_array($credentialsResponseBody)) {
63
                throw new CredentialsException('Unable to parse token credentials response.');
64
            }
65
66
            $user->setAccessTokenResponseBody($credentialsResponseBody);
67
        }
68
69
        return $user;
70
    }
71
72
    /**
73
     * Redirect the user to the authentication page for the provider.
74
     *
75
     * @return RedirectResponse
76
     */
77
    public function redirect()
78
    {
79
        if (!$this->isStateless()) {
80
            $this->request->getSession()->set(
81
                'oauth.temp', $temp = $this->server->getTemporaryCredentials()
82
            );
83
        } else {
84
            $temp = $this->server->getTemporaryCredentials();
85
            setcookie('oauth_temp', serialize($temp));
86
        }
87
88
        return new RedirectResponse($this->server->getAuthorizationUrl($temp));
89
    }
90
91
    /**
92
     * Get the token credentials for the request.
93
     *
94
     * @return \League\OAuth1\Client\Credentials\TokenCredentials
95
     */
96
    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...
97
    {
98
        if (!$this->isStateless()) {
99
            $temp = $this->request->getSession()->get('oauth.temp');
100
101
            return $this->server->getTokenCredentials(
102
                $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
103
            );
104
        } else {
105
            $temp = unserialize($_COOKIE['oauth_temp']);
106
107
            return $this->server->getTokenCredentials(
108
                $temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
109
            );
110
        }
111
    }
112
113
    /**
114
     * Indicates that the provider should operate as stateless.
115
     *
116
     * @return $this
117
     */
118
    public function stateless()
119
    {
120
        $this->stateless = true;
121
122
        return $this;
123
    }
124
125
    /**
126
     * Determine if the provider is operating as stateless.
127
     *
128
     * @return bool
129
     */
130
    protected function isStateless()
131
    {
132
        if (defined('SOCIALITEPROVIDERS_STATELESS')) {
133
            return true;
134
        }
135
136
        return $this->stateless;
137
    }
138
139
    public static function additionalConfigKeys()
140
    {
141
        return [];
142
    }
143
144
    /**
145
     * Set the scopes of the requested access.
146
     *
147
     * @param  array  $scopes
148
     * @return $this
149
     */
150
    public function scopes(array $scopes)
151
    {
152
        $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...
153
154
        return $this;
155
    }
156
157
    /**
158
     * Set the custom parameters of the request.
159
     *
160
     * @param  array  $parameters
161
     * @return $this
162
     */
163
    public function with(array $parameters)
164
    {
165
        $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...
166
167
        return $this;
168
    }
169
}
170