public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request('code')) { $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required'); return false; } $code = $request->request('code'); if (!($authCode = $this->storage->getAuthorizationCode($code))) { $response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client'); return false; } /* * 4.1.3 - ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request * @uri - http://tools.ietf.org/html/rfc6749#section-4.1.3 */ if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) { if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) { $response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3"); return false; } } if (!isset($authCode['expires'])) { throw new Exception('Storage must return authcode with a value for "expires"'); } if ($authCode["expires"] < time()) { $response->setError(400, 'invalid_grant', "The authorization code has expired"); return false; } if (!isset($authCode['code'])) { $authCode['code'] = $code; // used to expire the code after the access token is granted } $this->authCode = $authCode; return true; }
/** * Grant or deny a requested access token. * This would be called from the "/token" endpoint as defined in the spec. * You can call your endpoint whatever you want. * * @param $request - RequestInterface * Request object to grant access token * * @throws InvalidArgumentException * @throws LogicException * * @see http://tools.ietf.org/html/rfc6749#section-4 * @see http://tools.ietf.org/html/rfc6749#section-10.6 * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 * * @ingroup oauth2_section_4 */ public function grantAccessToken(RequestInterface $request, ResponseInterface $response) { if (strtolower($request->server('REQUEST_METHOD')) != 'post') { $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); $response->addHttpHeaders(array('Allow' => 'POST')); return null; } /* Determine grant type from request * and validate the request for that grant type */ if (!($grantTypeIdentifier = $request->request('grant_type'))) { $response->setError(400, 'invalid_request', 'The grant type was not specified in the request'); return null; } if (!isset($this->grantTypes[$grantTypeIdentifier])) { /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier)); return null; } $grantType = $this->grantTypes[$grantTypeIdentifier]; if (!$grantType->validateRequest($request, $response)) { return null; } /* Retrieve the client information from the request * ClientAssertionTypes allow for grant types which also assert the client data * in which case ClientAssertion is handled in the validateRequest method * * @see OAuth2\GrantType\JWTBearer * @see OAuth2\GrantType\ClientCredentials */ if ($grantType instanceof ClientAssertionTypeInterface) { $clientId = $grantType->getClientId(); } else { if (!$this->clientAssertionType->validateRequest($request, $response)) { return null; } $clientId = $this->clientAssertionType->getClientId(); // validate the Client ID (if applicable) if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier)); return null; } } /* * Validate the scope of the token * If the grant type returns a value for the scope, * this value must be verified with the scope being requested */ $availableScope = $grantType->getScope(); if (!($requestedScope = $this->scopeUtil->getScopeFromRequest($request))) { $requestedScope = $availableScope ? $availableScope : $this->scopeUtil->getDefaultScope(); } if ($requestedScope && !$this->scopeUtil->scopeExists($requestedScope, $clientId) || $availableScope && !$this->scopeUtil->checkScope($requestedScope, $availableScope)) { $response->setError(400, 'invalid_scope', 'An unsupported scope was requested'); return null; } return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope); }
/** * This is a convenience function that can be used to get the token, which can then * be passed to getAccessTokenData(). The constraints specified by the draft are * attempted to be adheared to in this method. * * As per the Bearer spec (draft 8, section 2) - there are three ways for a client * to specify the bearer token, in order of preference: Authorization Header, * POST and GET. * * NB: Resource servers MUST accept tokens via the Authorization scheme * (http://tools.ietf.org/html/rfc6750#section-2). * * @todo Should we enforce TLS/SSL in this function? * * @see http://tools.ietf.org/html/rfc6750#section-2.1 * @see http://tools.ietf.org/html/rfc6750#section-2.2 * @see http://tools.ietf.org/html/rfc6750#section-2.3 * * Old Android version bug (at least with version 2.2) * @see http://code.google.com/p/android/issues/detail?id=6684 * */ public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) { $headers = $request->headers('AUTHORIZATION'); // echo ($headers."bearer"); /** * Ensure more than one method is not used for including an * access token * * @see http://tools.ietf.org/html/rfc6750#section-3.1 */ $methodsUsed = !empty($headers) + (bool) $request->query($this->config['token_param_name']) + (bool) $request->request($this->config['token_param_name']); // echo ($methodsUsed); // echo ("<br>".$this->config['token_param_name']."<br>"); if ($methodsUsed > 1) { $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); return null; } /** * If no authentication is provided, set the status code * to 401 and return no other error information * * @see http://tools.ietf.org/html/rfc6750#section-3.1 */ if ($methodsUsed == 0) { $response->setStatusCode(401); // echo ("no auth"); return null; } // HEADER: Get the access token from the header if (!empty($headers)) { if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\\s(\\S+)/i', $headers, $matches)) { $response->setError(400, 'invalid_request', 'Malformed auth header'); return null; } return $matches[1]; } if ($request->request($this->config['token_param_name'])) { // // POST: Get the token from POST data if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) { $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2'); return null; } $contentType = $request->server('CONTENT_TYPE'); if (false !== ($pos = strpos($contentType, ';'))) { $contentType = substr($contentType, 0, $pos); } if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') { // IETF specifies content-type. NB: Not all webservers populate this _SERVER variable // @see http://tools.ietf.org/html/rfc6750#section-2.2 $response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"'); return null; } return $request->request($this->config['token_param_name']); } // GET method return $request->query($this->config['token_param_name']); }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { $identifier = $this->getQuerystringIdentifier(); if (!$request->request($identifier)) { $response->setError(400, 'invalid_request', 'Missing parameters: "' . $identifier . '" required'); return null; } $fb_app_id = Config::get('api-foundation::fb_app_id'); $fb_app_secret = Config::get('api-foundation::fb_app_secret'); if (empty($fb_app_id)) { throw new \LogicException('Facebook APP ID not set.'); } if (empty($fb_app_secret)) { throw new \LogicException('Facebook APP SECRET not set.'); } FacebookSession::setDefaultApplication($fb_app_id, $fb_app_secret); try { $session = new FacebookSession($request->request($identifier)); } catch (FacebookRequestException $e) { $response->setError(401, 'invalid_grant', $e->getMessage()); return null; } catch (\Exception $e) { $response->setError(401, 'invalid_grant', $e->getMessage()); return null; } if (!empty($session)) { try { $user_profile = (new FacebookRequest($session, 'GET', '/me'))->execute()->getGraphObject(GraphUser::className()); $email = $user_profile->getProperty('email'); if (empty($email)) { $response->setError(400, 'invalid_request', "User's email address not available."); return null; } else { $userInfo = $this->storage->getUserInfoByFacebookId($user_profile->getId()); if (empty($userInfo)) { $this->storage->createFacebookUser($user_profile); $userInfo = $this->storage->getUserInfoByFacebookId($user_profile->getId()); } } } catch (FacebookRequestException $e) { $response->setError(401, 'invalid_grant', $e->getMessage()); return null; } } else { $response->setError(401, 'invalid_grant', 'Facebook session could not be set with supplied access token.'); return null; } if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information.'); return null; } if (!isset($userInfo['user_id'])) { throw new \LogicException("You must set the user_id on the array."); } $this->userInfo = $userInfo; return true; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { $query = DB::table('users')->select('id', 'email', 'employee_id', 'joining_date', 'name')->where('email', $request->request("email")); $data = $query->first(); if ($data) { $this->userInfo = $data; $this->userInfo->user_id = $data->id; return true; } return false; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { $identifier = $this->getQuerystringIdentifier(); if (!$request->request($identifier)) { $response->setError(400, 'invalid_request', 'Missing parameters: "' . $identifier . '" required'); return null; } $gplus_server_code = $request->request($identifier); try { $this->google_client->authenticate($gplus_server_code); $token_data = json_decode($this->google_client->getAccessToken()); $gplus_access_token = $token_data->access_token; $token_service = new Google_Service_Oauth2($this->google_client); $token_info = $token_service->tokeninfo(array('access_token' => $gplus_access_token)); if ($token_info->getAudience() != \Config::get('api-foundation::gplus_client_id')) { $response->setError(400, 'invalid_request', "Google+ access token audience does not match."); return null; } $gplus_id = $token_info->getUserId(); $email = $token_info->getEmail(); if (empty($email)) { $response->setError(400, 'invalid_request', "User's Google+ email addresses are not available."); return null; } if (empty($gplus_id)) { $response->setError(400, 'invalid_request', "User's Google+ id not available."); return null; } $userInfo = $this->storage->getUserInfoByGPlusId($gplus_id); if (empty($userInfo)) { $gplus_user = GPlusUserFromGPlusAccessToken::make($this->google_client, $gplus_access_token); $this->storage->createGPlusUser($gplus_user, $token_info); $userInfo = $this->storage->getUserInfoByGPlusId($gplus_id); } } catch (\Google_Service_Exception $e) { $response->setError($e->getCode(), 'invalid_request', "Google Plus server code is invalid."); return null; } catch (\Google_Auth_Exception $e) { $response->setError($e->getCode(), 'invalid_request', "Google Plus server code is invalid."); return null; } if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information.'); return null; } if (!isset($userInfo['user_id'])) { throw new \LogicException("You must set the user_id on the array."); } $this->userInfo = $userInfo; return true; }
/** * Validate request via session data * * This is used for internal requests via ajax * * @param object $request Request object * @param object $response Response object * @return bool Result of auth */ public function validateRequest(RequestInterface $request, ResponseInterface $response) { // ensure we have needed params if (!$request->request("password") || !$request->request("username")) { $response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" required'); return null; } // check username/password if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) { $response->setError(401, 'invalid_grant', 'Invalid username and password combination'); return null; } // get user details by username $userInfo = $this->storage->getUserDetails($request->request("username")); // make sure we got an array of user details if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); return null; } // if not set, something went wrong if (!isset($userInfo['user_id'])) { throw new \LogicException("you must set the user_id on the array returned by getUserDetails"); } // set our userinfo for later use $this->userInfo = $userInfo; // return sucess return true; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$this->_adapter->checkUserCredentials($request->request('identity'), $request->request('token'))) { $response->setError(401, 'invalid_grant', 'Invalid identity and token combination'); return null; } $userInfo = $this->_adapter->getUserDetails($request->request('identity')); if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); return null; } if (!isset($userInfo['user_id'])) { throw new \LogicException("You must set the user_id on the array returned by getUserDetails"); } $this->_userInfo = $userInfo; return true; }
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) { $prompt = $request->query('prompt', 'consent'); if ($prompt == 'none') { if (is_null($user_id)) { $error = 'login_required'; $error_message = 'The user must log in'; } else { $error = 'interaction_required'; $error_message = 'The user must grant access to your application'; } } else { $error = 'consent_required'; $error_message = 'The user denied access to your application'; } $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message); }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request('client_id')) { $response->setError(400, 'invalid_request', 'Missing parameter: "client_id" is required'); return false; } /* * Ensure that the client_id existed */ $client_id = $request->request('client_id'); if (!($client = $this->storage->getClientDetails($client_id))) { $response->setError(400, 'invalid_client', 'The client id supplied is invalid'); return false; } $this->client = $client; return true; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request("refresh_token")) { $response->setError(400, 'invalid_request', 'Missing parameter: "refresh_token" is required'); return null; } if (!($refreshToken = $this->storage->getRefreshToken($request->request("refresh_token")))) { $response->setError(400, 'invalid_grant', 'Invalid refresh token'); return null; } if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) { $response->setError(400, 'invalid_grant', 'Refresh token has expired'); return null; } // store the refresh token locally so we can delete it when a new refresh token is generated $this->refreshToken = $refreshToken; return true; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { $token = $request->request("token"); if (!$token) { $response->setError(400, 'invalid_request', 'Missing parameter: "token" is required'); return null; } $socialUser = $this->getTokenInfo($token); if (!$socialUser) { $response->setError(401, 'invalid_grant', 'Invalid or expired token'); return null; } $user_id = $this->getLocalUser($socialUser); if (!$user_id) { $response->setError(401, 'invalid_grant', 'Unable to identify or create user'); return null; } $this->userInfo = ['user_id' => $user_id]; return true; }
/** * This is a convenience function that can be used to get the token, which can then * be passed to getAccessTokenData(). The constraints specified by the draft are * attempted to be adheared to in this method. * * As per the Bearer spec (draft 8, section 2) - there are three ways for a client * to specify the bearer token, in order of preference: Authorization Header, * POST and GET. * * NB: Resource servers MUST accept tokens via the Authorization scheme * (http://tools.ietf.org/html/rfc6750#section-2). * * @todo Should we enforce TLS/SSL in this function? * * @see http://tools.ietf.org/html/rfc6750#section-2.1 * @see http://tools.ietf.org/html/rfc6750#section-2.2 * @see http://tools.ietf.org/html/rfc6750#section-2.3 * * Old Android version bug (at least with version 2.2) * @see http://code.google.com/p/android/issues/detail?id=6684 * */ public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) { $headers = $request->headers('AUTHORIZATION'); // Check that exactly one method was used $methodsUsed = !empty($headers) + !is_null($request->query($this->config['token_param_name'])) + !is_null($request->request($this->config['token_param_name'])); if ($methodsUsed > 1) { $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); return null; } if ($methodsUsed == 0) { $response->setStatusCode(401); return null; } // HEADER: Get the access token from the header if (!empty($headers)) { if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\\s(\\S+)/', $headers, $matches)) { $response->setError(400, 'invalid_request', 'Malformed auth header'); return null; } return $matches[1]; } if ($request->request($this->config['token_param_name'])) { // POST: Get the token from POST data if (strtolower($request->server('REQUEST_METHOD')) != 'post') { $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST'); return null; } $contentType = $request->server('CONTENT_TYPE'); if (false !== ($pos = strpos($contentType, ';'))) { $contentType = substr($contentType, 0, $pos); } LogMessage($request->request('upload_image')); LogMessage($contentType); if (!$request->files['Filedata']) { if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') { // IETF specifies content-type. NB: Not all webservers populate this _SERVER variable // @see http://tools.ietf.org/html/rfc6750#section-2.2 $response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"'); return null; } } return $request->request($this->config['token_param_name']); } // GET method return $request->query($this->config['token_param_name']); }
/** * Internal function used to get the client credentials from HTTP basic * auth or POST data. * * According to the spec (draft 20), the client_id can be provided in * the Basic Authorization header (recommended) or via GET/POST. * * @return * A list containing the client identifier and password, for example * @code * return array( * "client_id" => CLIENT_ID, // REQUIRED the client id * "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients) * ); * @endcode * * @see http://tools.ietf.org/html/rfc6749#section-2.3.1 * * @ingroup oauth2_section_2 */ public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null) { if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) { return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW')); } if ($this->config['allow_credentials_in_request_body']) { // Using POST for HttpBasic authorization is not recommended, but is supported by specification if (!is_null($request->request('client_id'))) { /** * client_secret can be null if the client's password is an empty string * @see http://tools.ietf.org/html/rfc6749#section-2.3.1 */ return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret')); } } if ($response) { $message = $this->config['allow_credentials_in_request_body'] ? ' or body' : ''; $response->setError(400, 'invalid_client', 'Client credentials were not found in the headers' . $message); } return null; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request("password") || !$request->request("username") || !$request->request("device_name") || !$request->request("device_uid")) { $response->setError(400, 'invalid_request', 'Missing parameters: "username" and "password" and "device" required'); return null; } if (!$this->storage->checkUserCredentials($request->request("username"), $request->request("password"))) { $response->setError(401, 'invalid_grant', 'Invalid username and password combination'); return null; } $userInfo = $this->storage->getUserDetails($request->request("username")); if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); return null; } if (!isset($userInfo['user_id'])) { throw new \LogicException("you must set the user_id on the array returned by getUserDetails"); } $this->device_uid = $request->request('device_uid'); $this->device_name = $request->request('device_name'); $this->userInfo = $userInfo; return true; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request("user_id") || !$request->request("provider") || !$request->request("provider_id") || !$request->request("provider_access_token")) { $response->setError(400, 'invalid_request', 'Missing parameters: "username" and "provider" and "provider_id" and "access_token" required'); return null; } if (!$this->storage->getUserProviderAccessToken($request->request("provider"), $request->request("provider_id"), $request->request("user_id"))) { return null; } $userInfo = $this->storage->getUser($request->request("user_id")); if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); return null; } if (!isset($userInfo['user_id'])) { throw new \LogicException("you must set the user_id on the array returned by getUserDetails"); } $this->userInfo = $userInfo; return true; }
public function getClientCredentials(RequestInterface $request, ResponseInterface $response = null) { if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) { return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW')); } if ($this->config['allow_credentials_in_request_body']) { // Using POST for HttpBasic authorization is not recommended, but is supported by specification if (!is_null($request->request('client_id'))) { return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret')); } } if ($response) { $message = $this->config['allow_credentials_in_request_body'] ? ' or body' : ''; $response->setError(400, 'invalid_client', 'Client credentials were not found in the headers' . $message); } return null; }
public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request('client_id')) { $response->setError(400, 'invalid_request', 'Missing parameter: "client_id" is required'); return false; } if (!$request->request('code')) { $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required'); return false; } /* * Ensure that the device code exists */ $client_id = $request->request('client_id'); $code = $request->request('code'); if (!($deviceCode = $this->storage->getDeviceCode($code, $client_id))) { $response->setError(400, 'bad_verification_code', 'Bad verification code'); return false; } /* * Verify expiration */ if ($deviceCode["expires"] < time()) { $response->setError(400, 'code_expired', "The authorization code has expired"); return false; } /* * Ensure that the user confirmed this code */ if (!$deviceCode['user_id']) { $response->setError(400, 'authorization_pending', ''); return false; } $this->deviceCode = $deviceCode; return true; }
public function getAccessTokenParameter(RequestInterface $request, ResponseInterface $response) { $headers = $request->headers('AUTHORIZATION'); $methodsUsed = !empty($headers) + (bool) $request->query($this->config['token_param_name']) + (bool) $request->request($this->config['token_param_name']); if ($methodsUsed > 1) { $response->setError(400, 'invalid_request', 'Only one method may be used to authenticate at a time (Auth header, GET or POST)'); return null; } if ($methodsUsed == 0) { $response->setStatusCode(401); return null; } // HEADER: Get the access token from the header if (!empty($headers)) { if (!preg_match('/' . $this->config['token_bearer_header_name'] . '\\s(\\S+)/i', $headers, $matches)) { $response->setError(400, 'invalid_request', 'Malformed auth header'); return null; } return $matches[1]; } if ($request->request($this->config['token_param_name'])) { // // POST: Get the token from POST data if (!in_array(strtolower($request->server('REQUEST_METHOD')), array('post', 'put'))) { $response->setError(400, 'invalid_request', 'When putting the token in the body, the method must be POST or PUT', '#section-2.2'); return null; } $contentType = $request->server('CONTENT_TYPE'); if (false !== ($pos = strpos($contentType, ';'))) { $contentType = substr($contentType, 0, $pos); } if ($contentType !== null && $contentType != 'application/x-www-form-urlencoded') { $response->setError(400, 'invalid_request', 'The content type for POST requests must be "application/x-www-form-urlencoded"'); return null; } return $request->request($this->config['token_param_name']); } return $request->query($this->config['token_param_name']); }
public function validateRequest(\OAuth2\RequestInterface $request, \OAuth2\ResponseInterface $response) { if (!$request->request('authkey') || !$request->request('username')) { $response->setError(400, 'invalid_request', 'Missing parameters: "authkey" and "username" required'); return null; } if (!$this->userStorage->findIdentityByAccessToken($request->request('authkey'))) { $response->setError(401, 'invalid_grant', 'Invalid user authkey'); return null; } $userInfo = $this->userStorage->getUserDetails($request->request('username')); if (empty($userInfo)) { $response->setError(400, 'invalid_grant', 'Unable to retrieve user information'); return null; } if (!isset($userInfo['user_id'])) { throw new \LogicException('you must set the user_id on the array returned by getUserDetails'); } $this->userInfo = $userInfo; return parent::validateRequest($request, $response); }
/** * Validates the data from the decoded JWT. * * @return * TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned. * * @see OAuth2\GrantType\GrantTypeInterface::getTokenData() */ public function validateRequest(RequestInterface $request, ResponseInterface $response) { if (!$request->request("assertion")) { $response->setError(400, 'invalid_request', 'Missing parameters: "assertion" required'); return null; } // Store the undecoded JWT for later use $undecodedJWT = $request->request('assertion'); // Decode the JWT $jwt = $this->jwtUtil->decode($request->request('assertion'), null, false); if (!$jwt) { $response->setError(400, 'invalid_request', "JWT is malformed"); return null; } // ensure these properties contain a value // @todo: throw malformed error for missing properties $jwt = array_merge(array('scope' => null, 'iss' => null, 'sub' => null, 'aud' => null, 'exp' => null, 'nbf' => null, 'iat' => null, 'jti' => null, 'typ' => null), $jwt); if (!isset($jwt['iss'])) { $response->setError(400, 'invalid_grant', "Invalid issuer (iss) provided"); return null; } if (!isset($jwt['sub'])) { $response->setError(400, 'invalid_grant', "Invalid subject (sub) provided"); return null; } if (!isset($jwt['exp'])) { $response->setError(400, 'invalid_grant', "Expiration (exp) time must be present"); return null; } // Check expiration if (ctype_digit($jwt['exp'])) { if ($jwt['exp'] <= time()) { $response->setError(400, 'invalid_grant', "JWT has expired"); return null; } } else { $response->setError(400, 'invalid_grant', "Expiration (exp) time must be a unix time stamp"); return null; } // Check the not before time if ($notBefore = $jwt['nbf']) { if (ctype_digit($notBefore)) { if ($notBefore > time()) { $response->setError(400, 'invalid_grant', "JWT cannot be used before the Not Before (nbf) time"); return null; } } else { $response->setError(400, 'invalid_grant', "Not Before (nbf) time must be a unix time stamp"); return null; } } // Check the audience if required to match if (!isset($jwt['aud']) || $jwt['aud'] != $this->audience) { $response->setError(400, 'invalid_grant', "Invalid audience (aud)"); return null; } // Check the jti (nonce) // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1.7 if (isset($jwt['jti'])) { $jti = $this->storage->getJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']); //Reject if jti is used and jwt is still valid (exp parameter has not expired). if ($jti && $jti['expires'] > time()) { $response->setError(400, 'invalid_grant', "JSON Token Identifier (jti) has already been used"); return null; } else { $this->storage->setJti($jwt['iss'], $jwt['sub'], $jwt['aud'], $jwt['exp'], $jwt['jti']); } } // Get the iss's public key // @see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06#section-4.1.1 if (!($key = $this->storage->getClientKey($jwt['iss'], $jwt['sub']))) { $response->setError(400, 'invalid_grant', "Invalid issuer (iss) or subject (sub) provided"); return null; } // Verify the JWT if (!$this->jwtUtil->decode($undecodedJWT, $key, true)) { $response->setError(400, 'invalid_grant', "JWT failed signature verification"); return null; } $this->jwt = $jwt; return true; }
/** * Revoke a refresh or access token. Returns true on success and when tokens are invalid * * Note: invalid tokens do not cause an error response since the client * cannot handle such an error in a reasonable way. Moreover, the * purpose of the revocation request, invalidating the particular token, * is already achieved. * * @param RequestInterface $request * @param ResponseInterface $response * @return bool|null */ public function revokeToken(RequestInterface $request, ResponseInterface $response) { if (strtolower($request->server('REQUEST_METHOD')) != 'post') { $response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2'); $response->addHttpHeaders(array('Allow' => 'POST')); return null; } $token_type_hint = $request->request('token_type_hint'); if (!in_array($token_type_hint, array(null, 'access_token', 'refresh_token'), true)) { $response->setError(400, 'invalid_request', 'Token type hint must be either \'access_token\' or \'refresh_token\''); return null; } $token = $request->request('token'); if ($token === null) { $response->setError(400, 'invalid_request', 'Missing token parameter to revoke'); return null; } // @todo remove this check for v2.0 if (!method_exists($this->accessToken, 'revokeToken')) { $class = get_class($this->accessToken); throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method"); } $this->accessToken->revokeToken($token, $token_type_hint); return true; }
/** * Validate request via client * * @param object $request Request object * @param object $response Response object * @return bool Result of auth */ public function validateRequest(RequestInterface $request, ResponseInterface $response) { // check HTTP basic auth headers for client id/secret if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) { $clientData = array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW')); } // if we allow credentials via request body look there if ($this->config['allow_credentials_in_request_body']) { // check for client id in request if (!is_null($request->request('client_id'))) { $clientData = array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret')); } } // must have client id if (!isset($clientData['client_id']) || $clientData['client_id'] == '') { $message = $this->config['allow_credentials_in_request_body'] ? ' or body' : ''; $response->setError(400, 'invalid_client', 'Client credentials were not found in the headers' . $message); return false; } // check to see if we have client secret if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') { // invalid if we dont have client secret and public clients are off if (!$this->config['allow_public_clients']) { $response->setError(400, 'invalid_client', 'client credentials are required'); return false; } // check storage if client is public client if (!$this->storage->isPublicClient($clientData['client_id'])) { $response->setError(400, 'invalid_client', 'This client is invalid or must authenticate using a client secret'); return false; } } elseif ($this->storage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) { $response->setError(400, 'invalid_client', 'The client credentials are invalid'); return false; } // store data locally $this->clientData = $clientData; return true; }
/** * @param RequestInterface $request * @param ResponseInterface $response * * @return bool */ public function validateRequest(RequestInterface $request, ResponseInterface $response) { $providerName = $request->request('provider'); $providerUserId = $request->request('provider_user_id'); $providerAccessToken = $request->request('provider_access_token'); if (!$providerName || !$providerUserId || !$providerAccessToken) { $response->setError(400, 'invalid_request', 'One or more missing parameter: "provider", "provider_user_id" and "provider_access_token" are required'); return false; } $provider = isset($this->providers[$providerName]) ? $this->providers[$providerName] : null; if (!$provider instanceof ProviderInterface) { $response->setError(400, 'invalid_request', 'Unknown provider selected'); return false; } try { $errorMessage = ''; if (!$provider->validate($providerUserId, $providerAccessToken, $errorMessage)) { $response->setError(401, 'invalid_grant', 'Invalid third party credentials: ' . $errorMessage); return false; } } catch (ClientException $e) { $response->setError($e->getCode(), 'provider_client_error', $e->getMessage()); return false; } catch (Exception $e) { $response->setError(500, 'provider_error', $e->getMessage()); return false; } $token = $request->request('access_token'); $accessToken = $token ? $this->accessTokenMapper->findByToken($token) : null; if ($accessToken instanceof Entity\AccessToken && $accessToken->isExpired()) { $response->setError(401, 'invalid_grant', 'Access token is expired'); return false; } $thirdPartyUser = $this->thirdPartyMapper->findByProvider($provider); switch (true) { // a known user tries to connect with third party credentials owned by another user? issue an error case $accessToken instanceof Entity\AccessToken && $thirdPartyUser instanceof Entity\ThirdParty && $thirdPartyUser->getUser() !== $accessToken->getUser(): $response->setError(400, 'invalid_request', 'Another user is already registered with same credentials'); return false; // known third party credentials? update the data and grab the user form it // known third party credentials? update the data and grab the user form it case $thirdPartyUser instanceof Entity\ThirdParty: $thirdPartyUser->setData($provider->getUserData()); $user = $thirdPartyUser->getUser(); break; // valid access token? grab the user form it // valid access token? grab the user form it case $accessToken instanceof Entity\AccessToken: $user = $accessToken->getUser(); break; // no third party credentials or access token? it's a new user // no third party credentials or access token? it's a new user default: $userClass = $this->moduleOptions->getUserEntityClassName(); $user = new $userClass(); } // in case 3 and 4 we need to connect the user with new third party credentials if (!$thirdPartyUser instanceof Entity\ThirdParty) { $this->connectUserToThirdParty($user, $provider); } $this->userMapper->save($user); $this->user = $user; return true; }
/** * Grant or deny a requested access token. * This would be called from the "/token" endpoint as defined in the spec. * You can call your endpoint whatever you want. * * @param $request - RequestInterface * Request object to grant access token * * @throws InvalidArgumentException * @throws LogicException * * @see http://tools.ietf.org/html/rfc6749#section-4 * @see http://tools.ietf.org/html/rfc6749#section-10.6 * @see http://tools.ietf.org/html/rfc6749#section-4.1.3 * * @ingroup oauth2_section_4 */ public function grantAccessToken(RequestInterface $request, ResponseInterface $response) { if (strtolower($request->server('REQUEST_METHOD')) != 'post') { $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); $response->addHttpHeaders(array('Allow' => 'POST')); return null; } /** * Determine grant type from request * and validate the request for that grant type */ if (!($grantTypeIdentifier = $request->request('grant_type'))) { $response->setError(400, 'invalid_request', 'The grant type was not specified in the request'); return null; } if (!isset($this->grantTypes[$grantTypeIdentifier])) { /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier)); return null; } $grantType = $this->grantTypes[$grantTypeIdentifier]; /** * Retrieve the client information from the request * ClientAssertionTypes allow for grant types which also assert the client data * in which case ClientAssertion is handled in the validateRequest method * * @see OAuth2\GrantType\JWTBearer * @see OAuth2\GrantType\ClientCredentials */ if (!$grantType instanceof ClientAssertionTypeInterface) { if (!$this->clientAssertionType->validateRequest($request, $response)) { return null; } $clientId = $this->clientAssertionType->getClientId(); } /** * Retrieve the grant type information from the request * The GrantTypeInterface object handles all validation * If the object is an instance of ClientAssertionTypeInterface, * That logic is handled here as well */ if (!$grantType->validateRequest($request, $response)) { return null; } if ($grantType instanceof ClientAssertionTypeInterface) { $clientId = $grantType->getClientId(); } else { // validate the Client ID (if applicable) if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier)); return null; } } /** * Validate the client can use the requested grant type */ if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) { $response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id'); return false; } /** * Validate the scope of the token * * requestedScope - the scope specified in the token request * availableScope - the scope associated with the grant type * ex: in the case of the "Authorization Code" grant type, * the scope is specified in the authorize request * * @see http://tools.ietf.org/html/rfc6749#section-3.3 */ $requestedScope = $this->scopeUtil->getScopeFromRequest($request); $availableScope = $grantType->getScope(); if ($requestedScope) { // validate the requested scope if ($availableScope) { if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) { $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request'); return null; } } else { // validate the client has access to this scope if ($clientScope = $this->clientStorage->getClientScope($clientId)) { if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) { $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client'); return false; } } elseif (!$this->scopeUtil->scopeExists($requestedScope)) { $response->setError(400, 'invalid_scope', 'An unsupported scope was requested'); return null; } } } elseif ($availableScope) { // use the scope associated with this grant type $requestedScope = $availableScope; } else { // use a globally-defined default scope $defaultScope = $this->scopeUtil->getDefaultScope($clientId); // "false" means default scopes are not allowed if (false === $defaultScope) { $response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter'); return null; } $requestedScope = $defaultScope; } return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope); }
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) { // Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI) if (!($client_id = $request->query('client_id', $request->request('client_id')))) { // We don't have a good URI to use $response->setError(400, 'invalid_client', "No client id supplied"); return false; } // Get client details if (!($clientData = $this->clientStorage->getClientDetails($client_id))) { $response->setError(400, 'invalid_client', 'The client id supplied is invalid'); return false; } $registered_redirect_uri = isset($clientData['redirect_uri']) ? $clientData['redirect_uri'] : ''; // Make sure a valid redirect_uri was supplied. If specified, it must match the clientData URI. // @see http://tools.ietf.org/html/rfc6749#section-3.1.2 // @see http://tools.ietf.org/html/rfc6749#section-4.1.2.1 // @see http://tools.ietf.org/html/rfc6749#section-4.2.2.1 if ($supplied_redirect_uri = $request->query('redirect_uri', $request->request('redirect_uri'))) { // validate there is no fragment supplied $parts = parse_url($supplied_redirect_uri); if (isset($parts['fragment']) && $parts['fragment']) { $response->setError(400, 'invalid_uri', 'The redirect URI must not contain a fragment'); return false; } // validate against the registered redirect uri(s) if available if ($registered_redirect_uri && !$this->validateRedirectUri($supplied_redirect_uri, $registered_redirect_uri)) { $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI provided is missing or does not match', '#section-3.1.2'); return false; } $redirect_uri = $supplied_redirect_uri; } else { // use the registered redirect_uri if none has been supplied, if possible if (!$registered_redirect_uri) { $response->setError(400, 'invalid_uri', 'No redirect URI was supplied or stored'); return false; } if (count(explode(' ', $registered_redirect_uri)) > 1) { $response->setError(400, 'invalid_uri', 'A redirect URI must be supplied when multiple redirect URIs are registered', '#section-3.1.2.3'); return false; } $redirect_uri = $registered_redirect_uri; } // Select the redirect URI $response_type = $request->query('response_type', $request->request('response_type')); // for multiple-valued response types - make them alphabetical if (false !== strpos($response_type, ' ')) { $types = explode(' ', $response_type); sort($types); $response_type = ltrim(implode(' ', $types)); } $state = $request->query('state', $request->request('state')); // type and client_id are required if (!$response_type || !in_array($response_type, $this->getValidResponseTypes())) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_request', 'Invalid or missing response type', null); return false; } if ($response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) { if (!isset($this->responseTypes['code'])) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'authorization code grant type not supported', null); return false; } if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'authorization_code')) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); return false; } if ($this->responseTypes['code']->enforceRedirect() && !$redirect_uri) { $response->setError(400, 'redirect_uri_mismatch', 'The redirect URI is mandatory and was not supplied'); return false; } } else { if (!$this->config['allow_implicit']) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unsupported_response_type', 'implicit grant type not supported', null); return false; } if (!$this->clientStorage->checkRestrictedGrantType($client_id, 'implicit')) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'unauthorized_client', 'The grant type is unauthorized for this client_id', null); return false; } } // validate requested scope if it exists $requestedScope = $this->scopeUtil->getScopeFromRequest($request); if ($requestedScope) { // restrict scope by client specific scope if applicable, // otherwise verify the scope exists $clientScope = $this->clientStorage->getClientScope($client_id); if (is_null($clientScope) && !$this->scopeUtil->scopeExists($requestedScope) || $clientScope && !$this->scopeUtil->checkScope($requestedScope, $clientScope)) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_scope', 'An unsupported scope was requested', null); return false; } } else { // use a globally-defined default scope $defaultScope = $this->scopeUtil->getDefaultScope($client_id); if (false === $defaultScope) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $state, 'invalid_client', 'This application requires you specify a scope parameter', null); return false; } $requestedScope = $defaultScope; } // Validate state parameter exists (if configured to enforce this) if ($this->config['enforce_state'] && !$state) { $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, null, 'invalid_request', 'The state parameter is required'); return false; } // save the input data and return true $this->scope = $requestedScope; $this->state = $state; $this->client_id = $client_id; // Only save the SUPPLIED redirect URI (@see http://tools.ietf.org/html/rfc6749#section-4.1.3) $this->redirect_uri = $supplied_redirect_uri; $this->response_type = $response_type; return true; }
public function getScopeFromRequest(RequestInterface $request) { // "scope" is valid if passed in either POST or QUERY return $request->request('scope', $request->query('scope')); }
/** * Validate request via client * * @param object $request Request object * @param object $response Response object * @return bool Result of auth */ public function validateRequest(RequestInterface $request, ResponseInterface $response) { // make sure we have a code param if (!($code = $request->request('code'))) { $response->setError(400, 'invalid_request', 'Missing parameter: "code" is required'); return false; } // verify code param if (!($authCode = $this->storage->getAuthorizationCode($code))) { $response->setError(400, 'invalid_grant', 'Authorization code doesn\'t exist or is invalid for the client'); return false; } // make sure "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request if (isset($authCode['redirect_uri']) && $authCode['redirect_uri']) { if (!$request->request('redirect_uri') || urldecode($request->request('redirect_uri')) != $authCode['redirect_uri']) { $response->setError(400, 'redirect_uri_mismatch', "The redirect URI is missing or do not match", "#section-4.1.3"); return false; } } // must have expiration if (!isset($authCode['expires'])) { throw new \Exception('Storage must return authcode with a value for "expires"'); } // checkk code isnt expired if ($authCode["expires"] < time()) { $response->setError(400, 'invalid_grant', "The authorization code has expired"); return false; } // make sure have the actual auth code if (!isset($authCode['code'])) { $authCode['code'] = $code; // used to expire the code after the access token is granted } // store locally $this->authCode = $authCode; return true; }
public function grantAccessToken(RequestInterface $request, ResponseInterface $response) { if (strtolower($request->server('REQUEST_METHOD')) != 'post') { $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); $response->addHttpHeaders(array('Allow' => 'POST')); return null; } if (!($grantTypeIdentifier = $request->request('grant_type'))) { $response->setError(400, 'invalid_request', 'The grant type was not specified in the request'); return null; } if (!isset($this->grantTypes[$grantTypeIdentifier])) { $response->setError(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantTypeIdentifier)); return null; } $grantType = $this->grantTypes[$grantTypeIdentifier]; if (!$grantType instanceof ClientAssertionTypeInterface) { if (!$this->clientAssertionType->validateRequest($request, $response)) { return null; } $clientId = $this->clientAssertionType->getClientId(); } if (!$grantType->validateRequest($request, $response)) { return null; } if ($grantType instanceof ClientAssertionTypeInterface) { $clientId = $grantType->getClientId(); } else { // validate the Client ID (if applicable) if (!is_null($storedClientId = $grantType->getClientId()) && $storedClientId != $clientId) { $response->setError(400, 'invalid_grant', sprintf('%s doesn\'t exist or is invalid for the client', $grantTypeIdentifier)); return null; } } /** * Validate the client can use the requested grant type */ if (!$this->clientStorage->checkRestrictedGrantType($clientId, $grantTypeIdentifier)) { $response->setError(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id'); return false; } $requestedScope = $this->scopeUtil->getScopeFromRequest($request); $availableScope = $grantType->getScope(); if ($requestedScope) { // validate the requested scope if ($availableScope) { if (!$this->scopeUtil->checkScope($requestedScope, $availableScope)) { $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this request'); return null; } } else { // validate the client has access to this scope if ($clientScope = $this->clientStorage->getClientScope($clientId)) { if (!$this->scopeUtil->checkScope($requestedScope, $clientScope)) { $response->setError(400, 'invalid_scope', 'The scope requested is invalid for this client'); return false; } } elseif (!$this->scopeUtil->scopeExists($requestedScope)) { $response->setError(400, 'invalid_scope', 'An unsupported scope was requested'); return null; } } } elseif ($availableScope) { // use the scope associated with this grant type $requestedScope = $availableScope; } else { // use a globally-defined default scope $defaultScope = $this->scopeUtil->getDefaultScope($clientId); // "false" means default scopes are not allowed if (false === $defaultScope) { $response->setError(400, 'invalid_scope', 'This application requires you specify a scope parameter'); return null; } $requestedScope = $defaultScope; } return $grantType->createAccessToken($this->accessToken, $clientId, $grantType->getUserId(), $requestedScope); }
/** * Get tool data from request * * @return bool Result of test */ public function getToolSessionDataFromRequest(RequestInterface $request) { // get params via post vars $toolSessionId = $request->request('sessionnum'); $toolSessionToken = $request->request('sessiontoken'); // use headers as backup method to post vars if (!$toolSessionId && !$toolSessionToken) { $toolSessionId = $request->headers('sessionnum'); $toolSessionToken = $request->headers('sessiontoken'); } // return id & token return compact('toolSessionId', 'toolSessionToken'); }