thephpleague /
oauth2-linkedin
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace League\OAuth2\Client\Provider; |
||
| 4 | |||
| 5 | use Exception; |
||
| 6 | use InvalidArgumentException; |
||
| 7 | use League\OAuth2\Client\Grant\AbstractGrant; |
||
| 8 | use League\OAuth2\Client\Provider\Exception\IdentityProviderException; |
||
| 9 | use League\OAuth2\Client\Provider\Exception\LinkedInAccessDeniedException; |
||
| 10 | use League\OAuth2\Client\Token\AccessToken; |
||
| 11 | use League\OAuth2\Client\Token\LinkedInAccessToken; |
||
| 12 | use League\OAuth2\Client\Tool\BearerAuthorizationTrait; |
||
| 13 | use Psr\Http\Message\ResponseInterface; |
||
| 14 | |||
| 15 | class LinkedIn extends AbstractProvider |
||
| 16 | { |
||
| 17 | use BearerAuthorizationTrait; |
||
| 18 | |||
| 19 | /** |
||
| 20 | * Default scopes |
||
| 21 | * |
||
| 22 | * @var array |
||
| 23 | */ |
||
| 24 | public $defaultScopes = ['r_liteprofile', 'r_emailaddress']; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * Requested fields in scope, seeded with default values |
||
| 28 | * |
||
| 29 | * @var array |
||
| 30 | * @see https://developer.linkedin.com/docs/fields/basic-profile |
||
| 31 | */ |
||
| 32 | protected $fields = [ |
||
| 33 | 'id', 'firstName', 'lastName', 'localizedFirstName', 'localizedLastName', |
||
| 34 | 'profilePicture(displayImage~:playableStreams)', |
||
| 35 | ]; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Constructs an OAuth 2.0 service provider. |
||
| 39 | * |
||
| 40 | * @param array $options An array of options to set on this provider. |
||
| 41 | * Options include `clientId`, `clientSecret`, `redirectUri`, and `state`. |
||
| 42 | * Individual providers may introduce more options, as needed. |
||
| 43 | * @param array $collaborators An array of collaborators that may be used to |
||
| 44 | * override this provider's default behavior. Collaborators include |
||
| 45 | * `grantFactory`, `requestFactory`, and `httpClient`. |
||
| 46 | * Individual providers may introduce more collaborators, as needed. |
||
| 47 | */ |
||
| 48 | 17 | public function __construct(array $options = [], array $collaborators = []) |
|
| 49 | { |
||
| 50 | 17 | if (isset($options['fields']) && !is_array($options['fields'])) { |
|
| 51 | 1 | throw new InvalidArgumentException('The fields option must be an array'); |
|
| 52 | } |
||
| 53 | |||
| 54 | 17 | parent::__construct($options, $collaborators); |
|
| 55 | 17 | } |
|
| 56 | |||
| 57 | |||
| 58 | /** |
||
| 59 | * Creates an access token from a response. |
||
| 60 | * |
||
| 61 | * The grant that was used to fetch the response can be used to provide |
||
| 62 | * additional context. |
||
| 63 | * |
||
| 64 | * @param array $response |
||
| 65 | * @param AbstractGrant $grant |
||
| 66 | * @return AccessTokenInterface |
||
| 67 | */ |
||
| 68 | 7 | protected function createAccessToken(array $response, AbstractGrant $grant) |
|
| 69 | { |
||
| 70 | 7 | return new LinkedInAccessToken($response); |
|
| 71 | } |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Get the string used to separate scopes. |
||
| 75 | * |
||
| 76 | * @return string |
||
| 77 | */ |
||
| 78 | 3 | protected function getScopeSeparator() |
|
| 79 | { |
||
| 80 | 3 | return ' '; |
|
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Get authorization url to begin OAuth flow |
||
| 85 | * |
||
| 86 | * @return string |
||
| 87 | */ |
||
| 88 | 3 | public function getBaseAuthorizationUrl() |
|
| 89 | { |
||
| 90 | 3 | return 'https://www.linkedin.com/oauth/v2/authorization'; |
|
| 91 | } |
||
| 92 | |||
| 93 | /** |
||
| 94 | * Get access token url to retrieve token |
||
| 95 | * |
||
| 96 | * @return string |
||
| 97 | */ |
||
| 98 | 10 | public function getBaseAccessTokenUrl(array $params) |
|
| 99 | { |
||
| 100 | 10 | return 'https://www.linkedin.com/oauth/v2/accessToken'; |
|
| 101 | } |
||
| 102 | |||
| 103 | /** |
||
| 104 | * Get provider url to fetch user details |
||
| 105 | * |
||
| 106 | * @param AccessToken $token |
||
| 107 | * |
||
| 108 | * @return string |
||
| 109 | */ |
||
| 110 | 4 | public function getResourceOwnerDetailsUrl(AccessToken $token) |
|
| 111 | { |
||
| 112 | 4 | $query = http_build_query([ |
|
| 113 | 4 | 'projection' => '(' . implode(',', $this->fields) . ')' |
|
| 114 | ]); |
||
| 115 | |||
| 116 | 4 | return 'https://api.linkedin.com/v2/me?' . urldecode($query); |
|
| 117 | } |
||
| 118 | |||
| 119 | /** |
||
| 120 | * Get provider url to fetch user details |
||
| 121 | * |
||
| 122 | * @param AccessToken $token |
||
| 123 | * |
||
| 124 | * @return string |
||
| 125 | */ |
||
| 126 | 7 | public function getResourceOwnerEmailUrl(AccessToken $token) |
|
|
0 ignored issues
–
show
|
|||
| 127 | { |
||
| 128 | 7 | $query = http_build_query([ |
|
| 129 | 7 | 'q' => 'members', |
|
| 130 | 'projection' => '(elements*(state,primary,type,handle~))' |
||
| 131 | ]); |
||
| 132 | |||
| 133 | 7 | return 'https://api.linkedin.com/v2/clientAwareMemberHandles?' . urldecode($query); |
|
| 134 | } |
||
| 135 | |||
| 136 | /** |
||
| 137 | * Get the default scopes used by this provider. |
||
| 138 | * |
||
| 139 | * This should not be a complete list of all scopes, but the minimum |
||
| 140 | * required for the provider user interface! |
||
| 141 | * |
||
| 142 | * @return array |
||
| 143 | */ |
||
| 144 | 2 | protected function getDefaultScopes() |
|
| 145 | { |
||
| 146 | 2 | return $this->defaultScopes; |
|
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Check a provider response for errors. |
||
| 151 | * |
||
| 152 | * @param ResponseInterface $response |
||
| 153 | * @param array $data Parsed response data |
||
| 154 | * @return void |
||
| 155 | * @throws IdentityProviderException |
||
| 156 | * @see https://developer.linkedin.com/docs/guide/v2/error-handling |
||
| 157 | */ |
||
| 158 | 9 | protected function checkResponse(ResponseInterface $response, $data) |
|
| 159 | { |
||
| 160 | 9 | $this->checkResponseUnauthorized($response, $data); |
|
| 161 | |||
| 162 | 9 | if ($response->getStatusCode() >= 400) { |
|
| 163 | 2 | throw new IdentityProviderException( |
|
| 164 | 2 | isset($data['message']) ? $data['message'] : $response->getReasonPhrase(), |
|
| 165 | 2 | isset($data['status']) ? $data['status'] : $response->getStatusCode(), |
|
| 166 | 2 | $response |
|
|
0 ignored issues
–
show
$response is of type object<Psr\Http\Message\ResponseInterface>, but the function expects a array|string.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 167 | ); |
||
| 168 | } |
||
| 169 | 7 | } |
|
| 170 | |||
| 171 | /** |
||
| 172 | * Check a provider response for unauthorized errors. |
||
| 173 | * |
||
| 174 | * @param ResponseInterface $response |
||
| 175 | * @param array $data Parsed response data |
||
| 176 | * @return void |
||
| 177 | * @throws LinkedInAccessDeniedException |
||
| 178 | * @see https://developer.linkedin.com/docs/guide/v2/error-handling |
||
| 179 | */ |
||
| 180 | 9 | protected function checkResponseUnauthorized(ResponseInterface $response, $data) |
|
| 181 | { |
||
| 182 | 9 | if (isset($data['status']) && $data['status'] === 403) { |
|
| 183 | 2 | throw new LinkedInAccessDeniedException( |
|
| 184 | 2 | isset($data['message']) ? $data['message'] : $response->getReasonPhrase(), |
|
| 185 | 2 | isset($data['status']) ? $data['status'] : $response->getStatusCode(), |
|
| 186 | 2 | $response |
|
|
0 ignored issues
–
show
$response is of type object<Psr\Http\Message\ResponseInterface>, but the function expects a array|string.
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
| 187 | ); |
||
| 188 | } |
||
| 189 | 9 | } |
|
| 190 | |||
| 191 | /** |
||
| 192 | * Generate a user object from a successful user details request. |
||
| 193 | * |
||
| 194 | * @param array $response |
||
| 195 | * @param AccessToken $token |
||
| 196 | * @return LinkedInResourceOwner |
||
| 197 | */ |
||
| 198 | 3 | protected function createResourceOwner(array $response, AccessToken $token) |
|
| 199 | { |
||
| 200 | // If current accessToken is not authorized with r_emailaddress scope, |
||
| 201 | // getResourceOwnerEmail will throw LinkedInAccessDeniedException, it will be caught here, |
||
| 202 | // and then the email will be set to null |
||
| 203 | // When email is not available due to chosen scopes, other providers simply set it to null, let's do the same. |
||
| 204 | try { |
||
| 205 | 3 | $email = $this->getResourceOwnerEmail($token); |
|
| 206 | 1 | } catch (LinkedInAccessDeniedException $exception) { |
|
| 207 | 1 | $email = null; |
|
| 208 | } |
||
| 209 | 3 | $response['email'] = $email; |
|
| 210 | 3 | return new LinkedInResourceOwner($response); |
|
| 211 | } |
||
| 212 | |||
| 213 | /** |
||
| 214 | * Returns the requested fields in scope. |
||
| 215 | * |
||
| 216 | * @return array |
||
| 217 | */ |
||
| 218 | 3 | public function getFields() |
|
| 219 | { |
||
| 220 | 3 | return $this->fields; |
|
| 221 | } |
||
| 222 | |||
| 223 | /** |
||
| 224 | * Attempts to fetch resource owner's email address via separate API request. |
||
| 225 | * |
||
| 226 | * @param AccessToken $token [description] |
||
| 227 | * @return string|null |
||
| 228 | * @throws IdentityProviderException |
||
| 229 | */ |
||
| 230 | 6 | public function getResourceOwnerEmail(AccessToken $token) |
|
| 231 | { |
||
| 232 | 6 | $emailUrl = $this->getResourceOwnerEmailUrl($token); |
|
| 233 | 6 | $emailRequest = $this->getAuthenticatedRequest(self::METHOD_GET, $emailUrl, $token); |
|
| 234 | 6 | $emailResponse = $this->getParsedResponse($emailRequest); |
|
| 235 | |||
| 236 | 4 | return $this->extractEmailFromResponse($emailResponse); |
|
|
0 ignored issues
–
show
It seems like
$emailResponse defined by $this->getParsedResponse($emailRequest) on line 234 can also be of type null or string; however, League\OAuth2\Client\Pro...ractEmailFromResponse() does only seem to accept array, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 237 | } |
||
| 238 | |||
| 239 | /** |
||
| 240 | * Updates the requested fields in scope. |
||
| 241 | * |
||
| 242 | * @param array $fields |
||
| 243 | * |
||
| 244 | * @return LinkedIn |
||
| 245 | */ |
||
| 246 | 1 | public function withFields(array $fields) |
|
| 247 | { |
||
| 248 | 1 | $this->fields = $fields; |
|
| 249 | |||
| 250 | 1 | return $this; |
|
| 251 | } |
||
| 252 | |||
| 253 | /** |
||
| 254 | * Attempts to extract the email address from a valid email api response. |
||
| 255 | * |
||
| 256 | * @param array $response |
||
| 257 | * @return string|null |
||
| 258 | */ |
||
| 259 | protected function extractEmailFromResponse($response = []) |
||
| 260 | { |
||
| 261 | try { |
||
| 262 | 4 | $confirmedEmails = array_filter($response['elements'], function ($element) { |
|
| 263 | return |
||
| 264 | 3 | strtoupper($element['type']) === 'EMAIL' |
|
| 265 | 3 | && strtoupper($element['state']) === 'CONFIRMED' |
|
| 266 | 3 | && $element['primary'] === true |
|
| 267 | 3 | && isset($element['handle~']['emailAddress']) |
|
| 268 | ; |
||
| 269 | 4 | }); |
|
| 270 | |||
| 271 | 3 | return $confirmedEmails[0]['handle~']['emailAddress']; |
|
| 272 | 1 | } catch (Exception $e) { |
|
| 273 | 1 | return null; |
|
| 274 | } |
||
| 275 | } |
||
| 276 | } |
||
| 277 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.