@Override public Response keycloakInitiatedBrowserLogout( UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) { if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("")) return null; String idToken = userSession.getNote(FEDERATED_ID_TOKEN); if (idToken != null && getConfig().isBackchannelSupported()) { backchannelLogout(userSession, idToken); return null; } else { String sessionId = userSession.getId(); UriBuilder logoutUri = UriBuilder.fromUri(getConfig().getLogoutUrl()).queryParam("state", sessionId); if (idToken != null) logoutUri.queryParam("id_token_hint", idToken); String redirect = RealmsResource.brokerUrl(uriInfo) .path(IdentityBrokerService.class, "getEndpoint") .path(OIDCEndpoint.class, "logoutResponse") .build(realm.getName(), getConfig().getAlias()) .toString(); logoutUri.queryParam("post_logout_redirect_uri", redirect); Response response = Response.status(302).location(logoutUri.build()).build(); return response; } }
/** * Get offline sessions for client * * <p>Returns a list of offline user sessions associated with this client * * @param firstResult Paging offset * @param maxResults Maximum results size (defaults to 100) * @return */ @Path("offline-sessions") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public List<UserSessionRepresentation> getOfflineUserSessions( @QueryParam("first") Integer firstResult, @QueryParam("max") Integer maxResults) { auth.requireView(); if (client == null) { throw new NotFoundException("Could not find client"); } firstResult = firstResult != null ? firstResult : -1; maxResults = maxResults != null ? maxResults : Constants.DEFAULT_MAX_RESULTS; List<UserSessionRepresentation> sessions = new ArrayList<UserSessionRepresentation>(); List<UserSessionModel> userSessions = session .sessions() .getOfflineUserSessions(client.getRealm(), client, firstResult, maxResults); for (UserSessionModel userSession : userSessions) { UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(userSession); // Update lastSessionRefresh with the timestamp from clientSession for (ClientSessionModel clientSession : userSession.getClientSessions()) { if (client.getId().equals(clientSession.getClient().getId())) { rep.setLastAccess(Time.toMillis(clientSession.getTimestamp())); break; } } sessions.add(rep); } return sessions; }
public static void attachClientSession( UserSessionModel session, ClientSessionModel clientSession) { if (clientSession.getUserSession() != null) { return; } UserModel user = session.getUser(); clientSession.setUserSession(session); Set<String> requestedRoles = new HashSet<String>(); // todo scope param protocol independent for (RoleModel r : TokenManager.getAccess(null, clientSession.getClient(), user)) { requestedRoles.add(r.getId()); } clientSession.setRoles(requestedRoles); Set<String> requestedProtocolMappers = new HashSet<String>(); for (ProtocolMapperModel protocolMapper : clientSession.getClient().getProtocolMappers()) { if (protocolMapper.getProtocol().equals(clientSession.getAuthMethod())) { requestedProtocolMappers.add(protocolMapper.getId()); } } clientSession.setProtocolMappers(requestedProtocolMappers); Map<String, String> transferredNotes = clientSession.getUserSessionNotes(); for (Map.Entry<String, String> entry : transferredNotes.entrySet()) { session.setNote(entry.getKey(), entry.getValue()); } }
/** * Get offline sessions associated with the user and client * * @param id User id * @return */ @Path("{id}/offline-sessions/{clientId}") @GET @NoCache @Produces(MediaType.APPLICATION_JSON) public List<UserSessionRepresentation> getSessions( final @PathParam("id") String id, final @PathParam("clientId") String clientId) { auth.requireView(); UserModel user = session.users().getUserById(id, realm); if (user == null) { throw new NotFoundException("User not found"); } ClientModel client = realm.getClientById(clientId); if (client == null) { throw new NotFoundException("Client not found"); } List<UserSessionModel> sessions = new UserSessionManager(session).findOfflineSessions(realm, client, user); List<UserSessionRepresentation> reps = new ArrayList<UserSessionRepresentation>(); for (UserSessionModel session : sessions) { UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session); // Update lastSessionRefresh with the timestamp from clientSession for (ClientSessionModel clientSession : session.getClientSessions()) { if (clientId.equals(clientSession.getClient().getId())) { rep.setLastAccess(Time.toMillis(clientSession.getTimestamp())); break; } } reps.add(rep); } return reps; }
@Path("sessions/{session}") @DELETE public void deleteSession(@PathParam("session") String sessionId) { UserSessionModel session = realm.getUserSession(sessionId); if (session == null) throw new NotFoundException("Sesssion not found"); realm.removeUserSession(session); new ResourceAdminManager().logoutSession(uriInfo.getRequestUri(), realm, session.getId()); }
@Override public void attachUserSession( UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context) { AccessTokenResponse tokenResponse = (AccessTokenResponse) context.getContextData().get(FEDERATED_ACCESS_TOKEN_RESPONSE); userSession.setNote(FEDERATED_ACCESS_TOKEN, tokenResponse.getToken()); userSession.setNote(FEDERATED_ID_TOKEN, tokenResponse.getIdToken()); }
/** * Impersonate the user * * @param id User id * @return */ @Path("{id}/impersonation") @POST @NoCache @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> impersonate(final @PathParam("id") String id) { auth.init(RealmAuth.Resource.IMPERSONATION); auth.requireManage(); UserModel user = session.users().getUserById(id, realm); if (user == null) { throw new NotFoundException("User not found"); } RealmModel authenticatedRealm = auth.getAuth().getRealm(); // if same realm logout before impersonation boolean sameRealm = false; if (authenticatedRealm.getId().equals(realm.getId())) { sameRealm = true; UserSessionModel userSession = session .sessions() .getUserSession(authenticatedRealm, auth.getAuth().getToken().getSessionState()); AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection); AuthenticationManager.expireRememberMeCookie(realm, uriInfo, clientConnection); AuthenticationManager.backchannelLogout( session, authenticatedRealm, userSession, uriInfo, clientConnection, headers, true); } EventBuilder event = new EventBuilder(realm, session, clientConnection); UserSessionModel userSession = session .sessions() .createUserSession( realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "impersonate", false, null, null); AuthenticationManager.createLoginCookie( realm, userSession.getUser(), userSession, uriInfo, clientConnection); URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(realm.getName()); Map<String, Object> result = new HashMap<>(); result.put("sameRealm", sameRealm); result.put("redirect", redirect.toString()); event .event(EventType.IMPERSONATE) .session(userSession) .user(user) .detail(Details.IMPERSONATOR_REALM, authenticatedRealm.getName()) .detail(Details.IMPERSONATOR, auth.getAuth().getUser().getUsername()) .success(); return result; }
public static void dettachClientSession( UserSessionProvider sessions, RealmModel realm, ClientSessionModel clientSession) { UserSessionModel userSession = clientSession.getUserSession(); if (userSession == null) { return; } clientSession.setUserSession(null); clientSession.setRoles(null); clientSession.setProtocolMappers(null); if (userSession.getClientSessions().isEmpty()) { sessions.removeUserSession(realm, userSession); } }
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; }
protected String getNameId( String nameIdFormat, ClientSessionModel clientSession, UserSessionModel userSession) { if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) { return userSession.getUser().getEmail(); } else if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get())) { // "G-" stands for "generated" Add this for the slight possibility of collisions. return "G-" + UUID.randomUUID().toString(); } else if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get())) { return getPersistentNameId(clientSession, userSession); } else if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get())) { // TODO: Support for persistent NameID (pseudo-random identifier persisted in user object) return userSession.getUser().getUsername(); } else { return userSession.getUser().getUsername(); } }
@Override public void backchannelLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) { if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("") || !getConfig().isBackchannelSupported()) return; String idToken = userSession.getNote(FEDERATED_ID_TOKEN); if (idToken == null) return; backchannelLogout(userSession, idToken); }
@Override public Response finishLogout(UserSessionModel userSession) { String redirectUri = userSession.getNote(OIDCLoginProtocol.LOGOUT_REDIRECT_URI); String state = userSession.getNote(OIDCLoginProtocol.LOGOUT_STATE_PARAM); event.event(EventType.LOGOUT); if (redirectUri != null) { event.detail(Details.REDIRECT_URI, redirectUri); } event.user(userSession.getUser()).session(userSession).success(); if (redirectUri != null) { UriBuilder uriBuilder = UriBuilder.fromUri(redirectUri); if (state != null) uriBuilder.queryParam(STATE_PARAM, state); return Response.status(302).location(uriBuilder.build()).build(); } else { return Response.ok().build(); } }
@GET @Path("logout_response") public Response logoutResponse(@Context UriInfo uriInfo, @QueryParam("state") String state) { UserSessionModel userSession = session.sessions().getUserSession(realm, state); if (userSession == null) { logger.error("no valid user session"); EventBuilder event = new EventBuilder(realm, session, clientConnection); event.event(EventType.LOGOUT); event.error(Errors.USER_SESSION_NOT_FOUND); return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR); } if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) { logger.error("usersession in different state"); EventBuilder event = new EventBuilder(realm, session, clientConnection); event.event(EventType.LOGOUT); event.error(Errors.USER_SESSION_NOT_FOUND); return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE); } return AuthenticationManager.finishBrowserLogout( session, realm, userSession, uriInfo, clientConnection, headers); }
@Override public Response finishLogout(UserSessionModel userSession) { logger.debug("finishLogout"); String logoutBindingUri = userSession.getNote(SAML_LOGOUT_BINDING_URI); if (logoutBindingUri == null) { logger.error( "Can't finish SAML logout as there is no logout binding set. Please configure the logout service url in the admin console for your client applications."); return ErrorPage.error(session, Messages.FAILED_LOGOUT); } String logoutRelayState = userSession.getNote(SAML_LOGOUT_RELAY_STATE); SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder(); builder.logoutRequestID(userSession.getNote(SAML_LOGOUT_REQUEST_ID)); builder.destination(logoutBindingUri); builder.issuer(getResponseIssuer(realm)); JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder(); binding.relayState(logoutRelayState); String signingAlgorithm = userSession.getNote(SAML_LOGOUT_SIGNATURE_ALGORITHM); if (signingAlgorithm != null) { SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(signingAlgorithm); String canonicalization = userSession.getNote(SAML_LOGOUT_CANONICALIZATION); if (canonicalization != null) { binding.canonicalizationMethod(canonicalization); } KeyManager.ActiveKey keys = session.keys().getActiveKey(realm); binding .signatureAlgorithm(algorithm) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signDocument(); } try { return buildLogoutResponse(userSession, logoutBindingUri, builder, binding); } catch (ConfigurationException e) { throw new RuntimeException(e); } catch (ProcessingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } }
@Override public void transformAttributeStatement( AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { UserModel user = userSession.getUser(); String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE); String attributeValue = user.getFirstAttribute(attributeName); if (attributeValue == null) return; AttributeStatementHelper.addAttribute(attributeStatement, mappingModel, attributeValue); }
private void initEvent(ClientSessionModel clientSession) { event .event(EventType.LOGIN) .client(clientSession.getClient()) .user(clientSession.getUserSession().getUser()) .session(clientSession.getUserSession().getId()) .detail(Details.CODE_ID, clientSession.getId()) .detail(Details.REDIRECT_URI, clientSession.getRedirectUri()) .detail( Details.USERNAME, clientSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME)) .detail(Details.RESPONSE_TYPE, "code"); UserSessionModel userSession = clientSession.getUserSession(); if (userSession != null) { event.detail(Details.AUTH_METHOD, userSession.getAuthMethod()); event.detail(Details.USERNAME, userSession.getLoginUsername()); if (userSession.isRememberMe()) { event.detail(Details.REMEMBER_ME, "true"); } } }
protected Response handleSamlResponse(String samlResponse, String relayState) { event.event(EventType.LOGOUT); SAMLDocumentHolder holder = extractResponseDocument(samlResponse); StatusResponseType statusResponse = (StatusResponseType) holder.getSamlObject(); // validate destination if (statusResponse.getDestination() != null && !uriInfo.getAbsolutePath().toString().equals(statusResponse.getDestination())) { event.detail(Details.REASON, "invalid_destination"); event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE); return ErrorPage.error(session, Messages.INVALID_REQUEST); } AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false); if (authResult == null) { logger.warn("Unknown saml response."); event.event(EventType.LOGOUT); event.error(Errors.INVALID_TOKEN); return ErrorPage.error(session, Messages.INVALID_REQUEST); } // assume this is a logout response UserSessionModel userSession = authResult.getSession(); if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) { logger.warn("Unknown saml response."); logger.warn("UserSession is not tagged as logging out."); event.event(EventType.LOGOUT); event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE); return ErrorPage.error(session, Messages.INVALID_REQUEST); } logger.debug("logout response"); Response response = authManager.browserLogout( session, realm, userSession, uriInfo, clientConnection, headers); event.success(); return response; }
protected void backchannelLogout(UserSessionModel userSession, String idToken) { String sessionId = userSession.getId(); UriBuilder logoutUri = UriBuilder.fromUri(getConfig().getLogoutUrl()).queryParam("state", sessionId); logoutUri.queryParam("id_token_hint", idToken); String url = logoutUri.build().toString(); try { int status = JsonSimpleHttp.doGet(url).asStatus(); boolean success = status >= 200 && status < 400; if (!success) { logger.warn("Failed backchannel broker logout to: " + url); } } catch (Exception e) { logger.warn("Failed backchannel broker logout to: " + url, e); } }
@Path("email-verification") @GET public Response emailVerification( @QueryParam("code") String code, @QueryParam("key") String key) { event.event(EventType.VERIFY_EMAIL); if (key != null) { Checks checks = new Checks(); if (!checks.verifyCode(key, ClientSessionModel.Action.VERIFY_EMAIL.name())) { return checks.response; } ClientSessionCode accessCode = checks.clientCode; ClientSessionModel clientSession = accessCode.getClientSession(); UserSessionModel userSession = clientSession.getUserSession(); UserModel user = userSession.getUser(); initEvent(clientSession); user.setEmailVerified(true); user.removeRequiredAction(RequiredAction.VERIFY_EMAIL); event.event(EventType.VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success(); String actionCookieValue = getActionCookie(); if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) { session.sessions().removeClientSession(realm, clientSession); return session .getProvider(LoginFormsProvider.class) .setSuccess(Messages.EMAIL_VERIFIED) .createInfoPage(); } event = event.clone().removeDetail(Details.EMAIL).event(EventType.LOGIN); return AuthenticationManager.nextActionAfterAuthentication( session, userSession, clientSession, clientConnection, request, uriInfo, event); } else { Checks checks = new Checks(); if (!checks.verifyCode(code, ClientSessionModel.Action.VERIFY_EMAIL.name())) { return checks.response; } ClientSessionCode accessCode = checks.clientCode; ClientSessionModel clientSession = accessCode.getClientSession(); UserSessionModel userSession = clientSession.getUserSession(); initEvent(clientSession); createActionCookie(realm, uriInfo, clientConnection, userSession.getId()); return session .getProvider(LoginFormsProvider.class) .setClientSessionCode(accessCode.getCode()) .setUser(userSession.getUser()) .createResponse(RequiredAction.VERIFY_EMAIL); } }
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; }
/** * Attempts to retrieve the persistent type NameId as follows: * * <ol> * <li>saml.persistent.name.id.for.$clientId user attribute * <li>saml.persistent.name.id.for.* user attribute * <li>G-$randomUuid * </ol> * * If a randomUuid is generated, an attribute for the given saml.persistent.name.id.for.$clientId * will be generated, otherwise no state change will occur with respect to the user's attributes. * * @return the user's persistent NameId */ protected String getPersistentNameId( final ClientSessionModel clientSession, final UserSessionModel userSession) { // attempt to retrieve the UserID for the client-specific attribute final UserModel user = userSession.getUser(); final String clientNameId = String.format( "%s.%s", SAML_PERSISTENT_NAME_ID_FOR, clientSession.getClient().getClientId()); String samlPersistentNameId = user.getFirstAttribute(clientNameId); if (samlPersistentNameId != null) { return samlPersistentNameId; } // check for a wildcard attribute final String wildcardNameId = String.format("%s.*", SAML_PERSISTENT_NAME_ID_FOR); samlPersistentNameId = user.getFirstAttribute(wildcardNameId); if (samlPersistentNameId != null) { return samlPersistentNameId; } // default to generated. "G-" stands for "generated" samlPersistentNameId = "G-" + UUID.randomUUID().toString(); user.setSingleAttribute(clientNameId, samlPersistentNameId); return samlPersistentNameId; }
/** * OAuth grant page. You should not invoked this directly! * * @param formData * @return */ @Path("consent") @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response processConsent(final MultivaluedMap<String, String> formData) { event.event(EventType.LOGIN).detail(Details.RESPONSE_TYPE, "code"); if (!checkSsl()) { return ErrorPage.error(session, Messages.HTTPS_REQUIRED); } String code = formData.getFirst("code"); ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm); if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT.name())) { event.error(Errors.INVALID_CODE); return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE); } ClientSessionModel clientSession = accessCode.getClientSession(); event.detail(Details.CODE_ID, clientSession.getId()); String redirect = clientSession.getRedirectUri(); UserSessionModel userSession = clientSession.getUserSession(); UserModel user = userSession.getUser(); ClientModel client = clientSession.getClient(); event .client(client) .user(user) .detail(Details.RESPONSE_TYPE, "code") .detail(Details.REDIRECT_URI, redirect); event.detail(Details.AUTH_METHOD, userSession.getAuthMethod()); event.detail(Details.USERNAME, userSession.getLoginUsername()); if (userSession.isRememberMe()) { event.detail(Details.REMEMBER_ME, "true"); } if (!AuthenticationManager.isSessionValid(realm, userSession)) { AuthenticationManager.backchannelLogout( session, realm, userSession, uriInfo, clientConnection, headers, true); event.error(Errors.INVALID_CODE); return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE); } event.session(userSession); if (formData.containsKey("cancel")) { LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod()); protocol.setRealm(realm).setHttpHeaders(headers).setUriInfo(uriInfo); event.error(Errors.REJECTED_BY_USER); return protocol.consentDenied(clientSession); } UserConsentModel grantedConsent = user.getConsentByClient(client.getId()); if (grantedConsent == null) { grantedConsent = new UserConsentModel(client); user.addConsent(grantedConsent); } for (RoleModel role : accessCode.getRequestedRoles()) { grantedConsent.addGrantedRole(role); } for (ProtocolMapperModel protocolMapper : accessCode.getRequestedProtocolMappers()) { if (protocolMapper.isConsentRequired() && protocolMapper.getConsentText() != null) { grantedConsent.addGrantedProtocolMapper(protocolMapper); } } user.updateConsent(grantedConsent); event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED); event.success(); return authManager.redirectAfterSuccessfulFlow( session, realm, userSession, clientSession, request, uriInfo, clientConnection); }
public static boolean isLogoutPostBindingForInitiator(UserSessionModel session) { String note = session.getNote(SamlProtocol.SAML_LOGOUT_BINDING); return SamlProtocol.SAML_POST_BINDING.equals(note); }
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); }
public void init() { eventStore = session.getProvider(EventStoreProvider.class); account = session .getProvider(AccountProvider.class) .setRealm(realm) .setUriInfo(uriInfo) .setHttpHeaders(headers); AuthenticationManager.AuthResult authResult = authManager.authenticateBearerToken(session, realm, uriInfo, clientConnection, headers); if (authResult != null) { auth = new Auth( realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), false); } else { authResult = authManager.authenticateIdentityCookie(session, realm); if (authResult != null) { auth = new Auth( realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), true); updateCsrfChecks(); account.setStateChecker(stateChecker); } } String requestOrigin = UriUtils.getOrigin(uriInfo.getBaseUri()); // don't allow cors requests unless they were authenticated by an access token // This is to prevent CSRF attacks. if (auth != null && auth.isCookieAuthenticated()) { String origin = headers.getRequestHeaders().getFirst("Origin"); if (origin != null && !requestOrigin.equals(origin)) { throw new ForbiddenException(); } if (!request.getHttpMethod().equals("GET")) { String referrer = headers.getRequestHeaders().getFirst("Referer"); if (referrer != null && !requestOrigin.equals(UriUtils.getOrigin(referrer))) { throw new ForbiddenException(); } } } if (authResult != null) { UserSessionModel userSession = authResult.getSession(); if (userSession != null) { boolean associated = false; for (ClientSessionModel c : userSession.getClientSessions()) { if (c.getClient().equals(client)) { auth.setClientSession(c); associated = true; break; } } if (!associated) { ClientSessionModel clientSession = session.sessions().createClientSession(realm, client); clientSession.setUserSession(userSession); auth.setClientSession(clientSession); } } account.setUser(auth.getUser()); } boolean eventsEnabled = eventStore != null && realm.isEventsEnabled(); // todo find out from federation if password is updatable account.setFeatures(realm.isIdentityFederationEnabled(), eventsEnabled, true); }
/** * Update account password * * <p>Form params: * * <p>password - old password password-new pasword-confirm * * @param formData * @return */ @Path("password") @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) { if (auth == null) { return login("password"); } require(AccountRoles.MANAGE_ACCOUNT); String action = formData.getFirst("submitAction"); if (action != null && action.equals("Cancel")) { setReferrerOnPage(); return account.createResponse(AccountPages.PASSWORD); } csrfCheck(formData); UserModel user = auth.getUser(); boolean requireCurrent = isPasswordSet(user); account.setPasswordSet(requireCurrent); String password = formData.getFirst("password"); String passwordNew = formData.getFirst("password-new"); String passwordConfirm = formData.getFirst("password-confirm"); if (requireCurrent) { if (Validation.isBlank(password)) { setReferrerOnPage(); return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD); } UserCredentialModel cred = UserCredentialModel.password(password); if (!session.users().validCredentials(realm, user, cred)) { setReferrerOnPage(); return account .setError(Messages.INVALID_PASSWORD_EXISTING) .createResponse(AccountPages.PASSWORD); } } if (Validation.isEmpty(passwordNew)) { setReferrerOnPage(); return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD); } if (!passwordNew.equals(passwordConfirm)) { setReferrerOnPage(); return account .setError(Messages.INVALID_PASSWORD_CONFIRM) .createResponse(AccountPages.PASSWORD); } try { session.users().updateCredential(realm, user, UserCredentialModel.password(passwordNew)); } catch (ModelReadOnlyException mre) { setReferrerOnPage(); return account.setError(Messages.READ_ONLY_PASSWORD).createResponse(AccountPages.PASSWORD); } catch (ModelException me) { logger.error("Failed to update password", me); setReferrerOnPage(); return account .setError(me.getMessage(), me.getParameters()) .createResponse(AccountPages.PASSWORD); } catch (Exception ape) { logger.error("Failed to update password", ape); setReferrerOnPage(); return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD); } List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, user); for (UserSessionModel s : sessions) { if (!s.getId().equals(auth.getSession().getId())) { AuthenticationManager.backchannelLogout( session, realm, s, uriInfo, clientConnection, headers, true); } } event.event(EventType.UPDATE_PASSWORD).client(auth.getClient()).user(auth.getUser()).success(); setReferrerOnPage(); return account .setPasswordSet(true) .setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED) .createResponse(AccountPages.PASSWORD); }
protected Response logoutRequest( LogoutRequestType logoutRequest, ClientModel client, String relayState) { SamlClient samlClient = new SamlClient(client); // validate destination if (logoutRequest.getDestination() != null && !uriInfo.getAbsolutePath().equals(logoutRequest.getDestination())) { event.detail(Details.REASON, "invalid_destination"); event.error(Errors.INVALID_SAML_LOGOUT_REQUEST); return ErrorPage.error(session, Messages.INVALID_REQUEST); } // authenticate identity cookie, but ignore an access token timeout as we're logging out // anyways. AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false); if (authResult != null) { String logoutBinding = getBindingType(); if ("true".equals(samlClient.forcePostBinding())) logoutBinding = SamlProtocol.SAML_POST_BINDING; String bindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding); UserSessionModel userSession = authResult.getSession(); userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING_URI, bindingUri); if (samlClient.requiresRealmSignature()) { userSession.setNote( SamlProtocol.SAML_LOGOUT_SIGNATURE_ALGORITHM, samlClient.getSignatureAlgorithm().toString()); } if (relayState != null) userSession.setNote(SamlProtocol.SAML_LOGOUT_RELAY_STATE, relayState); userSession.setNote(SamlProtocol.SAML_LOGOUT_REQUEST_ID, logoutRequest.getID()); userSession.setNote(SamlProtocol.SAML_LOGOUT_BINDING, logoutBinding); userSession.setNote( SamlProtocol.SAML_LOGOUT_CANONICALIZATION, samlClient.getCanonicalizationMethod()); userSession.setNote( AuthenticationManager.KEYCLOAK_LOGOUT_PROTOCOL, SamlProtocol.LOGIN_PROTOCOL); // remove client from logout requests for (ClientSessionModel clientSession : userSession.getClientSessions()) { if (clientSession.getClient().getId().equals(client.getId())) { clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name()); } } logger.debug("browser Logout"); return authManager.browserLogout( session, realm, userSession, uriInfo, clientConnection, headers); } else if (logoutRequest.getSessionIndex() != null) { for (String sessionIndex : logoutRequest.getSessionIndex()) { ClientSessionModel clientSession = session.sessions().getClientSession(realm, sessionIndex); if (clientSession == null) continue; UserSessionModel userSession = clientSession.getUserSession(); if (clientSession.getClient().getClientId().equals(client.getClientId())) { // remove requesting client from logout clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT.name()); // Remove also other clientSessions of this client as there could be more in this // UserSession if (userSession != null) { for (ClientSessionModel clientSession2 : userSession.getClientSessions()) { if (clientSession2.getClient().getId().equals(client.getId())) { clientSession2.setAction(ClientSessionModel.Action.LOGGED_OUT.name()); } } } } try { authManager.backchannelLogout( session, realm, userSession, uriInfo, clientConnection, headers, true); } catch (Exception e) { logger.warn("Failure with backchannel logout", e); } } } // default String logoutBinding = getBindingType(); String logoutBindingUri = SamlProtocol.getLogoutServiceUrl(uriInfo, client, logoutBinding); String logoutRelayState = relayState; SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder(); builder.logoutRequestID(logoutRequest.getID()); builder.destination(logoutBindingUri); builder.issuer(RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString()); JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder().relayState(logoutRelayState); if (samlClient.requiresRealmSignature()) { SignatureAlgorithm algorithm = samlClient.getSignatureAlgorithm(); KeyManager.ActiveKey keys = session.keys().getActiveKey(realm); binding .signatureAlgorithm(algorithm) .signWith(keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()) .signDocument(); } try { if (SamlProtocol.SAML_POST_BINDING.equals(logoutBinding)) { return binding.postBinding(builder.buildDocument()).response(logoutBindingUri); } else { return binding.redirectBinding(builder.buildDocument()).response(logoutBindingUri); } } catch (Exception e) { throw new RuntimeException(e); } }