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 | |||
4 | namespace Ntb\RestAPI; |
||
5 | |||
6 | /** |
||
7 | * Authentication mechanism using a token in the request header and validates it on every request. |
||
8 | * |
||
9 | * The mechanism works stateless. JWT is described in RFC 7519. |
||
10 | * @author Christian Blank <[email protected]> |
||
11 | */ |
||
12 | class JwtAuth extends \SS_Object implements IAuth { |
||
13 | |||
14 | public static function authenticate($email, $password) { |
||
15 | $authenticator = \Injector::inst()->get('ApiMemberAuthenticator'); |
||
16 | View Code Duplication | if($user = $authenticator->authenticate(['Password' => $password, 'Email' => $email])) { |
|
0 ignored issues
–
show
|
|||
17 | return self::createSession($user); |
||
18 | } |
||
19 | } |
||
20 | |||
21 | /** |
||
22 | * @param Member $user |
||
23 | * @return ApiSession |
||
24 | */ |
||
25 | public static function createSession($user) { |
||
26 | // create session |
||
27 | $session = ApiSession::create(); |
||
28 | $session->User = $user; |
||
0 ignored issues
–
show
It seems like
$user of type object<Ntb\RestAPI\Member> is incompatible with the declared type object<Member> of property $User .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
29 | $session->Token = JwtAuth::generate_token($user); |
||
30 | return $session; |
||
31 | } |
||
32 | |||
33 | public static function delete($request) { |
||
34 | // nothing to do here |
||
35 | } |
||
36 | |||
37 | /** |
||
38 | * @param \SS_HTTPRequest $request |
||
39 | * @return \Member |
||
0 ignored issues
–
show
|
|||
40 | */ |
||
41 | View Code Duplication | public static function current($request) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
42 | try { |
||
43 | $token = AuthFactory::get_token($request); |
||
44 | return self::get_member_from_token($token); |
||
45 | } catch(\Exception $e) { |
||
46 | \SS_Log::log($e->getMessage(), \SS_Log::INFO); |
||
47 | } |
||
48 | return false; |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * |
||
53 | * |
||
54 | * @param string $token |
||
55 | * @throws RestUserException |
||
56 | * @return \Member |
||
0 ignored issues
–
show
|
|||
57 | */ |
||
58 | private static function get_member_from_token($token) { |
||
59 | try { |
||
60 | $data = self::jwt_decode($token, self::get_key()); |
||
61 | if($data) { |
||
0 ignored issues
–
show
The expression
$data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
62 | // todo: check expire time |
||
63 | if(time() > $data['expire']) { |
||
64 | throw new RestUserException("Session expired", 403); |
||
65 | } |
||
66 | $id = (int)$data['userId']; |
||
67 | $user = \DataObject::get(\Config::inst()->get('BaseRestController', 'Owner'))->byID($id); |
||
68 | if(!$user) { |
||
69 | throw new RestUserException("Owner not found in database", 403); |
||
70 | } |
||
71 | return $user; |
||
72 | } |
||
73 | } catch(RestUserException $e) { |
||
74 | throw $e; |
||
75 | } catch(\Exception $e) { |
||
76 | View Code Duplication | if(\Director::isDev() && $token == \Config::inst()->get('JwtAuth', 'DevToken')) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
77 | return \DataObject::get(\Config::inst()->get('BaseRestController', 'Owner'))->first(); |
||
78 | } |
||
79 | } |
||
80 | throw new RestUserException("Token invalid", 403); |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * @param Member $user |
||
85 | * @return string |
||
86 | */ |
||
87 | private static function generate_token($user) { |
||
88 | $iat = time(); |
||
89 | $data = [ |
||
90 | 'iat' => $iat, |
||
91 | 'jti' => AuthFactory::generate_token($user), |
||
92 | 'iss' => \Config::inst()->get('JwtAuth', 'Issuer'), |
||
93 | 'expire' => $iat + \Config::inst()->get('JwtAuth', 'ExpireTime'), |
||
94 | 'userId' => $user->ID |
||
95 | ]; |
||
96 | $key = self::get_key(); |
||
97 | return self::jwt_encode($data, $key); |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * @param array $data |
||
102 | * @param string $key |
||
103 | * @return string |
||
104 | */ |
||
105 | public static function jwt_encode($data, $key) { |
||
106 | $header = ['typ' => 'JWT']; |
||
107 | $headerEncoded = self::base64_url_encode(json_encode($header)); |
||
108 | $dataEncoded = self::base64_url_encode(json_encode($data)); |
||
109 | $signature = hash_hmac(\Config::inst()->get('JwtAuth', 'HashAlgorithm'), "$headerEncoded.$dataEncoded", $key); |
||
110 | return "$headerEncoded.$dataEncoded.$signature"; |
||
111 | } |
||
112 | |||
113 | private static function get_key() { |
||
114 | return \Config::inst()->get('JwtAuth', 'Key'); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * @param string $token |
||
119 | * @param string $key |
||
120 | * @return array |
||
121 | * @throws \Exception |
||
122 | */ |
||
123 | public static function jwt_decode($token, $key) { |
||
124 | $exploded = explode('.', $token); |
||
125 | if(count($exploded) < 3) { |
||
126 | throw new \Exception("No valid JWT token"); |
||
127 | } |
||
128 | list($headerEncoded, $dataEncoded, $signature) = $exploded; |
||
129 | $selfRun = hash_hmac(\Config::inst()->get('JwtAuth', 'HashAlgorithm'), "$headerEncoded.$dataEncoded", $key); |
||
130 | if($selfRun === $signature) { |
||
131 | return json_decode(self::base64_url_decode($dataEncoded), true); |
||
132 | } |
||
133 | return false; |
||
134 | } |
||
135 | |||
136 | static function base64_url_encode($data) { |
||
0 ignored issues
–
show
|
|||
137 | return rtrim(base64_encode($data), '='); |
||
138 | } |
||
139 | |||
140 | static function base64_url_decode($base64) { |
||
0 ignored issues
–
show
|
|||
141 | return base64_decode(strtr($base64, '-_', '+/')); |
||
142 | } |
||
143 | |||
144 | } |
||
145 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.