Mongo.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <?php
  2. namespace OAuth2\Storage;
  3. use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
  4. /**
  5. * Simple MongoDB storage for all storage types
  6. *
  7. * NOTE: This class is meant to get users started
  8. * quickly. If your application requires further
  9. * customization, extend this class or create your own.
  10. *
  11. * NOTE: Passwords are stored in plaintext, which is never
  12. * a good idea. Be sure to override this for your application
  13. *
  14. * @author Julien Chaumond <chaumond@gmail.com>
  15. */
  16. class Mongo implements AuthorizationCodeInterface,
  17. AccessTokenInterface,
  18. ClientCredentialsInterface,
  19. UserCredentialsInterface,
  20. RefreshTokenInterface,
  21. JwtBearerInterface,
  22. OpenIDAuthorizationCodeInterface
  23. {
  24. protected $db;
  25. protected $config;
  26. public function __construct($connection, $config = array())
  27. {
  28. if ($connection instanceof \MongoDB) {
  29. $this->db = $connection;
  30. } else {
  31. if (!is_array($connection)) {
  32. throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB or a configuration array');
  33. }
  34. $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']);
  35. $m = new \MongoClient($server);
  36. $this->db = $m->{$connection['database']};
  37. }
  38. $this->config = array_merge(array(
  39. 'client_table' => 'oauth_clients',
  40. 'access_token_table' => 'oauth_access_tokens',
  41. 'refresh_token_table' => 'oauth_refresh_tokens',
  42. 'code_table' => 'oauth_authorization_codes',
  43. 'user_table' => 'oauth_users',
  44. 'jwt_table' => 'oauth_jwt',
  45. ), $config);
  46. }
  47. // Helper function to access a MongoDB collection by `type`:
  48. protected function collection($name)
  49. {
  50. return $this->db->{$this->config[$name]};
  51. }
  52. /* ClientCredentialsInterface */
  53. public function checkClientCredentials($client_id, $client_secret = null)
  54. {
  55. if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) {
  56. return $result['client_secret'] == $client_secret;
  57. }
  58. return false;
  59. }
  60. public function isPublicClient($client_id)
  61. {
  62. if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) {
  63. return false;
  64. }
  65. return empty($result['client_secret']);
  66. }
  67. /* ClientInterface */
  68. public function getClientDetails($client_id)
  69. {
  70. $result = $this->collection('client_table')->findOne(array('client_id' => $client_id));
  71. return is_null($result) ? false : $result;
  72. }
  73. public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
  74. {
  75. if ($this->getClientDetails($client_id)) {
  76. $this->collection('client_table')->update(
  77. array('client_id' => $client_id),
  78. array('$set' => array(
  79. 'client_secret' => $client_secret,
  80. 'redirect_uri' => $redirect_uri,
  81. 'grant_types' => $grant_types,
  82. 'scope' => $scope,
  83. 'user_id' => $user_id,
  84. ))
  85. );
  86. } else {
  87. $client = array(
  88. 'client_id' => $client_id,
  89. 'client_secret' => $client_secret,
  90. 'redirect_uri' => $redirect_uri,
  91. 'grant_types' => $grant_types,
  92. 'scope' => $scope,
  93. 'user_id' => $user_id,
  94. );
  95. $this->collection('client_table')->insert($client);
  96. }
  97. return true;
  98. }
  99. public function checkRestrictedGrantType($client_id, $grant_type)
  100. {
  101. $details = $this->getClientDetails($client_id);
  102. if (isset($details['grant_types'])) {
  103. $grant_types = explode(' ', $details['grant_types']);
  104. return in_array($grant_type, $grant_types);
  105. }
  106. // if grant_types are not defined, then none are restricted
  107. return true;
  108. }
  109. /* AccessTokenInterface */
  110. public function getAccessToken($access_token)
  111. {
  112. $token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token));
  113. return is_null($token) ? false : $token;
  114. }
  115. public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
  116. {
  117. // if it exists, update it.
  118. if ($this->getAccessToken($access_token)) {
  119. $this->collection('access_token_table')->update(
  120. array('access_token' => $access_token),
  121. array('$set' => array(
  122. 'client_id' => $client_id,
  123. 'expires' => $expires,
  124. 'user_id' => $user_id,
  125. 'scope' => $scope
  126. ))
  127. );
  128. } else {
  129. $token = array(
  130. 'access_token' => $access_token,
  131. 'client_id' => $client_id,
  132. 'expires' => $expires,
  133. 'user_id' => $user_id,
  134. 'scope' => $scope
  135. );
  136. $this->collection('access_token_table')->insert($token);
  137. }
  138. return true;
  139. }
  140. public function unsetAccessToken($access_token)
  141. {
  142. $this->collection('access_token_table')->remove(array('access_token' => $access_token));
  143. }
  144. /* AuthorizationCodeInterface */
  145. public function getAuthorizationCode($code)
  146. {
  147. $code = $this->collection('code_table')->findOne(array('authorization_code' => $code));
  148. return is_null($code) ? false : $code;
  149. }
  150. public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
  151. {
  152. // if it exists, update it.
  153. if ($this->getAuthorizationCode($code)) {
  154. $this->collection('code_table')->update(
  155. array('authorization_code' => $code),
  156. array('$set' => array(
  157. 'client_id' => $client_id,
  158. 'user_id' => $user_id,
  159. 'redirect_uri' => $redirect_uri,
  160. 'expires' => $expires,
  161. 'scope' => $scope,
  162. 'id_token' => $id_token,
  163. ))
  164. );
  165. } else {
  166. $token = array(
  167. 'authorization_code' => $code,
  168. 'client_id' => $client_id,
  169. 'user_id' => $user_id,
  170. 'redirect_uri' => $redirect_uri,
  171. 'expires' => $expires,
  172. 'scope' => $scope,
  173. 'id_token' => $id_token,
  174. );
  175. $this->collection('code_table')->insert($token);
  176. }
  177. return true;
  178. }
  179. public function expireAuthorizationCode($code)
  180. {
  181. $this->collection('code_table')->remove(array('authorization_code' => $code));
  182. return true;
  183. }
  184. /* UserCredentialsInterface */
  185. public function checkUserCredentials($username, $password)
  186. {
  187. if ($user = $this->getUser($username)) {
  188. return $this->checkPassword($user, $password);
  189. }
  190. return false;
  191. }
  192. public function getUserDetails($username)
  193. {
  194. if ($user = $this->getUser($username)) {
  195. $user['user_id'] = $user['username'];
  196. }
  197. return $user;
  198. }
  199. /* RefreshTokenInterface */
  200. public function getRefreshToken($refresh_token)
  201. {
  202. $token = $this->collection('refresh_token_table')->findOne(array('refresh_token' => $refresh_token));
  203. return is_null($token) ? false : $token;
  204. }
  205. public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
  206. {
  207. $token = array(
  208. 'refresh_token' => $refresh_token,
  209. 'client_id' => $client_id,
  210. 'user_id' => $user_id,
  211. 'expires' => $expires,
  212. 'scope' => $scope
  213. );
  214. $this->collection('refresh_token_table')->insert($token);
  215. return true;
  216. }
  217. public function unsetRefreshToken($refresh_token)
  218. {
  219. $this->collection('refresh_token_table')->remove(array('refresh_token' => $refresh_token));
  220. return true;
  221. }
  222. // plaintext passwords are bad! Override this for your application
  223. protected function checkPassword($user, $password)
  224. {
  225. return $user['password'] == $password;
  226. }
  227. public function getUser($username)
  228. {
  229. $result = $this->collection('user_table')->findOne(array('username' => $username));
  230. return is_null($result) ? false : $result;
  231. }
  232. public function setUser($username, $password, $firstName = null, $lastName = null)
  233. {
  234. if ($this->getUser($username)) {
  235. $this->collection('user_table')->update(
  236. array('username' => $username),
  237. array('$set' => array(
  238. 'password' => $password,
  239. 'first_name' => $firstName,
  240. 'last_name' => $lastName
  241. ))
  242. );
  243. } else {
  244. $user = array(
  245. 'username' => $username,
  246. 'password' => $password,
  247. 'first_name' => $firstName,
  248. 'last_name' => $lastName
  249. );
  250. $this->collection('user_table')->insert($user);
  251. }
  252. return true;
  253. }
  254. public function getClientKey($client_id, $subject)
  255. {
  256. $result = $this->collection('jwt_table')->findOne(array(
  257. 'client_id' => $client_id,
  258. 'subject' => $subject
  259. ));
  260. return is_null($result) ? false : $result['key'];
  261. }
  262. public function getClientScope($client_id)
  263. {
  264. if (!$clientDetails = $this->getClientDetails($client_id)) {
  265. return false;
  266. }
  267. if (isset($clientDetails['scope'])) {
  268. return $clientDetails['scope'];
  269. }
  270. return null;
  271. }
  272. public function getJti($client_id, $subject, $audience, $expiration, $jti)
  273. {
  274. //TODO: Needs mongodb implementation.
  275. throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.');
  276. }
  277. public function setJti($client_id, $subject, $audience, $expiration, $jti)
  278. {
  279. //TODO: Needs mongodb implementation.
  280. throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.');
  281. }
  282. }