public function testBrokenFromArray() { try { $c = ClientRegistration::fromArray(array("foo" => "bar")); $this->assertTrue(FALSE); } catch (ClientRegistrationException $e) { $this->assertEquals("not a valid client, 'id' not set", $e->getMessage()); } }
public function handleRequest(HttpRequest $request) { $response = new HttpResponse(200, "application/json"); try { if (!$this->_config->getSectionValue("Api", "enableApi")) { throw new ApiException("forbidden", "api disabled"); } $this->_rs->verifyAuthorizationHeader($request->getHeader("Authorization")); $storage = $this->_storage; // FIXME: can this be avoided?? $rs = $this->_rs; // FIXME: can this be avoided?? $request->matchRest("POST", "/authorizations/", function () use($request, $response, $storage, $rs) { $rs->requireScope("authorizations"); $data = Json::dec($request->getContent()); if (NULL === $data || !is_array($data) || !array_key_exists("client_id", $data) || !array_key_exists("scope", $data)) { throw new ApiException("invalid_request", "missing required parameters"); } // client needs to exist $clientId = $data['client_id']; $client = $storage->getClient($clientId); if (FALSE === $client) { throw new ApiException("invalid_request", "client is not registered"); } // scope should be part of "allowed_scope" of client registration $clientAllowedScope = new Scope($client['allowed_scope']); $requestedScope = new Scope($data['scope']); if (!$requestedScope->isSubSetOf($clientAllowedScope)) { throw new ApiException("invalid_request", "invalid scope for this client"); } $refreshToken = array_key_exists("refresh_token", $data) && $data['refresh_token'] ? Utils::randomHex(16) : NULL; // check to see if an authorization for this client/resource_owner already exists if (FALSE === $storage->getApprovalByResourceOwnerId($clientId, $rs->getResourceOwnerId())) { if (FALSE === $storage->addApproval($clientId, $rs->getResourceOwnerId(), $data['scope'], $refreshToken)) { throw new ApiException("invalid_request", "unable to add authorization"); } } else { throw new ApiException("invalid_request", "authorization already exists for this client and resource owner"); } $response->setStatusCode(201); $response->setContent(Json::enc(array("ok" => true))); }); $request->matchRest("GET", "/authorizations/:id", function ($id) use($request, $response, $storage, $rs) { $rs->requireScope("authorizations"); $data = $storage->getApprovalByResourceOwnerId($id, $rs->getResourceOwnerId()); if (FALSE === $data) { throw new ApiException("not_found", "the resource you are trying to retrieve does not exist"); } $response->setContent(Json::enc($data)); }); $request->matchRest("GET", "/authorizations/:id", function ($id) use($request, $response, $storage, $rs) { $rs->requireScope("authorizations"); $data = $storage->getApprovalByResourceOwnerId($id, $rs->getResourceOwnerId()); if (FALSE === $data) { throw new ApiException("not_found", "the resource you are trying to retrieve does not exist"); } $response->setContent(Json::enc($data)); }); $request->matchRest("DELETE", "/authorizations/:id", function ($id) use($request, $response, $storage, $rs) { $rs->requireScope("authorizations"); if (FALSE === $storage->deleteApproval($id, $rs->getResourceOwnerId())) { throw new ApiException("not_found", "the resource you are trying to delete does not exist"); } $response->setContent(Json::enc(array("ok" => true))); }); $request->matchRest("GET", "/authorizations/", function () use($request, $response, $storage, $rs) { $rs->requireScope("authorizations"); $data = $storage->getApprovals($rs->getResourceOwnerId()); $response->setContent(Json::enc($data)); }); $request->matchRest("GET", "/applications/", function () use($request, $response, $storage, $rs) { $rs->requireScope("applications"); // $rs->requireEntitlement("urn:x-oauth:entitlement:applications"); // do not require entitlement to list clients... $data = $storage->getClients(); $response->setContent(Json::enc($data)); }); $request->matchRest("DELETE", "/applications/:id", function ($id) use($request, $response, $storage, $rs) { $rs->requireScope("applications"); $rs->requireEntitlement("urn:x-oauth:entitlement:applications"); if (FALSE === $storage->deleteClient($id)) { throw new ApiException("not_found", "the resource you are trying to delete does not exist"); } $response->setContent(Json::enc(array("ok" => true))); }); $request->matchRest("GET", "/applications/:id", function ($id) use($request, $response, $storage, $rs) { $rs->requireScope("applications"); $rs->requireEntitlement("urn:x-oauth:entitlement:applications"); // FIXME: for now require entitlement as long as password hashing is not // implemented... $data = $storage->getClient($id); if (FALSE === $data) { throw new ApiException("not_found", "the resource you are trying to retrieve does not exist"); } $response->setContent(Json::enc($data)); }); $request->matchRest("POST", "/applications/", function () use($request, $response, $storage, $rs) { $rs->requireScope("applications"); $rs->requireEntitlement("urn:x-oauth:entitlement:applications"); try { $client = ClientRegistration::fromArray(Json::dec($request->getContent())); $data = $client->getClientAsArray(); // check to see if an application with this id already exists if (FALSE === $storage->getClient($data['id'])) { if (FALSE === $storage->addClient($data)) { throw new ApiException("invalid_request", "unable to add application"); } } else { throw new ApiException("invalid_request", "application already exists"); } $response->setStatusCode(201); $response->setContent(Json::enc(array("ok" => true))); } catch (ClientRegistrationException $e) { throw new ApiException("invalid_request", $e->getMessage()); } }); $request->matchRest("GET", "/stats/", function () use($request, $response, $storage, $rs) { $rs->requireScope("applications"); $rs->requireEntitlement("urn:x-oauth:entitlement:applications"); $data = $storage->getStats(); $response->setContent(Json::enc($data)); }); $request->matchRest("PUT", "/applications/:id", function ($id) use($request, $response, $storage, $rs) { $rs->requireScope("applications"); $rs->requireEntitlement("urn:x-oauth:entitlement:applications"); try { $client = ClientRegistration::fromArray(Json::dec($request->getContent())); $data = $client->getClientAsArray(); if ($data['id'] !== $id) { throw new ApiException("invalid_request", "resource does not match client id value"); } if (FALSE === $storage->updateClient($id, $data)) { throw new ApiException("invalid_request", "unable to update application"); } } catch (ClientRegistrationException $e) { throw new ApiException("invalid_request", $e->getMessage()); } $response->setContent(Json::enc(array("ok" => true))); }); $request->matchRestDefault(function ($methodMatch, $patternMatch) use($request, $response) { if (in_array($request->getRequestMethod(), $methodMatch)) { if (!$patternMatch) { throw new ApiException("not_found", "resource not found"); } } else { $response->setStatusCode(405); $response->setHeader("Allow", implode(",", $methodMatch)); } }); } catch (ResourceServerException $e) { $response->setStatusCode($e->getResponseCode()); if ("no_token" === $e->getMessage()) { // no authorization header is a special case, the client did not know // authentication was required, so tell it now without giving error message $hdr = 'Bearer realm="Resource Server"'; } else { $hdr = sprintf('Bearer realm="Resource Server",error="%s",error_description="%s"', $e->getMessage(), $e->getDescription()); } $response->setHeader("WWW-Authenticate", $hdr); $response->setContent(Json::enc(array("error" => $e->getMessage(), "error_description" => $e->getDescription()))); if (NULL !== $this->_logger) { $this->_logger->logFatal($e->getLogMessage(TRUE) . PHP_EOL . $request . PHP_EOL . $response); } } catch (ApiException $e) { $response->setStatusCode($e->getResponseCode()); $response->setContent(Json::enc(array("error" => $e->getMessage(), "error_description" => $e->getDescription()))); if (NULL !== $this->_logger) { $this->_logger->logFatal($e->getLogMessage(TRUE) . PHP_EOL . $request . PHP_EOL . $response); } } return $response; }
<?php require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . "vendor" . DIRECTORY_SEPARATOR . "autoload.php"; use RestService\Utils\Config; use OAuth\PdoOAuthStorage; use OAuth\ClientRegistration; use RestService\Utils\Json; $config = new Config(dirname(__DIR__) . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "oauth.ini"); $storage = new PdoOAuthStorage($config); $storage->initDatabase(); if ($argc !== 2) { echo "ERROR: specify manifest file or URL to parse" . PHP_EOL; die; } $manifestFile = $argv[1]; $fileContents = file_get_contents($manifestFile); $data = Json::dec($fileContents); if (NULL === $data || !is_array($data)) { echo "ERROR: manifest seems to be in wrong format" . PHP_EOL; die; } foreach ($data as $d) { // go over all app entries if (FALSE === $storage->getClient($d['key'])) { echo "Adding '" . $d['name'] . "'..." . PHP_EOL; $x = array("id" => $d['key'], "name" => $d['name'], "description" => $d['description'], "secret" => NULL, "type" => "user_agent_based_application", "icon" => $d['icons']['128'], "allowed_scope" => implode(" ", $d['permissions']), "redirect_uri" => $d['app']['launch']['web_url']); $y = ClientRegistration::fromArray($x); $storage->addClient($y->getClientAsArray()); } }
private function _handleAuthorize(IResourceOwner $resourceOwner, array $get) { try { $clientId = Utils::getParameter($get, 'client_id'); $responseType = Utils::getParameter($get, 'response_type'); $redirectUri = Utils::getParameter($get, 'redirect_uri'); // FIXME: scope can never be empty, if the client requests no scope we should have a default scope! $scope = new Scope(Utils::getParameter($get, 'scope')); $state = Utils::getParameter($get, 'state'); if (NULL === $clientId) { throw new ResourceOwnerException('client_id missing'); } if (NULL === $responseType) { throw new ResourceOwnerException('response_type missing'); } $client = $this->_storage->getClient($clientId); if (FALSE === $client) { throw new ResourceOwnerException('client not registered'); } if (NULL !== $redirectUri) { if ($client['redirect_uri'] !== $redirectUri) { throw new ResourceOwnerException('specified redirect_uri not the same as registered redirect_uri'); } } // we need to make sure the client can only request the grant types belonging to its profile $allowedClientProfiles = array("web_application" => array("code"), "native_application" => array("token", "code"), "user_agent_based_application" => array("token")); if (!in_array($responseType, $allowedClientProfiles[$client['type']])) { throw new ClientException("unsupported_response_type", "response_type not supported by client profile", $client, $state); } if (!$scope->isSubsetOf(new Scope($client['allowed_scope']))) { throw new ClientException("invalid_scope", "not authorized to request this scope", $client, $state); } $this->_storage->updateResourceOwner($resourceOwner); $approvedScope = $this->_storage->getApprovalByResourceOwnerId($clientId, $resourceOwner->getId()); if (FALSE === $approvedScope || FALSE === $scope->isSubsetOf(new Scope($approvedScope['scope']))) { $ar = new AuthorizeResult(AuthorizeResult::ASK_APPROVAL); $ar->setClient(ClientRegistration::fromArray($client)); $ar->setScope($scope); return $ar; } else { if ("token" === $responseType) { // implicit grant // FIXME: return existing access token if it exists for this exact client, resource owner and scope? $accessToken = Utils::randomHex(16); $this->_storage->storeAccessToken($accessToken, time(), $clientId, $resourceOwner->getId(), $scope->getScope(), $this->_config->getValue('accessTokenExpiry')); $token = array("access_token" => $accessToken, "expires_in" => $this->_config->getValue('accessTokenExpiry'), "token_type" => "bearer"); $s = $scope->getScope(); if (!empty($s)) { $token += array("scope" => $s); } if (NULL !== $state) { $token += array("state" => $state); } $ar = new AuthorizeResult(AuthorizeResult::REDIRECT); $ar->setRedirectUri(new Uri($client['redirect_uri'] . "#" . http_build_query($token))); return $ar; } else { // authorization code grant $authorizationCode = Utils::randomHex(16); $this->_storage->storeAuthorizationCode($authorizationCode, $resourceOwner->getId(), time(), $clientId, $redirectUri, $scope->getScope()); $token = array("code" => $authorizationCode); if (NULL !== $state) { $token += array("state" => $state); } $ar = new AuthorizeResult(AuthorizeResult::REDIRECT); $separator = FALSE === strpos($client['redirect_uri'], "?") ? "?" : "&"; $ar->setRedirectUri(new Uri($client['redirect_uri'] . $separator . http_build_query($token))); return $ar; } } } catch (ScopeException $e) { throw new ClientException("invalid_scope", "malformed scope", $client, $state); } }
<?php require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . "vendor" . DIRECTORY_SEPARATOR . "autoload.php"; use RestService\Utils\Config; use OAuth\PdoOAuthStorage; use OAuth\ClientRegistration; use RestService\Utils\Json; $config = new Config(dirname(__DIR__) . DIRECTORY_SEPARATOR . "config" . DIRECTORY_SEPARATOR . "oauth.ini"); $storage = new PdoOAuthStorage($config); if ($argc !== 2) { echo "ERROR: please specify file with client registration information" . PHP_EOL; die; } $registrationFile = $argv[1]; if (!file_exists($registrationFile) || !is_file($registrationFile) || !is_readable($registrationFile)) { echo "ERROR: unable to read client registration file" . PHP_EOL; die; } $registration = Json::dec(file_get_contents($registrationFile)); foreach ($registration as $r) { // first load it in ClientRegistration object to check it... $cr = ClientRegistration::fromArray($r); if (FALSE === $storage->getClient($cr->getId())) { // does not exist yet, install echo "Adding '" . $cr->getName() . "'..." . PHP_EOL; $storage->addClient($cr->getClientAsArray()); } }