protected boolean corsRequest() { if (!deployment.isCors()) return false; KeycloakSecurityContext securityContext = facade.getSecurityContext(); String origin = facade.getRequest().getHeader(CorsHeaders.ORIGIN); String requestOrigin = UriUtils.getOrigin(facade.getRequest().getURI()); log.debugv("Origin: {0} uri: {1}", origin, facade.getRequest().getURI()); if (securityContext != null && origin != null && !origin.equals(requestOrigin)) { AccessToken token = securityContext.getToken(); Set<String> allowedOrigins = token.getAllowedOrigins(); if (log.isDebugEnabled()) { for (String a : allowedOrigins) log.debug(" " + a); } if (allowedOrigins == null || (!allowedOrigins.contains("*") && !allowedOrigins.contains(origin))) { if (allowedOrigins == null) { log.debugv("allowedOrigins was null in token"); } else { log.debugv("allowedOrigins did not contain origin"); } facade.getResponse().setStatus(403); facade.getResponse().end(); return true; } log.debugv("returning origin: {0}", origin); facade.getResponse().setStatus(200); facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin); facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } else { log.debugv( "cors validation not needed as we're not a secure session or origin header was null: {0}", facade.getRequest().getURI()); } return false; }
protected AdminAuth authenticateRealmAdminRequest(HttpHeaders headers) { String tokenString = authManager.extractAuthorizationHeaderToken(headers); if (tokenString == null) throw new UnauthorizedException("Bearer"); JWSInput input = new JWSInput(tokenString); AccessToken token; try { token = input.readJsonContent(AccessToken.class); } catch (IOException e) { throw new UnauthorizedException("Bearer token format error"); } String realmName = token.getAudience(); RealmManager realmManager = new RealmManager(session); RealmModel realm = realmManager.getRealmByName(realmName); if (realm == null) { throw new UnauthorizedException("Unknown realm in token"); } AuthenticationManager.AuthResult authResult = authManager.authenticateBearerToken(session, realm, uriInfo, clientConnection, headers); if (authResult == null) { logger.debug("Token not valid"); throw new UnauthorizedException("Bearer"); } ClientModel client = realm.findClient(token.getIssuedFor()); if (client == null) { throw new NotFoundException("Could not find client for authorization"); } return new AdminAuth(realm, authResult.getToken(), authResult.getUser(), client); }
private void loginToTokenMinTtlApp() { tokenMinTTLPage.navigateTo(); testRealmLoginPage.form().waitForUsernameInputPresent(); assertCurrentUrlStartsWithLoginUrlOf(testRealmPage); testRealmLoginPage.form().login("*****@*****.**", "password"); assertCurrentUrlEquals(tokenMinTTLPage); AccessToken token = tokenMinTTLPage.getAccessToken(); Assert.assertEquals("*****@*****.**", token.getPreferredUsername()); }
@Test public void changeClientIdTest() throws Exception { keycloakRule.update( new KeycloakRule.KeycloakSetup() { @Override public void config( RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { ClientModel app = appRealm.getClientByClientId("service-account-cl"); app.setClientId("updated-client"); } }); oauth.clientId("updated-client"); OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("secret1"); assertEquals(200, response.getStatusCode()); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken()); Assert.assertEquals( "updated-client", accessToken.getOtherClaims().get(ServiceAccountConstants.CLIENT_ID)); // Username still same. Client ID changed events .expectClientLogin() .client("updated-client") .user(userId) .session(accessToken.getSessionState()) .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) .detail( Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl") .assertEvent(); // Revert change keycloakRule.update( new KeycloakRule.KeycloakSetup() { @Override public void config( RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { ClientModel app = appRealm.getClientByClientId("updated-client"); app.setClientId("service-account-cl"); } }); }
@Override public KeycloakSecurityContext getKeycloakSecurityContext() { String tokenString = ""; AccessToken accessToken = new AccessToken(); accessToken.setName(name); accessToken.setEmail(email); accessToken.setOtherClaims("groups", groups); String idTokenString = ""; IDToken idToken = new IDToken(); return new KeycloakSecurityContext(tokenString, accessToken, idTokenString, idToken); }
@Test public void clientCredentialsLogout() throws Exception { oauth.clientId("service-account-cl"); OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("secret1"); assertEquals(200, response.getStatusCode()); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken()); events .expectClientLogin() .client("service-account-cl") .user(userId) .session(accessToken.getSessionState()) .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) .detail( Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl") .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID) .assertEvent(); HttpResponse logoutResponse = oauth.doLogout(response.getRefreshToken(), "secret1"); assertEquals(204, logoutResponse.getStatusLine().getStatusCode()); events .expectLogout(accessToken.getSessionState()) .client("service-account-cl") .user(userId) .removeDetail(Details.REDIRECT_URI) .assertEvent(); response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret1"); assertEquals(400, response.getStatusCode()); assertEquals("invalid_grant", response.getError()); events .expectRefresh(refreshToken.getId(), refreshToken.getSessionState()) .client("service-account-cl") .user(userId) .removeDetail(Details.TOKEN_ID) .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID) .error(Errors.INVALID_TOKEN) .assertEvent(); }
protected void addComposites(AccessToken token, RoleModel role) { AccessToken.Access access = null; if (role.getContainer() instanceof RealmModel) { access = token.getRealmAccess(); if (token.getRealmAccess() == null) { access = new AccessToken.Access(); token.setRealmAccess(access); } else if (token.getRealmAccess().getRoles() != null && token.getRealmAccess().isUserInRole(role.getName())) return; } else { ClientModel app = (ClientModel) role.getContainer(); access = token.getResourceAccess(app.getClientId()); if (access == null) { access = token.addAccess(app.getClientId()); if (app.isSurrogateAuthRequired()) access.verifyCaller(true); } else if (access.isUserInRole(role.getName())) return; } access.addRole(role.getName()); if (!role.isComposite()) return; for (RoleModel composite : role.getComposites()) { addComposites(token, composite); } }
public void verifyAccess(AccessToken token, AccessToken newToken) throws OAuthErrorException { if (token.getRealmAccess() != null) { if (newToken.getRealmAccess() == null) throw new OAuthErrorException( OAuthErrorException.INVALID_SCOPE, "User no long has permission for realm roles"); for (String roleName : token.getRealmAccess().getRoles()) { if (!newToken.getRealmAccess().getRoles().contains(roleName)) { throw new OAuthErrorException( OAuthErrorException.INVALID_SCOPE, "User no long has permission for realm role: " + roleName); } } } if (token.getResourceAccess() != null) { for (Map.Entry<String, AccessToken.Access> entry : token.getResourceAccess().entrySet()) { AccessToken.Access appAccess = newToken.getResourceAccess(entry.getKey()); if (appAccess == null && !entry.getValue().getRoles().isEmpty()) { throw new OAuthErrorException( OAuthErrorException.INVALID_SCOPE, "User or client no longer has role permissions for client key: " + entry.getKey()); } for (String roleName : entry.getValue().getRoles()) { if (!appAccess.getRoles().contains(roleName)) { throw new OAuthErrorException( OAuthErrorException.INVALID_SCOPE, "User no long has permission for client role " + roleName); } } } } }
@Test public void grantAccessTokenLogout() throws Exception { oauth.clientId("resource-owner"); OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password"); assertEquals(200, response.getStatusCode()); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken()); events .expectLogin() .client("resource-owner") .session(accessToken.getSessionState()) .detail(Details.AUTH_METHOD, "oauth_credentials") .detail(Details.RESPONSE_TYPE, "token") .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) .removeDetail(Details.CODE_ID) .removeDetail(Details.REDIRECT_URI) .removeDetail(Details.CONSENT) .assertEvent(); HttpResponse logoutResponse = oauth.doLogout(response.getRefreshToken(), "secret"); assertEquals(204, logoutResponse.getStatusLine().getStatusCode()); events .expectLogout(accessToken.getSessionState()) .client("resource-owner") .removeDetail(Details.REDIRECT_URI) .assertEvent(); response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret"); assertEquals(400, response.getStatusCode()); assertEquals("invalid_grant", response.getError()); events .expectRefresh(refreshToken.getId(), refreshToken.getSessionState()) .client("resource-owner") .removeDetail(Details.TOKEN_ID) .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID) .error(Errors.INVALID_TOKEN) .assertEvent(); }
public AccessTokenResponseBuilder generateIDToken() { if (accessToken == null) { throw new IllegalStateException("accessToken not set"); } idToken = new IDToken(); idToken.id(KeycloakModelUtils.generateId()); idToken.subject(accessToken.getSubject()); idToken.audience(client.getClientId()); idToken.issuedNow(); idToken.issuedFor(accessToken.getIssuedFor()); idToken.issuer(accessToken.getIssuer()); idToken.setSessionState(accessToken.getSessionState()); if (realm.getAccessTokenLifespan() > 0) { idToken.expiration(Time.currentTime() + realm.getAccessTokenLifespan()); } transformIDToken( session, idToken, realm, client, userSession.getUser(), userSession, clientSession); return this; }
public AccessTokenResponse build() { if (accessToken != null) { event.detail(Details.TOKEN_ID, accessToken.getId()); } if (refreshToken != null) { if (event.getEvent().getDetails().containsKey(Details.REFRESH_TOKEN_ID)) { event.detail(Details.UPDATED_REFRESH_TOKEN_ID, refreshToken.getId()); } else { event.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()); } } AccessTokenResponse res = new AccessTokenResponse(); if (idToken != null) { String encodedToken = new JWSBuilder().jsonContent(idToken).rsa256(realm.getPrivateKey()); res.setIdToken(encodedToken); } if (accessToken != null) { String encodedToken = new JWSBuilder().jsonContent(accessToken).rsa256(realm.getPrivateKey()); res.setToken(encodedToken); res.setTokenType("bearer"); res.setSessionState(accessToken.getSessionState()); if (accessToken.getExpiration() != 0) { res.setExpiresIn(accessToken.getExpiration() - Time.currentTime()); } } if (refreshToken != null) { String encodedToken = new JWSBuilder().jsonContent(refreshToken).rsa256(realm.getPrivateKey()); res.setRefreshToken(encodedToken); if (refreshToken.getExpiration() != 0) { res.setRefreshExpiresIn(refreshToken.getExpiration() - Time.currentTime()); } } int notBefore = realm.getNotBefore(); if (client.getNotBefore() > notBefore) notBefore = client.getNotBefore(); res.setNotBeforePolicy(notBefore); return res; }
@Override public AccessToken transformAccessToken( AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { String role = mappingModel.getConfig().get(ROLE_CONFIG); String[] scopedRole = KeycloakModelUtils.parseRole(role); String appName = scopedRole[0]; String roleName = scopedRole[1]; if (appName != null) { token.addAccess(appName).addRole(roleName); } else { AccessToken.Access access = token.getRealmAccess(); if (access == null) { access = new AccessToken.Access(); token.setRealmAccess(access); } access.addRole(role); } return token; }
private void grantAccessToken(String login) throws Exception { oauth.clientId("resource-owner"); OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", login, "password"); assertEquals(200, response.getStatusCode()); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken()); events .expectLogin() .client("resource-owner") .user(userId) .session(accessToken.getSessionState()) .detail(Details.AUTH_METHOD, "oauth_credentials") .detail(Details.RESPONSE_TYPE, "token") .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) .detail(Details.USERNAME, login) .removeDetail(Details.CODE_ID) .removeDetail(Details.REDIRECT_URI) .removeDetail(Details.CONSENT) .assertEvent(); assertEquals(accessToken.getSessionState(), refreshToken.getSessionState()); OAuthClient.AccessTokenResponse refreshedResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret"); AccessToken refreshedAccessToken = oauth.verifyToken(refreshedResponse.getAccessToken()); RefreshToken refreshedRefreshToken = oauth.verifyRefreshToken(refreshedResponse.getRefreshToken()); assertEquals(accessToken.getSessionState(), refreshedAccessToken.getSessionState()); assertEquals(accessToken.getSessionState(), refreshedRefreshToken.getSessionState()); events .expectRefresh(refreshToken.getId(), refreshToken.getSessionState()) .user(userId) .client("resource-owner") .assertEvent(); }
public Cors allowedOrigins(AccessToken token) { if (token != null) { allowedOrigins = token.getAllowedOrigins(); } return this; }
public TokenValidation validateToken( KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, AccessToken oldToken, HttpHeaders headers) throws OAuthErrorException { UserModel user = session.users().getUserById(oldToken.getSubject(), realm); if (user == null) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user"); } if (!user.isEnabled()) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled"); } UserSessionModel userSession = session.sessions().getUserSession(realm, oldToken.getSessionState()); if (!AuthenticationManager.isSessionValid(realm, userSession)) { AuthenticationManager.backchannelLogout( session, realm, userSession, uriInfo, connection, headers, true); throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active"); } ClientSessionModel clientSession = null; for (ClientSessionModel clientSessionModel : userSession.getClientSessions()) { if (clientSessionModel.getId().equals(oldToken.getClientSession())) { clientSession = clientSessionModel; break; } } if (clientSession == null) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Client session not active", "Client session not active"); } ClientModel client = clientSession.getClient(); if (!client.getClientId().equals(oldToken.getIssuedFor())) { throw new OAuthErrorException( OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients"); } if (oldToken.getIssuedAt() < client.getNotBefore()) { throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token"); } if (oldToken.getIssuedAt() < realm.getNotBefore()) { throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token"); } // recreate token. Set<RoleModel> requestedRoles = TokenManager.getAccess(null, clientSession.getClient(), user); AccessToken newToken = createClientAccessToken( session, requestedRoles, realm, client, user, userSession, clientSession); verifyAccess(oldToken, newToken); return new TokenValidation(user, userSession, clientSession, newToken); }
protected AccessToken initToken( RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) { AccessToken token = new AccessToken(); if (clientSession != null) token.clientSession(clientSession.getId()); token.id(KeycloakModelUtils.generateId()); token.subject(user.getId()); token.audience(client.getClientId()); token.issuedNow(); token.issuedFor(client.getClientId()); token.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER)); if (session != null) { token.setSessionState(session.getId()); } if (realm.getAccessTokenLifespan() > 0) { token.expiration(Time.currentTime() + realm.getAccessTokenLifespan()); } Set<String> allowedOrigins = client.getWebOrigins(); if (allowedOrigins != null) { token.setAllowedOrigins(allowedOrigins); } return token; }
@Test public void clientCredentialsAuthSuccess() throws Exception { oauth.clientId("service-account-cl"); OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("secret1"); assertEquals(200, response.getStatusCode()); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken()); events .expectClientLogin() .client("service-account-cl") .user(userId) .session(accessToken.getSessionState()) .detail(Details.TOKEN_ID, accessToken.getId()) .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId()) .detail( Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl") .assertEvent(); assertEquals(accessToken.getSessionState(), refreshToken.getSessionState()); System.out.println("Access token other claims: " + accessToken.getOtherClaims()); Assert.assertEquals( "service-account-cl", accessToken.getOtherClaims().get(ServiceAccountConstants.CLIENT_ID)); Assert.assertTrue( accessToken.getOtherClaims().containsKey(ServiceAccountConstants.CLIENT_ADDRESS)); Assert.assertTrue( accessToken.getOtherClaims().containsKey(ServiceAccountConstants.CLIENT_HOST)); OAuthClient.AccessTokenResponse refreshedResponse = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret1"); AccessToken refreshedAccessToken = oauth.verifyToken(refreshedResponse.getAccessToken()); RefreshToken refreshedRefreshToken = oauth.verifyRefreshToken(refreshedResponse.getRefreshToken()); assertEquals(accessToken.getSessionState(), refreshedAccessToken.getSessionState()); assertEquals(accessToken.getSessionState(), refreshedRefreshToken.getSessionState()); events .expectRefresh(refreshToken.getId(), refreshToken.getSessionState()) .user(userId) .client("service-account-cl") .assertEvent(); }