use of org.keycloak.TokenVerifier in project keycloak by keycloak.
the class PreAuthActionsHandler method verifyAdminRequest.
protected JWSInput verifyAdminRequest() throws Exception {
if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) {
log.warn("SSL is required for adapter admin action");
facade.getResponse().sendError(403, "ssl required");
return null;
}
String token = StreamUtil.readString(facade.getRequest().getInputStream());
if (token == null) {
log.warn("admin request failed, no token");
facade.getResponse().sendError(403, "no token");
return null;
}
try {
// Check just signature. Other things checked in validateAction
TokenVerifier tokenVerifier = AdapterTokenVerifier.createVerifier(token, deployment, false, JsonWebToken.class);
tokenVerifier.verify();
return new JWSInput(token);
} catch (VerificationException ignore) {
log.warn("admin request failed, unable to verify token: " + ignore.getMessage());
if (log.isDebugEnabled()) {
log.debug(ignore.getMessage(), ignore);
}
facade.getResponse().sendError(403, "token failed verification");
return null;
}
}
use of org.keycloak.TokenVerifier in project keycloak by keycloak.
the class ClientRegistrationTokenUtils method verifyToken.
public static TokenVerification verifyToken(KeycloakSession session, RealmModel realm, String token) {
if (token == null) {
return TokenVerification.error(new RuntimeException("Missing token"));
}
String kid;
JsonWebToken jwt;
try {
TokenVerifier<JsonWebToken> verifier = TokenVerifier.create(token, JsonWebToken.class).withChecks(new TokenVerifier.RealmUrlCheck(getIssuer(session, realm)), TokenVerifier.IS_ACTIVE);
SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId());
verifier.verifierContext(verifierContext);
kid = verifierContext.getKid();
verifier.verify();
jwt = verifier.getToken();
} catch (VerificationException e) {
return TokenVerification.error(new RuntimeException("Failed decode token", e));
}
if (!(TokenUtil.TOKEN_TYPE_BEARER.equals(jwt.getType()) || TYPE_INITIAL_ACCESS_TOKEN.equals(jwt.getType()) || TYPE_REGISTRATION_ACCESS_TOKEN.equals(jwt.getType()))) {
return TokenVerification.error(new RuntimeException("Invalid type of token"));
}
return TokenVerification.success(kid, jwt);
}
use of org.keycloak.TokenVerifier in project keycloak by keycloak.
the class ClientTokenExchangeTest method testImpersonation.
@Test
@UncaughtServerErrorExpected
public void testImpersonation() throws Exception {
testingClient.server().run(ClientTokenExchangeTest::setupRealm);
oauth.realm(TEST);
oauth.clientId("client-exchanger");
Client httpClient = AdminClientUtil.createResteasyClient();
WebTarget exchangeUrl = httpClient.target(OAuthClient.AUTH_SERVER_ROOT).path("/realms").path(TEST).path("protocol/openid-connect/token");
System.out.println("Exchange url: " + exchangeUrl.getUri().toString());
OAuthClient.AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("secret", "user", "password");
String accessToken = tokenResponse.getAccessToken();
TokenVerifier<AccessToken> accessTokenVerifier = TokenVerifier.create(accessToken, AccessToken.class);
AccessToken token = accessTokenVerifier.parse().getToken();
Assert.assertEquals(token.getPreferredUsername(), "user");
Assert.assertTrue(token.getRealmAccess() == null || !token.getRealmAccess().isUserInRole("example"));
// client-exchanger can impersonate from token "user" to user "impersonated-user"
{
Response response = exchangeUrl.request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader("client-exchanger", "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, accessToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_SUBJECT, "impersonated-user")));
org.junit.Assert.assertEquals(200, response.getStatus());
AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
response.close();
String exchangedTokenString = accessTokenResponse.getToken();
TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
AccessToken exchangedToken = verifier.parse().getToken();
Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
Assert.assertNull(exchangedToken.getAudience());
Assert.assertEquals("impersonated-user", exchangedToken.getPreferredUsername());
Assert.assertNull(exchangedToken.getRealmAccess());
Object impersonatorRaw = exchangedToken.getOtherClaims().get("impersonator");
Assert.assertThat(impersonatorRaw, instanceOf(Map.class));
Map impersonatorClaim = (Map) impersonatorRaw;
Assert.assertEquals(token.getSubject(), impersonatorClaim.get("id"));
Assert.assertEquals("user", impersonatorClaim.get("username"));
}
// client-exchanger can impersonate from token "user" to user "impersonated-user" and to "target" client
{
Response response = exchangeUrl.request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader("client-exchanger", "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, accessToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_SUBJECT, "impersonated-user").param(OAuth2Constants.AUDIENCE, "target")));
org.junit.Assert.assertEquals(200, response.getStatus());
AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
response.close();
String exchangedTokenString = accessTokenResponse.getToken();
TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
AccessToken exchangedToken = verifier.parse().getToken();
Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
Assert.assertEquals("target", exchangedToken.getAudience()[0]);
Assert.assertEquals(exchangedToken.getPreferredUsername(), "impersonated-user");
Assert.assertTrue(exchangedToken.getRealmAccess().isUserInRole("example"));
}
}
use of org.keycloak.TokenVerifier in project keycloak by keycloak.
the class LoginActionsService method handleActionToken.
protected <T extends JsonWebToken & ActionTokenKeyModel> Response handleActionToken(String tokenString, String execution, String clientId, String tabId) {
T token;
ActionTokenHandler<T> handler;
ActionTokenContext<T> tokenContext;
String eventError = null;
String defaultErrorMessage = null;
AuthenticationSessionModel authSession = null;
// Setup client, so error page will contain "back to application" link
ClientModel client = null;
if (clientId != null) {
client = realm.getClientByClientId(clientId);
}
AuthenticationSessionManager authenticationSessionManager = new AuthenticationSessionManager(session);
if (client != null) {
session.getContext().setClient(client);
authSession = authenticationSessionManager.getCurrentAuthenticationSession(realm, client, tabId);
}
event.event(EventType.EXECUTE_ACTION_TOKEN);
// First resolve action token handler
try {
if (tokenString == null) {
throw new ExplainedTokenVerificationException(null, Errors.NOT_ALLOWED, Messages.INVALID_REQUEST);
}
TokenVerifier<DefaultActionTokenKey> tokenVerifier = TokenVerifier.create(tokenString, DefaultActionTokenKey.class);
DefaultActionTokenKey aToken = tokenVerifier.getToken();
event.detail(Details.TOKEN_ID, aToken.getId()).detail(Details.ACTION, aToken.getActionId()).user(aToken.getUserId());
handler = resolveActionTokenHandler(aToken.getActionId());
eventError = handler.getDefaultEventError();
defaultErrorMessage = handler.getDefaultErrorMessage();
if (!realm.isEnabled()) {
throw new ExplainedTokenVerificationException(aToken, Errors.REALM_DISABLED, Messages.REALM_NOT_ENABLED);
}
if (!checkSsl()) {
throw new ExplainedTokenVerificationException(aToken, Errors.SSL_REQUIRED, Messages.HTTPS_REQUIRED);
}
TokenVerifier<DefaultActionTokenKey> verifier = tokenVerifier.withChecks(// Token introspection checks
TokenVerifier.IS_ACTIVE, new TokenVerifier.RealmUrlCheck(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())), ACTION_TOKEN_BASIC_CHECKS);
String kid = verifier.getHeader().getKeyId();
String algorithm = verifier.getHeader().getAlgorithm().name();
SignatureVerifierContext signatureVerifier = session.getProvider(SignatureProvider.class, algorithm).verifier(kid);
verifier.verifierContext(signatureVerifier);
verifier.verify();
token = TokenVerifier.create(tokenString, handler.getTokenClass()).getToken();
} catch (TokenNotActiveException ex) {
if (authSession != null) {
event.clone().error(Errors.EXPIRED_CODE);
String flowPath = authSession.getClientNote(AuthorizationEndpointBase.APP_INITIATED_FLOW);
if (flowPath == null) {
flowPath = AUTHENTICATE_PATH;
}
AuthenticationProcessor.resetFlow(authSession, flowPath);
// Process correct flow
return processFlowFromPath(flowPath, authSession, Messages.EXPIRED_ACTION_TOKEN_SESSION_EXISTS);
}
return handleActionTokenVerificationException(null, ex, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION_TOKEN_NO_SESSION);
} catch (ExplainedTokenVerificationException ex) {
return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
} catch (ExplainedVerificationException ex) {
return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
} catch (VerificationException ex) {
return handleActionTokenVerificationException(null, ex, eventError, defaultErrorMessage);
}
// Now proceed with the verification and handle the token
tokenContext = new ActionTokenContext(session, realm, session.getContext().getUri(), clientConnection, request, event, handler, execution, this::processFlow, this::brokerLoginFlow);
try {
String tokenAuthSessionCompoundId = handler.getAuthenticationSessionIdFromToken(token, tokenContext, authSession);
if (tokenAuthSessionCompoundId != null) {
// This can happen if the token contains ID but user opens the link in a new browser
String sessionId = AuthenticationSessionCompoundId.encoded(tokenAuthSessionCompoundId).getRootSessionId();
LoginActionsServiceChecks.checkNotLoggedInYet(tokenContext, authSession, sessionId);
}
if (authSession == null) {
authSession = handler.startFreshAuthenticationSession(token, tokenContext);
tokenContext.setAuthenticationSession(authSession, true);
} else if (tokenAuthSessionCompoundId == null || !LoginActionsServiceChecks.doesAuthenticationSessionFromCookieMatchOneFromToken(tokenContext, authSession, tokenAuthSessionCompoundId)) {
// There exists an authentication session but no auth session ID was received in the action token
logger.debugf("Authentication session in progress but no authentication session ID was found in action token %s, restarting.", token.getId());
authenticationSessionManager.removeAuthenticationSession(realm, authSession, false);
authSession = handler.startFreshAuthenticationSession(token, tokenContext);
tokenContext.setAuthenticationSession(authSession, true);
processLocaleParam(authSession);
}
initLoginEvent(authSession);
event.event(handler.eventType());
LoginActionsServiceChecks.checkIsUserValid(token, tokenContext);
LoginActionsServiceChecks.checkIsClientValid(token, tokenContext);
session.getContext().setClient(authSession.getClient());
TokenVerifier.createWithoutSignature(token).withChecks(handler.getVerifiers(tokenContext)).verify();
authSession = tokenContext.getAuthenticationSession();
event = tokenContext.getEvent();
event.event(handler.eventType());
if (!handler.canUseTokenRepeatedly(token, tokenContext)) {
LoginActionsServiceChecks.checkTokenWasNotUsedYet(token, tokenContext);
authSession.setAuthNote(AuthenticationManager.INVALIDATE_ACTION_TOKEN, token.serializeKey());
}
authSession.setAuthNote(DefaultActionTokenKey.ACTION_TOKEN_USER_ID, token.getUserId());
authSession.setAuthNote(Constants.KEY, tokenString);
return handler.handleToken(token, tokenContext);
} catch (ExplainedTokenVerificationException ex) {
return handleActionTokenVerificationException(tokenContext, ex, ex.getErrorEvent(), ex.getMessage());
} catch (LoginActionsServiceException ex) {
Response response = ex.getResponse();
return response == null ? handleActionTokenVerificationException(tokenContext, ex, eventError, defaultErrorMessage) : response;
} catch (VerificationException ex) {
return handleActionTokenVerificationException(tokenContext, ex, eventError, defaultErrorMessage);
}
}
use of org.keycloak.TokenVerifier in project keycloak by keycloak.
the class ClientTokenExchangeTest method testExchange.
@Test
@UncaughtServerErrorExpected
public void testExchange() throws Exception {
testingClient.server().run(ClientTokenExchangeTest::setupRealm);
oauth.realm(TEST);
oauth.clientId("client-exchanger");
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "user", "password");
String accessToken = response.getAccessToken();
TokenVerifier<AccessToken> accessTokenVerifier = TokenVerifier.create(accessToken, AccessToken.class);
AccessToken token = accessTokenVerifier.parse().getToken();
Assert.assertEquals(token.getPreferredUsername(), "user");
Assert.assertTrue(token.getRealmAccess() == null || !token.getRealmAccess().isUserInRole("example"));
{
response = oauth.doTokenExchange(TEST, accessToken, "target", "client-exchanger", "secret");
String exchangedTokenString = response.getAccessToken();
TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
AccessToken exchangedToken = verifier.parse().getToken();
Assert.assertEquals("client-exchanger", exchangedToken.getIssuedFor());
Assert.assertEquals("target", exchangedToken.getAudience()[0]);
Assert.assertEquals(exchangedToken.getPreferredUsername(), "user");
Assert.assertTrue(exchangedToken.getRealmAccess().isUserInRole("example"));
}
{
response = oauth.doTokenExchange(TEST, accessToken, "target", "legal", "secret");
String exchangedTokenString = response.getAccessToken();
TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
AccessToken exchangedToken = verifier.parse().getToken();
Assert.assertEquals("legal", exchangedToken.getIssuedFor());
Assert.assertEquals("target", exchangedToken.getAudience()[0]);
Assert.assertEquals(exchangedToken.getPreferredUsername(), "user");
Assert.assertTrue(exchangedToken.getRealmAccess().isUserInRole("example"));
}
{
response = oauth.doTokenExchange(TEST, accessToken, "target", "illegal", "secret");
Assert.assertEquals(403, response.getStatusCode());
}
}
Aggregations