/** * Registration endpoint */ public function register() { $rand = new Random(); $response = new Response(); $this->checkHttps('error'); $this->logger->log(LogLevel::DEBUG, 'SimpleID\\Protocols\\Connect\\ConnectClientRegistrationModule->register'); // Access token OR rate limit if (!$this->isTokenAuthorized(self::CLIENT_REGISTRATION_INIT_SCOPE)) { $limiter = new RateLimiter('connect_register'); if (!$limiter->throttle()) { header('Retry-After: ' . $limiter->getInterval()); // We never display a log for rate limit errors $response->setError('invalid_request', 'client has been blocked from making further requests')->renderJSON(429); return; } } if (!$this->f3->exists('BODY')) { $response->setError('invalid_request')->renderJSON(); return; } $request = json_decode($this->f3->get('BODY'), true); if ($request == null) { $response->setError('invalid_request', 'unable to parse body')->renderJSON(); return; } if (!isset($request['redirect_uris'])) { $response->setError('invalid_redirect_uri', 'redirect_uris missing')->renderJSON(); return; } // Verify redirect_uri based on application_type $application_type = isset($request['application_type']) ? $request['application_type'] : 'web'; $grant_types = isset($request['grant_types']) ? $request['grant_types'] : array('authorization_code'); foreach ($request['redirect_uris'] as $redirect_uri) { $parts = parse_url($redirect_uri); if (isset($parts['fragment'])) { $response->setError('invalid_redirect_uri', 'redirect_uris cannot contain a fragment')->renderJSON(); return; } if ($application_type == 'web' && in_array('implicit', $grant_types)) { if (strtolower($parts['scheme']) != 'https' || strtolower($parts['host']) == 'localhost' && $parts['host'] == '127.0.0.1') { $response->setError('invalid_redirect_uri', 'implicit grant type must use https URIs')->renderJSON(); return; } } elseif ($application_type == 'native') { // Native Clients MUST only register redirect_uris using custom URI schemes or URLs using the http: scheme with localhost as the hostname. // Authorization Servers MAY place additional constraints on Native Clients. // Authorization Servers MAY reject Redirection URI values using the http scheme, other than the localhost case for Native Clients. // The Authorization Server MUST verify that all the registered redirect_uris conform to these constraints. This prevents sharing a Client ID across different types of Clients. if (strtolower($parts['scheme']) == 'http' && (strtolower($parts['host']) != 'localhost' || $parts['host'] != '127.0.0.1') || strtolower($parts['scheme']) == 'https') { $response->setError('invalid_redirect_uri', 'native clients cannot use https URIs')->renderJSON(); return; } } } // Verify sector_identifier_url $subject_type = isset($request['subject_type']) ? $request['subject_type'] : 'public'; if (isset($request['sector_identifier_uri'])) { if (!$this->verifySectorIdentifier($request['sector_identifier_uri'], $request['redirect_uris'])) { $response->setError('invalid_client_metadata', 'cannot verify sector_identifier_uri')->renderJSON(); return; } } $client = new ConnectDynamicClient(); $client_id = $client->getStoreID(); // Map data foreach ($request as $name => $value) { $parts = explode('#', $name, 2); $client_path = isset(self::$metadata_map[$parts[0]]) ? self::$metadata_map[$parts[0]] : 'connect.' . $parts[0]; if (isset($parts[1])) { $client_path .= '#' . $locale; } $client->pathSet($client_path, $value); } $client->fetchJWKs(); $response->loadData($request); $response->loadData(array('client_id' => $client->getStoreID(), 'registration_client_uri' => $this->getCanonicalURL('connect/client/' . $client->getStoreID()), 'client_id_issued_at' => time())); if ($client['oauth']['token_endpoint_auth_method'] != 'none') { $client->pathSet('oauth.client_secret', $rand->secret()); $response['client_secret'] = $client['oauth']['client_secret']; $response['client_secret_expires_at'] = 0; } $store = StoreManager::instance(); $store->saveClient($client); $this->logger->log(LogLevel::INFO, 'Created dynamic client: ' . $client_id); $auth = new Authorization($client, $client, self::CLIENT_REGISTRATION_ACCESS_SCOPE); $store->saveAuth($auth); $token = $auth->issueAccessToken(array(self::CLIENT_REGISTRATION_ACCESS_SCOPE)); $response['registration_access_token'] = $token['access_token']; $this->f3->status(201); $response->renderJSON(); }
/** * Processes an OAuth refresh token request. * * @param Request $request the OAuth token request * @param Response $response the response */ protected function tokenFromRefreshToken($request, $response) { $store = StoreManager::instance(); $client = $this->oauth->getClient(); if (!isset($request['refresh_token']) || $request['refresh_token'] == '') { $this->logger->log(LogLevel::ERROR, 'Token request failed: refresh_token not set'); $response->setError('invalid_request', 'refresh_token not set'); return; } $refresh_token = RefreshToken::decode($request['refresh_token']); if (!$refresh_token->isValid()) { $this->logger->log(LogLevel::ERROR, 'Token request failed: Refresh token not valid'); $response->setError('invalid_grant', 'Refresh token not valid'); return; } $authorization = $refresh_token->getAuthorization(); if ($authorization->getClient()->getStoreID() != $client->getStoreID()) { $this->logger->log(LogLevel::ERROR, 'Token request failed: this client (' . $client->getStoreID() . ') does not match the client stored in refresh token (' . $authorization->getClient()->getStoreID() . ')'); $response->setError('invalid_grant', 'this client does not match the client stored in refresh token'); $response->renderJSON(); return; } $authorization->revokeTokensFromSource($refresh_token); $scope = $refresh_token->getScope(); // If we issue, we delete the old refresh token so that it can't be used again $refresh_token->revoke(); $authorization->resetAuthState(); $store->saveAuth($authorization); $response->loadData($authorization->issueTokens($scope, SIMPLEID_SHORT_TOKEN_EXPIRES_IN, $refresh_token)); // Call modules $this->mgr->invokeAll('oAuthToken', 'refresh_token', $authorization, $request, $response, $scope); return $authorization; }