Spaces:
Sleeping
Sleeping
processmaker-community / processmaker-files /workflow /engine /src /ProcessMaker /Services /OAuth2 /PmPdo.php
| namespace ProcessMaker\Services\OAuth2; | |
| /** | |
| * Simple PmPDO storage for all storage types | |
| * based on \OAuth2\Storage\Pdo | |
| * | |
| * @author Erik Amaru Ortiz <aortiz.erik at gmail dot com> | |
| */ | |
| class PmPdo implements \OAuth2\Storage\AuthorizationCodeInterface, | |
| \OAuth2\Storage\AccessTokenInterface, | |
| \OAuth2\Storage\ClientCredentialsInterface, | |
| \OAuth2\Storage\UserCredentialsInterface, | |
| \OAuth2\Storage\RefreshTokenInterface, | |
| \OAuth2\Storage\JwtBearerInterface | |
| { | |
| protected $db; | |
| protected $dbRBAC; | |
| protected $config; | |
| public function __construct($connection, $config = array(), $connectionRBAC = null) | |
| { | |
| if (!$connection instanceof \PDO) { | |
| if (!is_array($connection)) { | |
| throw new \InvalidArgumentException('First argument to OAuth2\Storage\Pdo must be an instance of PDO or a configuration array'); | |
| } | |
| if (!isset($connection['dsn'])) { | |
| throw new \InvalidArgumentException('configuration array must contain "dsn"'); | |
| } | |
| // merge optional parameters | |
| $connection = array_merge(array( | |
| 'username' => null, | |
| 'password' => null, | |
| ), $connection); | |
| $connection = new \PDO($connection['dsn'], $connection['username'], $connection['password']); | |
| } | |
| $this->db = $connection; | |
| // it's for Pm < 3 | |
| if (!is_null($connectionRBAC) &&(!$connectionRBAC instanceof \PDO)) { | |
| if (!is_array($connectionRBAC)) { | |
| throw new \InvalidArgumentException('First argument to OAuth2\Storage\Pdo must be an instance of PDO or a configuration array'); | |
| } | |
| if (!isset($connectionRBAC['dsn'])) { | |
| throw new \InvalidArgumentException('configuration array must contain "dsn"'); | |
| } | |
| // merge optional parameters | |
| $connectionRBAC = array_merge(array( | |
| 'username' => null, | |
| 'password' => null, | |
| ), $connectionRBAC); | |
| $connectionRBAC = new \PDO($connectionRBAC['dsn'], $connectionRBAC['username'], $connectionRBAC['password']); | |
| } | |
| $this->dbRBAC = $connectionRBAC; | |
| // debugging | |
| $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); | |
| $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' => 'RBAC_USERS', | |
| 'jwt_table' => 'OAUTH_JWT', | |
| ), $config); | |
| } | |
| /* OAuth2_Storage_ClientCredentialsInterface */ | |
| public function checkClientCredentials($client_id, $client_secret = null) | |
| { | |
| $stmt = $this->db->prepare(sprintf('SELECT * from %s WHERE CLIENT_ID = :client_id', $this->config['client_table'])); | |
| $stmt->execute(compact('client_id')); | |
| $result = self::expandCase($stmt->fetch()); | |
| // make this extensible | |
| return $result['client_secret'] == $client_secret; | |
| } | |
| public function getClientDetails($client_id) | |
| { | |
| $stmt = $this->db->prepare(sprintf('SELECT * from %s WHERE CLIENT_ID = :client_id', $this->config['client_table'])); | |
| $stmt->execute(compact('client_id')); | |
| return self::expandCase($stmt->fetch()); | |
| } | |
| 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, (array) $grant_types); | |
| } | |
| // if grant_types are not defined, then none are restricted | |
| return true; | |
| } | |
| /* OAuth2_Storage_AccessTokenInterface */ | |
| public function getAccessToken($access_token) | |
| { | |
| $stmt = $this->db->prepare(sprintf('SELECT * from %s WHERE ACCESS_TOKEN = :access_token', $this->config['access_token_table'])); | |
| $token = $stmt->execute(compact('access_token')); | |
| if ($token = self::expandCase($stmt->fetch())) { | |
| // convert date string back to timestamp | |
| $token['expires'] = strtotime($token['expires']); | |
| } | |
| return $token; | |
| } | |
| public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) | |
| { | |
| //Delete expired Access and Refresh Token | |
| foreach (array($this->config["access_token_table"], $this->config["refresh_token_table"]) as $value) { | |
| $stmt = $this->db->prepare(sprintf("DELETE FROM %s WHERE EXPIRES < %s", $value, "'" . date("Y-m-d H:i:s") . "'")); | |
| $result = $stmt->execute(); | |
| } | |
| // convert expires to datestring | |
| $expires = date('Y-m-d H:i:s', $expires); | |
| // if it exists, update it. | |
| if ($this->getAccessToken($access_token)) { | |
| $stmt = $this->db->prepare(sprintf('UPDATE %s SET CLIENT_ID=:client_id, EXPIRES=:expires, USER_ID=:user_id, SCOPE=:scope WHERE ACCESS_TOKEN=:access_token', $this->config['access_token_table'])); | |
| } else { | |
| $stmt = $this->db->prepare(sprintf('INSERT INTO %s (ACCESS_TOKEN, CLIENT_ID, EXPIRES, USER_ID, SCOPE) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['access_token_table'])); | |
| } | |
| return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope')); | |
| } | |
| /* OAuth2_Storage_AuthorizationCodeInterface */ | |
| public function getAuthorizationCode($code) | |
| { | |
| $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE AUTHORIZATION_CODE = :code', $this->config['code_table'])); | |
| $stmt->execute(compact('code')); | |
| if ($code = self::expandCase($stmt->fetch())) { | |
| // convert date string back to timestamp | |
| $code['expires'] = strtotime($code['expires']); | |
| } | |
| return $code; | |
| } | |
| public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null) | |
| { | |
| // convert expires to datestring | |
| $expires = date('Y-m-d H:i:s', $expires); | |
| // if it exists, update it. | |
| if ($this->getAuthorizationCode($code)) { | |
| $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET CLIENT_ID=:client_id, USER_ID=:user_id, REDIRECT_URI=:redirect_uri, EXPIRES=:expires, SCOPE=:scope where AUTHORIZATION_CODE=:code', $this->config['code_table'])); | |
| } else { | |
| $stmt = $this->db->prepare(sprintf('INSERT INTO %s (AUTHORIZATION_CODE, CLIENT_ID, USER_ID, REDIRECT_URI, EXPIRES, SCOPE) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table'])); | |
| } | |
| return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope')); | |
| } | |
| public function expireAuthorizationCode($code) | |
| { | |
| $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE AUTHORIZATION_CODE = :code', $this->config['code_table'])); | |
| return $stmt->execute(compact('code')); | |
| } | |
| public function expireToken($token) | |
| { | |
| $access_token = new \OauthAccessTokens(); | |
| $access_token->load($token); | |
| $stmt = $this->db->prepare(sprintf('UPDATE %s SET EXPIRES=%s WHERE ACCESS_TOKEN=:token', $this->config['access_token_table'], "'".Date('Y-m-d H:i:s',strtotime("-1 minute"))."'")); | |
| return $stmt->execute(compact('token')); | |
| } | |
| public function deleteToken($token) | |
| { | |
| $access_token = new \OauthAccessTokens(); | |
| $access_token->load($token); | |
| $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE ACCESS_TOKEN = :token', $this->config['access_token_table'])); | |
| return $stmt->execute(compact("token")); | |
| } | |
| /* OAuth2_Storage_UserCredentialsInterface */ | |
| public function checkUserCredentials($username, $password) | |
| { | |
| $RBAC = \RBAC::getSingleton(); | |
| $RBAC->initRBAC(); | |
| $uid = $RBAC->VerifyLogin($username , $password); | |
| if($uid < 0){ | |
| return false; | |
| } | |
| if($uid != ''){ | |
| return true; | |
| } | |
| return false; | |
| } | |
| public function getUserDetails($username) | |
| { | |
| return $this->getUser($username); | |
| } | |
| /* OAuth2_Storage_RefreshTokenInterface */ | |
| public function getRefreshToken($refresh_token) | |
| { | |
| $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE REFRESH_TOKEN = :refresh_token', $this->config['refresh_token_table'])); | |
| $token = $stmt->execute(compact('refresh_token')); | |
| if ($token = self::expandCase($stmt->fetch())) { | |
| // convert expires to epoch time | |
| $token['expires'] = strtotime($token['expires']); | |
| } | |
| return $token; | |
| } | |
| public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) | |
| { | |
| // convert expires to datestring | |
| $expires = date('Y-m-d H:i:s', $expires); | |
| $stmt = $this->db->prepare(sprintf('INSERT INTO %s (REFRESH_TOKEN, CLIENT_ID, USER_ID, EXPIRES, SCOPE) VALUES (:refresh_token, :client_id, :user_id, :expires, :scope)', $this->config['refresh_token_table'])); | |
| return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope')); | |
| } | |
| public function unsetRefreshToken($refresh_token) | |
| { | |
| $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE REFRESH_TOKEN = :refresh_token', $this->config['refresh_token_table'])); | |
| return $stmt->execute(compact('refresh_token')); | |
| } | |
| // plaintext passwords are bad! Override this for your application | |
| protected function checkPassword($user, $password) | |
| { | |
| return $user['USR_PASSWORD'] == \Bootstrap::hashPassword($password); | |
| } | |
| public function getUser($username) | |
| { | |
| $stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE USR_USERNAME=:username', $this->config['user_table'])); | |
| if (!is_null($this->dbRBAC)) { | |
| $stmt = $this->dbRBAC->prepare($sql = sprintf('SELECT * FROM %s WHERE USR_USERNAME=:username', $this->config['user_table'])); | |
| } | |
| $stmt->execute(array('username' => $username)); | |
| if (!$userInfo = $stmt->fetch()) { | |
| return false; | |
| } | |
| $userInfo = self::expandCase($userInfo); | |
| // the default behavior is to use "username" as the user_id | |
| return array_merge(array( | |
| 'user_id' => $userInfo['USR_UID'] //$username | |
| ), $userInfo); | |
| } | |
| public function setUser($username, $password, $firstName = null, $lastName = null) | |
| { | |
| // do not store in plaintext | |
| $password = sha1($password); | |
| // if it exists, update it. | |
| if ($this->getUser($username)) { | |
| $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET PASSWORD=:password, FIRST_NAME=:firstName, LAST_NAME=:lastName WHERE USERNAME=:username', $this->config['user_table'])); | |
| } else { | |
| $stmt = $this->db->prepare(sprintf('INSERT INTO %s (USERNAME, PASSWORD, FIRST_NAME, LAST_NAME) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table'])); | |
| } | |
| return $stmt->execute(compact('username', 'password', 'firstName', 'lastName')); | |
| } | |
| /* OAuth2_Storage_JWTBearerInterface */ | |
| public function getClientKey($client_id, $subject) | |
| { | |
| $stmt = $this->db->prepare($sql = sprintf('SELECT PUBLIC_KEY from %s WHERE CLIENT_ID=:client_id AND SUBJECT=:subject', $this->config['jwt_table'])); | |
| $stmt->execute(array('client_id' => $client_id, 'subject' => $subject)); | |
| return self::expandCase($stmt->fetch()); | |
| } | |
| protected static function expandCase($a, $case = CASE_LOWER) | |
| { | |
| if (! is_array($a)) { | |
| return $a; | |
| } | |
| return array_merge($a, array_change_key_case($a, $case)); | |
| } | |
| } | |