Skip to content
Snippets Groups Projects
Commit c295f8e7 authored by Sonia Zorba's avatar Sonia Zorba Committed by zonia3000
Browse files

#5 Completed refactoring of access token management. Fixed some issues

parent 5d10d9f6
No related branches found
No related tags found
No related merge requests found
<?php
namespace RAP;
/**
* RFC 6749 specify that in some situations the client must send an Authorization
* Basic header containing its credentials (access token in the authorization code
* flow and refresh token requests).
*/
class ClientAuthChecker {
private $locator;
public function __construct(Locator $locator) {
$this->locator = $locator;
}
public function validateClientAuth(): void {
$headers = apache_request_headers();
if (!isset($headers['Authorization'])) {
throw new UnauthorizedException("Missing Authorization header");
}
$authorizationHeader = explode(" ", $headers['Authorization']);
if ($authorizationHeader[0] === "Basic") {
$basic = explode(':', base64_decode($authorizationHeader[1]));
if (count($basic) !== 2) {
throw new BadRequestException("Malformed Basic-Auth header");
}
$clientId = $basic[0];
$clientSecret = $basic[1];
$client = $this->locator->getOAuth2ClientDAO()->getOAuth2ClientByClientId($clientId);
if ($client === null) {
throw new UnauthorizedException("Client '$clientId' not configured");
}
if ($clientSecret !== $client->secret) {
throw new UnauthorizedException("Invalid client secret");
}
} else {
throw new UnauthorizedException("Expected Basic authorization header");
}
}
}
...@@ -102,6 +102,14 @@ class Locator { ...@@ -102,6 +102,14 @@ class Locator {
return new TokenBuilder($this); return new TokenBuilder($this);
} }
public function getTokenChecker(): TokenChecker {
return new TokenChecker($this);
}
public function getClientAuthChecker(): ClientAuthChecker {
return new ClientAuthChecker($this);
}
/** /**
* Retrieve the SessionData object from the $_SESSION PHP variable. Create a * Retrieve the SessionData object from the $_SESSION PHP variable. Create a
* new one if it is necessary. * new one if it is necessary.
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
namespace RAP; namespace RAP;
use \Firebase\JWT\JWT;
class OAuth2RequestHandler { class OAuth2RequestHandler {
private $locator; private $locator;
...@@ -84,7 +82,9 @@ class OAuth2RequestHandler { ...@@ -84,7 +82,9 @@ class OAuth2RequestHandler {
. '?code=' . $code . '&scope=profile&state=' . $state; . '?code=' . $code . '&scope=profile&state=' . $state;
} else { } else {
// Implicit grant flow // Implicit grant flow
$idToken = $this->locator->getTokenBuilder()->getIdToken($tokenData, $nonce); $idToken = $this->locator->getTokenBuilder()->getIdToken($tokenData, function(& $jwt) use($nonce) {
$jwt['nonce'] = $nonce;
});
$redirectUrl = $session->getOAuth2RequestData()->redirectUrl . "#id_token=" . $idToken; $redirectUrl = $session->getOAuth2RequestData()->redirectUrl . "#id_token=" . $idToken;
} }
...@@ -93,6 +93,8 @@ class OAuth2RequestHandler { ...@@ -93,6 +93,8 @@ class OAuth2RequestHandler {
public function handleAccessTokenRequest($params): array { public function handleAccessTokenRequest($params): array {
$this->locator->getClientAuthChecker()->validateClientAuth();
if ($params['code'] === null) { if ($params['code'] === null) {
throw new BadRequestException("code id is required"); throw new BadRequestException("code id is required");
} }
...@@ -123,6 +125,8 @@ class OAuth2RequestHandler { ...@@ -123,6 +125,8 @@ class OAuth2RequestHandler {
public function handleRefreshTokenRequest($params): array { public function handleRefreshTokenRequest($params): array {
$this->locator->getClientAuthChecker()->validateClientAuth();
if ($params['refresh_token'] === null) { if ($params['refresh_token'] === null) {
throw new BadRequestException("refresh_token is required"); throw new BadRequestException("refresh_token is required");
} }
...@@ -138,7 +142,6 @@ class OAuth2RequestHandler { ...@@ -138,7 +142,6 @@ class OAuth2RequestHandler {
// Generating a new access token // Generating a new access token
$accessTokenData = new AccessTokenData(); $accessTokenData = new AccessTokenData();
$accessTokenData->token = base64_encode(bin2hex(openssl_random_pseudo_bytes(128)));
$accessTokenData->clientId = $refreshToken->clientId; $accessTokenData->clientId = $refreshToken->clientId;
$accessTokenData->userId = $refreshToken->userId; $accessTokenData->userId = $refreshToken->userId;
$accessTokenData->scope = $scope; $accessTokenData->scope = $scope;
...@@ -186,10 +189,7 @@ class OAuth2RequestHandler { ...@@ -186,10 +189,7 @@ class OAuth2RequestHandler {
$result['token_type'] = 'Bearer'; $result['token_type'] = 'Bearer';
$result['expires_in'] = $tokenData->expirationTime - time(); $result['expires_in'] = $tokenData->expirationTime - time();
$refreshToken = base64_encode(bin2hex(openssl_random_pseudo_bytes(128))); $result['refresh_token'] = $this->buildRefreshToken($tokenData);
$refreshTokenHash = hash('sha256', $refreshToken);
$this->storeRefreshTokenData($tokenData, $refreshTokenHash);
$result['refresh_token'] = $refreshToken;
if ($tokenData->scope !== null && in_array('openid', $tokenData->scope)) { if ($tokenData->scope !== null && in_array('openid', $tokenData->scope)) {
$result['id_token'] = $this->locator->getTokenBuilder()->getIdToken($tokenData); $result['id_token'] = $this->locator->getTokenBuilder()->getIdToken($tokenData);
...@@ -198,93 +198,82 @@ class OAuth2RequestHandler { ...@@ -198,93 +198,82 @@ class OAuth2RequestHandler {
return $result; return $result;
} }
private function storeRefreshTokenData(AccessTokenData $accessTokenData, string $refreshTokenHash): void {
$refreshToken = new RefreshTokenData();
$refreshToken->tokenHash = $refreshTokenHash;
$refreshToken->clientId = $accessTokenData->clientId;
$refreshToken->userId = $accessTokenData->userId;
$refreshToken->scope = $accessTokenData->scope;
$this->locator->getRefreshTokenDAO()->createRefreshTokenData($refreshToken);
}
/** /**
* Token introspection endpoint shouldn't be necessary when using OIDC (since * Token introspection endpoint shouldn't be necessary when using OIDC (since
* tokens are self-contained JWT). This function is kept here for compatibility * tokens are self-contained JWT). This function is kept here for compatibility
* with some libraries (e.g. Spring Security) but it could be removed in the * with some libraries (e.g. Spring Security) but it could be removed in the
* future. * future.
*/ */
public function handleCheckTokenRequest($token): array { public function handleCheckTokenRequest(): array {
// TODO: validate the token and expose data
$accessToken = $this->locator->getAccessTokenDAO()->getAccessToken($token);
if ($accessToken === null) {
throw new UnauthorizedException("Invalid access token");
}
$user = $this->locator->getUserDAO()->findUserById($accessToken->userId); $jwt = $this->locator->getTokenChecker()->validateToken();
$tokenData = $this->getTokenDataFromJwtObject($jwt);
$result = []; $result = [];
$result['exp'] = $accessToken->expirationTime - time(); $result['exp'] = $tokenData->expirationTime - time();
$result['user_name'] = $user->id; $result['user_name'] = $tokenData->userId;
$result['client_id'] = $accessToken->clientId; $result['client_id'] = $tokenData->clientId;
$result['refresh_token'] = $this->storeRefreshTokenData($accessToken); $result['access_token'] = $this->copyReceivedAccessToken();
$result['refresh_token'] = $this->buildRefreshToken($tokenData);
if ($accessToken->scope !== null) {
$result['scope'] = $accessToken->scope; if (isset($tokenData->scope) && count($tokenData->scope) > 0) {
if (in_array('openid', $accessToken->scope)) { $result['scope'] = $tokenData->scope;
$result['id_token'] = $this->locator->getTokenBuilder()->getIdToken($accessToken); if (in_array('openid', $tokenData->scope)) {
$result['id_token'] = $this->locator->getTokenBuilder()->getIdToken($tokenData);
} }
} }
return $result; return $result;
} }
public function validateToken(): void { private function copyReceivedAccessToken(): string {
$headers = apache_request_headers(); $headers = apache_request_headers();
return explode(" ", $headers['Authorization'])[1];
if (!isset($headers['Authorization'])) {
throw new BadRequestException("Missing Authorization header");
} }
$authorizationHeader = explode(" ", $headers['Authorization']); private function getTokenDataFromJwtObject($jwt): AccessTokenData {
if ($authorizationHeader[0] === "Bearer") {
$bearer_token = $authorizationHeader[1];
} else {
throw new BadRequestException("Invalid token type");
}
$accessToken = $this->locator->getAccessTokenDAO()->getAccessToken($bearer_token); $tokenData = new AccessTokenData();
if ($accessToken === null) { $tokenData->clientId = $this->getClientIdFromAudience($jwt);
$this->attemptJWTTokenValidation($bearer_token); $tokenData->userId = $jwt->sub;
} else if ($accessToken->isExpired()) { $tokenData->creationTime = $jwt->iat;
throw new UnauthorizedException("Access token is expired"); $tokenData->expirationTime = $jwt->exp;
} $tokenData->scope = explode(' ', $jwt->scope);
return $tokenData;
} }
private function attemptJWTTokenValidation($jwt): void { private function getClientIdFromAudience(object $jwt): string {
$jwtParts = explode('.', $jwt); if (!(isset($jwt->aud))) {
if (count($jwtParts) === 0) { throw new UnauthorizedException("Missing 'aud' claim in token");
throw new UnauthorizedException("Invalid token");
} }
$header = JWT::jsonDecode(JWT::urlsafeB64Decode($jwtParts[0])); $audience = $jwt->aud;
if (!isset($header->kid)) { if (is_array($audience)) {
throw new UnauthorizedException("Invalid token: missing kid in header"); if (count($audience) === 0) {
throw new UnauthorizedException("Token has empty audience");
} }
return $audience[0];
$keyPair = $this->locator->getJWKSDAO()->getRSAKeyPairById($header->kid); }
if ($keyPair === null) { return $audience;
throw new UnauthorizedException("Invalid kid: no key found");
} }
try { private function buildRefreshToken(AccessTokenData $tokenData): string {
JWT::decode($jwt, $keyPair->publicKey, [$keyPair->alg]); $refreshToken = base64_encode(bin2hex(openssl_random_pseudo_bytes(128)));
} catch (\Firebase\JWT\ExpiredException $ex) { $refreshTokenHash = hash('sha256', $refreshToken);
throw new UnauthorizedException("Access token is expired"); $this->storeRefreshTokenData($tokenData, $refreshTokenHash);
return $refreshToken;
} }
private function storeRefreshTokenData(AccessTokenData $accessTokenData, string $refreshTokenHash): void {
$refreshToken = new RefreshTokenData();
$refreshToken->tokenHash = $refreshTokenHash;
$refreshToken->clientId = $accessTokenData->clientId;
$refreshToken->userId = $accessTokenData->userId;
$refreshToken->scope = $accessTokenData->scope;
$this->locator->getRefreshTokenDAO()->createRefreshTokenData($refreshToken);
} }
} }
...@@ -12,16 +12,16 @@ class TokenBuilder { ...@@ -12,16 +12,16 @@ class TokenBuilder {
$this->locator = $locator; $this->locator = $locator;
} }
public function getIdToken(AccessTokenData $tokenData, string $nonce = null): string { public function getIdToken(AccessTokenData $tokenData, \Closure $jwtCustomizer = null): string {
$keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair(); $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair();
$payload = $this->createIdTokenPayloadArray($tokenData, $nonce); $payload = $this->createIdTokenPayloadArray($tokenData, $jwtCustomizer);
return JWT::encode($payload, $keyPair->privateKey, $keyPair->alg, $keyPair->keyId); return JWT::encode($payload, $keyPair->privateKey, $keyPair->alg, $keyPair->keyId);
} }
private function createIdTokenPayloadArray(AccessTokenData $tokenData, string $nonce = null) { private function createIdTokenPayloadArray(AccessTokenData $tokenData, \Closure $jwtCustomizer = null) {
$user = $this->locator->getUserDAO()->findUserById($tokenData->userId); $user = $this->locator->getUserDAO()->findUserById($tokenData->userId);
...@@ -34,10 +34,6 @@ class TokenBuilder { ...@@ -34,10 +34,6 @@ class TokenBuilder {
'aud' => $tokenData->clientId 'aud' => $tokenData->clientId
); );
if ($nonce !== null) {
$payloadArr['nonce'] = $nonce;
}
if (in_array("email", $tokenData->scope)) { if (in_array("email", $tokenData->scope)) {
$payloadArr['email'] = $user->getPrimaryEmail(); $payloadArr['email'] = $user->getPrimaryEmail();
} }
...@@ -49,14 +45,15 @@ class TokenBuilder { ...@@ -49,14 +45,15 @@ class TokenBuilder {
} }
} }
/*if ($tokenData->joinUser !== null) { if ($jwtCustomizer !== null) {
$payloadArr['alt_sub'] = strval($tokenData->joinUser); // Add additional custom claims
}*/ $jwtCustomizer($payloadArr);
}
return $payloadArr; return $payloadArr;
} }
public function getAccessToken(AccessTokenData $tokenData) { public function getAccessToken(AccessTokenData $tokenData, \Closure $jwtCustomizer = null) {
$keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair(); $keyPair = $this->locator->getJWKSDAO()->getNewestKeyPair();
...@@ -67,8 +64,13 @@ class TokenBuilder { ...@@ -67,8 +64,13 @@ class TokenBuilder {
'sub' => strval($user->id), 'sub' => strval($user->id),
'iat' => intval($tokenData->creationTime), 'iat' => intval($tokenData->creationTime),
'exp' => intval($tokenData->expirationTime), 'exp' => intval($tokenData->expirationTime),
'aud' => $this->getAudience($tokenData) 'aud' => $this->getAudience($tokenData),
'scope' => implode(' ', $tokenData->scope)
); );
if ($jwtCustomizer !== null) {
// Add additional custom claims
$jwtCustomizer($payload);
}
return JWT::encode($payload, $keyPair->privateKey, $keyPair->alg, $keyPair->keyId); return JWT::encode($payload, $keyPair->privateKey, $keyPair->alg, $keyPair->keyId);
} }
......
<?php
namespace RAP;
use \Firebase\JWT\JWT;
class TokenChecker {
private $locator;
public function __construct(Locator $locator) {
$this->locator = $locator;
}
public function validateToken(): object {
$headers = apache_request_headers();
if (!isset($headers['Authorization'])) {
throw new BadRequestException("Missing Authorization header");
}
$authorizationHeader = explode(" ", $headers['Authorization']);
if ($authorizationHeader[0] === "Bearer") {
$token = $authorizationHeader[1];
} else {
throw new BadRequestException("Invalid token type");
}
return $this->attemptJWTTokenValidation($token);
}
private function attemptJWTTokenValidation($jwt): object {
$jwtParts = explode('.', $jwt);
if (count($jwtParts) === 0) {
throw new UnauthorizedException("Invalid token");
}
$header = JWT::jsonDecode(JWT::urlsafeB64Decode($jwtParts[0]));
if (!isset($header->kid)) {
throw new UnauthorizedException("Invalid token: missing kid in header");
}
$keyPair = $this->locator->getJWKSDAO()->getRSAKeyPairById($header->kid);
if ($keyPair === null) {
throw new UnauthorizedException("Invalid kid: no key found");
}
try {
return JWT::decode($jwt, $keyPair->publicKey, [$keyPair->alg]);
} catch (\Firebase\JWT\ExpiredException $ex) {
throw new UnauthorizedException("Access token is expired");
}
}
public function checkScope(object $tokenData, string $desiredScope): void {
if (!(isset($tokenData->scope))) {
throw new UnauthorizedException("Missing 'scope' claim in access token");
}
$scopes = explode(' ', $tokenData->scope);
foreach ($scopes as $scope) {
if ($scope === $desiredScope) {
return;
}
}
throw new UnauthorizedException("Scope '$desiredScope' is required for performing this action");
}
}
...@@ -71,7 +71,6 @@ class UserHandler { ...@@ -71,7 +71,6 @@ class UserHandler {
// Call Grouper for moving groups and privileges from one user to the other // Call Grouper for moving groups and privileges from one user to the other
if (isset($this->locator->config->gms)) { if (isset($this->locator->config->gms)) {
// TODO: change with new GMS
//create cURL connection //create cURL connection
$conn = curl_init($this->locator->config->gms->joinEndpoint); $conn = curl_init($this->locator->config->gms->joinEndpoint);
...@@ -81,7 +80,7 @@ class UserHandler { ...@@ -81,7 +80,7 @@ class UserHandler {
curl_setopt($conn, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($conn, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($conn, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($conn, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($conn, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' curl_setopt($conn, CURLOPT_HTTPHEADER, ['Authorization: Bearer '
. $this->getJoinIdToken($userId1, $userId2)]); . $this->getJoinAccessToken($userId1, $userId2)]);
//set data to be posted //set data to be posted
curl_setopt($conn, CURLOPT_POST, 1); curl_setopt($conn, CURLOPT_POST, 1);
...@@ -113,19 +112,20 @@ class UserHandler { ...@@ -113,19 +112,20 @@ class UserHandler {
return $user1; return $user1;
} }
private function getJoinIdToken(int $userId1, int $userId2): string { private function getJoinAccessToken(int $userId1, int $userId2): string {
$gmsId = $this->locator->config->gms->id; $gmsId = $this->locator->config->gms->id;
$accessToken = new AccessToken(); $accessToken = new AccessTokenData();
$accessToken->clientId = $gmsId; $accessToken->clientId = $gmsId;
$accessToken->userId = $userId1; $accessToken->userId = $userId1;
$accessToken->joinUser = $userId2;
// shorter expiration // shorter expiration
$accessToken->expirationTime = $accessToken->creationTime + 100; $accessToken->expirationTime = $accessToken->creationTime + 100;
$accessToken->scope = ['openid']; $accessToken->scope = ['openid'];
return $this->locator->getTokenBuilder()->getIdToken($accessToken); return $this->locator->getTokenBuilder()->getAccessToken($accessToken, function(& $jwt) use($userId2) {
$jwt['alt_sub'] = strval($userId2);
});
} }
} }
...@@ -24,7 +24,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -24,7 +24,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
return $clients; return $clients;
} }
private function getClientsMap(PDO $dbh): array { private function getClientsMap(\PDO $dbh): array {
// Load clients info // Load clients info
$queryClient = "SELECT id, title, icon, client, secret, redirect_url, scope, home_page, show_in_home FROM oauth2_client"; $queryClient = "SELECT id, title, icon, client, secret, redirect_url, scope, home_page, show_in_home FROM oauth2_client";
...@@ -50,7 +50,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -50,7 +50,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
return $clientsMap; return $clientsMap;
} }
private function loadAuthenticationMethods(PDO $dbh, array $clientsMap): void { private function loadAuthenticationMethods(\PDO $dbh, array $clientsMap): void {
$queryAuthNMethods = "SELECT client_id, auth_method FROM oauth2_client_auth_methods"; $queryAuthNMethods = "SELECT client_id, auth_method FROM oauth2_client_auth_methods";
...@@ -63,7 +63,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO { ...@@ -63,7 +63,7 @@ class MySQLOAuth2ClientDAO extends BaseMySQLDAO implements OAuth2ClientDAO {
} }
} }
private function loadScopeAudienceMapping(PDO $dbh, array $clientsMap): void { private function loadScopeAudienceMapping(\PDO $dbh, array $clientsMap): void {
$query = "SELECT client_id, scope, audience FROM oauth2_client_scope_audience_mapping"; $query = "SELECT client_id, scope, audience FROM oauth2_client_scope_audience_mapping";
......
...@@ -85,7 +85,6 @@ class LoginHandler { ...@@ -85,7 +85,6 @@ class LoginHandler {
$action = $session->getAction(); $action = $session->getAction();
if ($action === 'join') { if ($action === 'join') {
if ($session->getUser()->id !== $user->id) { if ($session->getUser()->id !== $user->id) {
$user = $this->locator->getUserHandler()->joinUsers($session->getUser(), $user); $user = $this->locator->getUserHandler()->joinUsers($session->getUser(), $user);
} }
......
...@@ -49,11 +49,6 @@ Flight::route('/', function() { ...@@ -49,11 +49,6 @@ Flight::route('/', function() {
$authPageModel = new \RAP\AuthPageModel($locator, $client); $authPageModel = new \RAP\AuthPageModel($locator, $client);
renderMainPage($authPageModel); renderMainPage($authPageModel);
break; break;
/*case "admin":
$client = new \RAP\InternalClient('admin');
$authPageModel = new \RAP\AuthPageModel($locator, $client);
renderMainPage($authPageModel);
break;*/
default: default:
session_destroy(); session_destroy();
$clients = $locator->getOAuth2ClientDAO()->getOAuth2Clients(); $clients = $locator->getOAuth2ClientDAO()->getOAuth2Clients();
...@@ -127,25 +122,8 @@ Flight::route('POST /auth/oauth2/check_token', function() { ...@@ -127,25 +122,8 @@ Flight::route('POST /auth/oauth2/check_token', function() {
global $locator; global $locator;
$headers = apache_request_headers();
if (!isset($headers['Authorization'])) {
throw new \RAP\BadRequestException("Missing Authorization header");
}
$authorizationHeader = explode(" ", $headers['Authorization']);
if ($authorizationHeader[0] === "Bearer") {
$token = $authorizationHeader[1];
} else {
throw new \RAP\BadRequestException("Invalid token type");
}
if ($token === null) {
throw new \RAP\BadRequestException("Access token is required");
}
$requestHandler = new \RAP\OAuth2RequestHandler($locator); $requestHandler = new \RAP\OAuth2RequestHandler($locator);
$result = $requestHandler->handleCheckTokenRequest($token); $result = $requestHandler->handleCheckTokenRequest();
Flight::json($result); Flight::json($result);
}); });
......
...@@ -13,7 +13,8 @@ Flight::route('GET ' . $WS_PREFIX . '/user/@userId', function($userId) { ...@@ -13,7 +13,8 @@ Flight::route('GET ' . $WS_PREFIX . '/user/@userId', function($userId) {
global $locator; global $locator;
$locator->getOAuth2RequestHandler()->validateToken(); $token = $locator->getTokenChecker()->validateToken();
$locator->getTokenChecker()->checkScope($token, 'read:rap');
$user = $locator->getUserDAO()->findUserById($userId); $user = $locator->getUserDAO()->findUserById($userId);
if ($user !== null) { if ($user !== null) {
...@@ -31,7 +32,8 @@ Flight::route('GET ' . $WS_PREFIX . '/user', function() { ...@@ -31,7 +32,8 @@ Flight::route('GET ' . $WS_PREFIX . '/user', function() {
global $locator; global $locator;
$locator->getOAuth2RequestHandler()->validateToken(); $token = $locator->getTokenChecker()->validateToken();
$locator->getTokenChecker()->checkScope($token, 'read:rap');
$searchText = Flight::request()->query['search']; $searchText = Flight::request()->query['search'];
if ($searchText !== null) { if ($searchText !== null) {
...@@ -51,13 +53,14 @@ Flight::route('GET ' . $WS_PREFIX . '/user', function() { ...@@ -51,13 +53,14 @@ Flight::route('GET ' . $WS_PREFIX . '/user', function() {
/** /**
* Create new user from identity data. Return the new user encoded in JSON. * Create new user from identity data. Return the new user encoded in JSON.
* This can be used to automatically import users without they explicitly * This can be used to automatically import users without they explicitly
* register (this is done for INAF eduGAIN users readling directly from LDAP). * register (this is done for INAF eduGAIN users reading directly from LDAP).
*/ */
Flight::route('POST ' . $WS_PREFIX . '/user', function() { Flight::route('POST ' . $WS_PREFIX . '/user', function() {
global $locator; global $locator;
$locator->getOAuth2RequestHandler()->validateToken(); $token = $locator->getTokenChecker()->validateToken();
$locator->getTokenChecker()->checkScope($token, 'write:rap');
$postData = Flight::request()->data; $postData = Flight::request()->data;
......
...@@ -20,7 +20,7 @@ include 'include/header.php'; ...@@ -20,7 +20,7 @@ include 'include/header.php';
<div class="col-sm-2"> <div class="col-sm-2">
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<a class="btn btn-success disabled" id="join-btn" href="<?php echo $contextRoot; ?>?action=join" title="Perform an additional login to join your identities" data-toggle="tooltip" data-placement="bottom"> <a class="btn btn-success" id="join-btn" href="<?php echo $contextRoot; ?>?action=join" title="Perform an additional login to join your identities" data-toggle="tooltip" data-placement="bottom">
Join with another identity Join with another identity
</a> </a>
</div> </div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment