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 Borfast\Socializr\Connectors; |
||
4 | |||
5 | use OAuth\Common\Token\Exception\ExpiredTokenException as OauthExpiredTokenException; |
||
6 | use OAuth\Common\Storage\Exception\TokenNotFoundException; |
||
7 | use OAuth\Common\Service\ServiceInterface; |
||
8 | use Borfast\Socializr\Post; |
||
9 | use Borfast\Socializr\Exceptions\CSRFException; |
||
10 | use Borfast\Socializr\Exceptions\ExpiredTokenException; |
||
11 | use Borfast\Socializr\Exceptions\AuthorizationException; |
||
12 | |||
13 | abstract class AbstractConnector implements ConnectorInterface |
||
14 | { |
||
15 | protected static $provider; |
||
16 | protected $service; |
||
17 | protected $id; |
||
18 | protected $config = []; |
||
19 | protected $options; |
||
20 | |||
21 | /** |
||
22 | * @param array $config |
||
23 | * @param ServiceInterface $service |
||
24 | * @param array $options |
||
25 | * @param $id |
||
26 | */ |
||
27 | public function __construct(array $config, ServiceInterface $service, array $options, $id) |
||
28 | { |
||
29 | $this->config = $config; |
||
30 | $this->service = $service; |
||
31 | $this->options = $options; |
||
32 | $this->id = $id; |
||
33 | static::$provider = $service->service(); |
||
34 | } |
||
35 | |||
36 | |||
37 | public function request($path, $method = 'GET', $params = [], $headers = []) |
||
38 | { |
||
39 | if (empty($params)) { |
||
40 | $params = null; |
||
41 | } |
||
42 | |||
43 | try { |
||
44 | $result = $this->service->request($path, $method, $params, $headers); |
||
45 | } catch (OauthExpiredTokenException $e) { |
||
46 | throw new ExpiredTokenException(); |
||
47 | } catch (TokenNotFoundException $e) { |
||
48 | throw new AuthorizationException(); |
||
49 | } |
||
50 | |||
51 | return $result; |
||
52 | } |
||
53 | |||
54 | |||
55 | /** |
||
56 | * The method that initiates the provider authentication process. |
||
57 | * It returns the provider's authentication/login page, which in turn |
||
58 | * will redirect back to us. We don't do the redirect ourselves because that |
||
59 | * means changing the application workflow and we don't want to get in the |
||
60 | * way of how people do things. |
||
61 | * |
||
62 | * @todo Use pluggable\swappable CSRF token storage. |
||
63 | */ |
||
64 | public function getAuthorizationUri(array $params = []) |
||
0 ignored issues
–
show
|
|||
65 | { |
||
66 | // Check if this provider uses an CSRF token at all. |
||
67 | if (!empty($this->config['csrf_token_name'])) { |
||
68 | // Generate a random anti-CSRF token. |
||
69 | $csrf_token = base64_encode(openssl_random_pseudo_bytes(32)); |
||
70 | |||
71 | // Write our token in session so we can check it after auth. |
||
72 | // // TODO: This could be improved and make the session storage |
||
73 | // pluggable. Is it worth the trouble, though? |
||
74 | session_start(); |
||
75 | $_SESSION['socializr_csrf_token'] = $csrf_token; |
||
76 | session_write_close(); |
||
77 | |||
78 | // Add the CSRF token to the request. |
||
79 | $csrf_token_name = $this->config['csrf_token_name']; |
||
80 | $params = array_merge($params, [$csrf_token_name => $csrf_token]); |
||
81 | } |
||
82 | |||
83 | $url = $this->service->getAuthorizationUri($params); |
||
84 | return $url; |
||
85 | } |
||
86 | |||
87 | |||
88 | /** |
||
89 | * For when the OAuth token expires and we need to refresh it. |
||
90 | */ |
||
91 | public function refreshAccessToken() |
||
92 | { |
||
93 | try { |
||
94 | $token = $this->service->getStorage()->retrieveAccessToken(static::$provider); |
||
95 | } catch (TokenNotFoundException $e) { |
||
96 | throw new AuthorizationException(); |
||
97 | } |
||
98 | $this->service->refreshAccessToken($token); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
OAuth\Common\Service\ServiceInterface as the method refreshAccessToken() does only exist in the following implementations of said interface: OAuthTest\Mocks\OAuth2\Service\Fake , OAuthTest\Mocks\OAuth2\Service\Mock , OAuth\OAuth2\Service\AbstractService , OAuth\OAuth2\Service\Amazon , OAuth\OAuth2\Service\Bitly , OAuth\OAuth2\Service\Box , OAuth\OAuth2\Service\Buffer , OAuth\OAuth2\Service\Dailymotion , OAuth\OAuth2\Service\Dropbox , OAuth\OAuth2\Service\Facebook , OAuth\OAuth2\Service\Foursquare , OAuth\OAuth2\Service\GitHub , OAuth\OAuth2\Service\Google , OAuth\OAuth2\Service\Harvest , OAuth\OAuth2\Service\Heroku , OAuth\OAuth2\Service\Instagram , OAuth\OAuth2\Service\JawboneUP , OAuth\OAuth2\Service\Linkedin , OAuth\OAuth2\Service\Mailchimp , OAuth\OAuth2\Service\Microsoft , OAuth\OAuth2\Service\Paypal , OAuth\OAuth2\Service\Pocket , OAuth\OAuth2\Service\Reddit , OAuth\OAuth2\Service\RunKeeper , OAuth\OAuth2\Service\SalesforceService , OAuth\OAuth2\Service\SoundCloud , OAuth\OAuth2\Service\Spotify , OAuth\OAuth2\Service\Ustream , OAuth\OAuth2\Service\Vkontakte , OAuth\OAuth2\Service\Yammer .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements 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 implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
99 | } |
||
100 | |||
101 | |||
102 | /** |
||
103 | * Check that the CSRF token |
||
104 | */ |
||
105 | public function checkCsrf(array $get) |
||
0 ignored issues
–
show
checkCsrf uses the super-global variable $_SESSION 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...
|
|||
106 | { |
||
107 | // Check if this provider uses an CSRF token at all. |
||
108 | if (!empty($this->config['csrf_token_name'])) { |
||
109 | |||
110 | session_start(); |
||
111 | |||
112 | // If we don't have a token and should have one, crash and burn. |
||
113 | if (!isset($_SESSION['socializr_csrf_token'])) { |
||
114 | throw new CSRFException('No CSRF token stored. Possible CSRF attack.', 1); |
||
115 | } |
||
116 | |||
117 | $stored_token = $_SESSION['socializr_csrf_token']; |
||
118 | session_write_close(); |
||
119 | |||
120 | // Now get the token from the URL |
||
121 | $csrf_token_name = $this->config['csrf_token_name']; |
||
122 | $received_token = $get[$csrf_token_name]; |
||
123 | |||
124 | // Finally check that the stored token and the received token match. |
||
125 | if (strcmp($stored_token, $received_token) != 0) { |
||
126 | throw new CSRFException('Verification code mismatch. Possible CSRF attack.', 1); |
||
127 | } |
||
128 | } |
||
129 | } |
||
130 | |||
131 | |||
132 | public function getSessionData() |
||
133 | { |
||
134 | try { |
||
135 | return $this->service->getStorage()->retrieveAccessToken(static::$provider)->getAccessToken(); |
||
136 | } catch (TokenNotFoundException $e) { |
||
137 | throw new AuthorizationException(); |
||
138 | } |
||
139 | } |
||
140 | |||
141 | |||
142 | public function get($path, $params = []) |
||
143 | { |
||
144 | $response = json_decode( |
||
145 | $this->service->request($path, 'GET', $params), |
||
146 | true |
||
147 | ); |
||
148 | |||
149 | return $response; |
||
150 | } |
||
151 | |||
152 | |||
153 | /** |
||
154 | * The method that sets the OAuth token for the current provider. It must be |
||
155 | * called after the authorize() method. Retrieves the auth token from the |
||
156 | * provider's response and store it. |
||
157 | * |
||
158 | * @params array $params The URL params. Each Connector knows how to get the |
||
159 | * token for its specific provider. |
||
160 | */ |
||
161 | public function storeOauthToken($params) |
||
162 | { |
||
163 | $this->service->requestAccessToken($params['code']); |
||
164 | } |
||
165 | |||
166 | |||
167 | public function getUid() |
||
168 | { |
||
169 | if (is_null($this->id)) { |
||
170 | $profile = $this->getProfile(); |
||
171 | $this->id = $profile->id; |
||
172 | } |
||
173 | |||
174 | return $this->id; |
||
175 | } |
||
176 | |||
177 | |||
178 | // These should be implementation-specific. |
||
179 | public function getProfile() |
||
180 | { |
||
181 | throw new \Exception('Trying to get a Profile from a generic provider. This probably means you are trying to get a type of data that does not make sense for the connector you are using. For example, trying to get a Facebook Profile from a FacebookPage connector.'); |
||
182 | } |
||
183 | |||
184 | public function getPage() |
||
185 | { |
||
186 | throw new \Exception('Trying to get a Page from a generic provider. This probably means you are trying to get a type of data that does not make sense for the connector you are using. For example, trying to get a Facebook Page from a FacebookGroup connector.'); |
||
187 | } |
||
188 | |||
189 | public function getPages() |
||
190 | { |
||
191 | throw new \Exception('Trying to get Pages from a generic provider. This probably means you are trying to get a type of data that does not make sense for the connector you are using.'); |
||
192 | } |
||
193 | |||
194 | public function getGroup() |
||
195 | { |
||
196 | throw new \Exception('Trying to get a Group from a generic provider. This probably means you are trying to get a type of data that does not make sense for the connector you are using. For example, trying to get a Facebook Group from a FacebookPage connector.'); |
||
197 | } |
||
198 | |||
199 | public function getGroups() |
||
200 | { |
||
201 | throw new \Exception('Trying to get Groups from a generic provider. This probably means you are trying to get a type of data that does not make sense for the connector you are using.'); |
||
202 | } |
||
203 | |||
204 | abstract public function post(Post $post); |
||
205 | abstract public function getStats(); |
||
206 | } |
||
207 |
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: