*/ class MongoDB implements AuthorizationCodeInterface, UserCredentialsInterface, AccessTokenInterface, ClientCredentialsInterface, RefreshTokenInterface, JwtBearerInterface, PublicKeyInterface, OpenIDAuthorizationCodeInterface { protected $db; protected $config; public function __construct($connection, $config = array()) { if ($connection instanceof Database) { $this->db = $connection; } else { if (!is_array($connection)) { throw new \InvalidArgumentException('First argument to OAuth2\Storage\Mongo must be an instance of MongoDB\Database or a configuration array'); } $server = sprintf('mongodb://%s:%d', $connection['host'], $connection['port']); $m = new Client($server); $this->db = $m->selectDatabase($connection['database']); } $this->config = array_merge(array( 'client_table' => 'oauth_clients', 'access_token_table' => 'oauth_access_tokens', 'refresh_token_table' => 'oauth_refresh_tokens', 'code_table' => 'oauth_authorization_codes', 'user_table' => 'oauth_users', 'jwt_table' => 'oauth_jwt', 'jti_table' => 'oauth_jti', 'scope_table' => 'oauth_scopes', 'key_table' => 'oauth_keys', ), $config); } /* ClientCredentialsInterface */ public function checkClientCredentials($client_id, $client_secret = null) { if ($result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { return $result['client_secret'] == $client_secret; } return false; } public function isPublicClient($client_id) { if (!$result = $this->collection('client_table')->findOne(array('client_id' => $client_id))) { return false; } return empty($result['client_secret']); } /* ClientInterface */ public function getClientDetails($client_id) { $result = $this->collection('client_table')->findOne(array('client_id' => $client_id)); return is_null($result) ? false : $result; } public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) { if ($this->getClientDetails($client_id)) { $result = $this->collection('client_table')->updateOne( array('client_id' => $client_id), array('$set' => array( 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri, 'grant_types' => $grant_types, 'scope' => $scope, 'user_id' => $user_id, )) ); return $result->getMatchedCount() > 0; } $client = array( 'client_id' => $client_id, 'client_secret' => $client_secret, 'redirect_uri' => $redirect_uri, 'grant_types' => $grant_types, 'scope' => $scope, 'user_id' => $user_id, ); $result = $this->collection('client_table')->insertOne($client); return $result->getInsertedCount() > 0; } public function checkRestrictedGrantType($client_id, $grant_type) { $details = $this->getClientDetails($client_id); if (isset($details['grant_types'])) { $grant_types = explode(' ', $details['grant_types']); return in_array($grant_type, $grant_types); } // if grant_types are not defined, then none are restricted return true; } /* AccessTokenInterface */ public function getAccessToken($access_token) { $token = $this->collection('access_token_table')->findOne(array('access_token' => $access_token)); return is_null($token) ? false : $token; } public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) { // if it exists, update it. if ($this->getAccessToken($access_token)) { $result = $this->collection('access_token_table')->updateOne( array('access_token' => $access_token), array('$set' => array( 'client_id' => $client_id, 'expires' => $expires, 'user_id' => $user_id, 'scope' => $scope )) ); return $result->getMatchedCount() > 0; } $token = array( 'access_token' => $access_token, 'client_id' => $client_id, 'expires' => $expires, 'user_id' => $user_id, 'scope' => $scope ); $result = $this->collection('access_token_table')->insertOne($token); return $result->getInsertedCount() > 0; } public function unsetAccessToken($access_token) { $result = $this->collection('access_token_table')->deleteOne(array( 'access_token' => $access_token )); return $result->getDeletedCount() > 0; } /* AuthorizationCodeInterface */ public function getAuthorizationCode($code) { $code = $this->collection('code_table')->findOne(array( 'authorization_code' => $code )); return is_null($code) ? false : $code; } public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) { // if it exists, update it. if ($this->getAuthorizationCode($code)) { $result = $this->collection('code_table')->updateOne( array('authorization_code' => $code), array('$set' => array( 'client_id' => $client_id, 'user_id' => $user_id, 'redirect_uri' => $redirect_uri, 'expires' => $expires, 'scope' => $scope, 'id_token' => $id_token, )) ); return $result->getMatchedCount() > 0; } $token = array( 'authorization_code' => $code, 'client_id' => $client_id, 'user_id' => $user_id, 'redirect_uri' => $redirect_uri, 'expires' => $expires, 'scope' => $scope, 'id_token' => $id_token, ); $result = $this->collection('code_table')->insertOne($token); return $result->getInsertedCount() > 0; } public function expireAuthorizationCode($code) { $result = $this->collection('code_table')->deleteOne(array( 'authorization_code' => $code )); return $result->getDeletedCount() > 0; } /* UserCredentialsInterface */ public function checkUserCredentials($username, $password) { if ($user = $this->getUser($username)) { return $this->checkPassword($user, $password); } return false; } public function getUserDetails($username) { if ($user = $this->getUser($username)) { $user['user_id'] = $user['username']; } return $user; } /* RefreshTokenInterface */ public function getRefreshToken($refresh_token) { $token = $this->collection('refresh_token_table')->findOne(array( 'refresh_token' => $refresh_token )); return is_null($token) ? false : $token; } public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) { $token = array( 'refresh_token' => $refresh_token, 'client_id' => $client_id, 'user_id' => $user_id, 'expires' => $expires, 'scope' => $scope ); $result = $this->collection('refresh_token_table')->insertOne($token); return $result->getInsertedCount() > 0; } public function unsetRefreshToken($refresh_token) { $result = $this->collection('refresh_token_table')->deleteOne(array( 'refresh_token' => $refresh_token )); return $result->getDeletedCount() > 0; } // plaintext passwords are bad! Override this for your application protected function checkPassword($user, $password) { return $user['password'] == $password; } public function getUser($username) { $result = $this->collection('user_table')->findOne(array('username' => $username)); return is_null($result) ? false : $result; } public function setUser($username, $password, $firstName = null, $lastName = null) { if ($this->getUser($username)) { $result = $this->collection('user_table')->updateOne( array('username' => $username), array('$set' => array( 'password' => $password, 'first_name' => $firstName, 'last_name' => $lastName )) ); return $result->getMatchedCount() > 0; } $user = array( 'username' => $username, 'password' => $password, 'first_name' => $firstName, 'last_name' => $lastName ); $result = $this->collection('user_table')->insertOne($user); return $result->getInsertedCount() > 0; } public function getClientKey($client_id, $subject) { $result = $this->collection('jwt_table')->findOne(array( 'client_id' => $client_id, 'subject' => $subject )); return is_null($result) ? false : $result['key']; } public function getClientScope($client_id) { if (!$clientDetails = $this->getClientDetails($client_id)) { return false; } if (isset($clientDetails['scope'])) { return $clientDetails['scope']; } return null; } public function getJti($client_id, $subject, $audience, $expires, $jti) { //TODO: Needs mongodb implementation. throw new \Exception('getJti() for the MongoDB driver is currently unimplemented.'); } public function setJti($client_id, $subject, $audience, $expires, $jti) { //TODO: Needs mongodb implementation. throw new \Exception('setJti() for the MongoDB driver is currently unimplemented.'); } public function getPublicKey($client_id = null) { if ($client_id) { $result = $this->collection('key_table')->findOne(array( 'client_id' => $client_id )); if ($result) { return $result['public_key']; } } $result = $this->collection('key_table')->findOne(array( 'client_id' => null )); return is_null($result) ? false : $result['public_key']; } public function getPrivateKey($client_id = null) { if ($client_id) { $result = $this->collection('key_table')->findOne(array( 'client_id' => $client_id )); if ($result) { return $result['private_key']; } } $result = $this->collection('key_table')->findOne(array( 'client_id' => null )); return is_null($result) ? false : $result['private_key']; } public function getEncryptionAlgorithm($client_id = null) { if ($client_id) { $result = $this->collection('key_table')->findOne(array( 'client_id' => $client_id )); if ($result) { return $result['encryption_algorithm']; } } $result = $this->collection('key_table')->findOne(array( 'client_id' => null )); return is_null($result) ? 'RS256' : $result['encryption_algorithm']; } // Helper function to access a MongoDB collection by `type`: protected function collection($name) { return $this->db->{$this->config[$name]}; } }