private String getActionCookie() { Cookie cookie = headers.getCookies().get(ACTION_COOKIE); AuthenticationManager.expireCookie( realm, ACTION_COOKIE, AuthenticationManager.getRealmCookiePath(realm, uriInfo), realm.getSslRequired().isRequired(clientConnection), clientConnection); return cookie != null ? cookie.getValue() : null; }
/** * 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; }
/** * Initiated by admin, not the user on login * * @param key * @return */ @Path("execute-actions") @GET public Response executeActions(@QueryParam("key") String key) { event.event(EventType.EXECUTE_ACTIONS); if (key != null) { Checks checks = new Checks(); if (!checks.verifyCode(key, ClientSessionModel.Action.EXECUTE_ACTIONS.name())) { return checks.response; } ClientSessionModel clientSession = checks.clientCode.getClientSession(); clientSession.setNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true"); clientSession.setNote(ClientSessionModel.Action.EXECUTE_ACTIONS.name(), "true"); return AuthenticationManager.nextActionAfterAuthentication( session, clientSession.getUserSession(), clientSession, clientConnection, request, uriInfo, event); } else { event.error(Errors.INVALID_CODE); return ErrorPage.error(session, Messages.INVALID_CODE); } }
/** * Revoke consent and offline tokens for particular client from user * * @param id User id * @param clientId Client id */ @Path("{id}/consents/{client}") @DELETE @NoCache public void revokeConsent( final @PathParam("id") String id, final @PathParam("client") String clientId) { auth.requireManage(); UserModel user = session.users().getUserById(id, realm); if (user == null) { throw new NotFoundException("User not found"); } ClientModel client = realm.getClientByClientId(clientId); boolean revokedConsent = user.revokeConsentForClient(client.getId()); boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client); if (revokedConsent) { // Logout clientSessions for this user and client AuthenticationManager.backchannelUserFromClient( session, realm, user, client, uriInfo, headers); } if (!revokedConsent && !revokedOfflineToken) { throw new NotFoundException("Consent nor offline token not found"); } adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success(); }
@Path("sessions-logout") @GET public Response processSessionsLogout(@QueryParam("stateChecker") String stateChecker) { if (auth == null) { return login("sessions"); } require(AccountRoles.MANAGE_ACCOUNT); csrfCheck(stateChecker); UserModel user = auth.getUser(); List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user); for (UserSessionModel userSession : userSessions) { AuthenticationManager.backchannelLogout( session, realm, userSession, uriInfo, clientConnection, headers, true); } UriBuilder builder = Urls.accountBase(uriInfo.getBaseUri()).path(AccountService.class, "sessionsPage"); String referrer = uriInfo.getQueryParameters().getFirst("referrer"); if (referrer != null) { builder.queryParam("referrer", referrer); } URI location = builder.build(realm.getName()); return Response.seeOther(location).build(); }
protected Response processFlow( String execution, ClientSessionModel clientSession, String flowPath, AuthenticationFlowModel flow, String errorMessage) { AuthenticationProcessor processor = new AuthenticationProcessor(); processor .setClientSession(clientSession) .setFlowPath(flowPath) .setFlowId(flow.getId()) .setConnection(clientConnection) .setEventBuilder(event) .setProtector(authManager.getProtector()) .setRealm(realm) .setSession(session) .setUriInfo(uriInfo) .setRequest(request); if (errorMessage != null) processor.setForwardedErrorMessage(new FormMessage(null, errorMessage)); try { if (execution != null) { return processor.authenticationAction(execution); } else { return processor.authenticate(); } } catch (Exception e) { return processor.handleBrowserException(e); } }
/** * Remove a specific user session. Any client that has an admin url will also be told to * invalidate this particular session. * * @param sessionId */ @Path("sessions/{session}") @DELETE public void deleteSession(@PathParam("session") String sessionId) { auth.init(RealmAuth.Resource.USER).requireManage(); UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId); if (userSession == null) throw new NotFoundException("Sesssion not found"); AuthenticationManager.backchannelLogout( session, realm, userSession, uriInfo, connection, headers, true); adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success(); }
public Response redirectAccessCode( AccessCodeEntry accessCode, UserSessionModel session, String state, String redirect, boolean rememberMe) { String code = accessCode.getCode(); UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, code); log.debugv("redirectAccessCode: state: {0}", state); if (state != null) redirectUri.queryParam(OAuth2Constants.STATE, state); Response.ResponseBuilder location = Response.status(302).location(redirectUri.build()); Cookie remember = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME); rememberMe = rememberMe || remember != null; // refresh the cookies! authManager.createLoginCookie(realm, accessCode.getUser(), session, uriInfo, rememberMe); if (rememberMe) authManager.createRememberMeCookie(realm, uriInfo); return location.build(); }
@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 static void createActionCookie( RealmModel realm, UriInfo uriInfo, ClientConnection clientConnection, String sessionId) { CookieHelper.addCookie( ACTION_COOKIE, sessionId, AuthenticationManager.getRealmCookiePath(realm, uriInfo), null, null, -1, realm.getSslRequired().isRequired(clientConnection), true); }
/** * Remove all user sessions associated with the user * * <p>Also send notification to all clients that have an admin URL to invalidate the sessions for * the particular user. * * @param id User id */ @Path("{id}/logout") @POST public void logout(final @PathParam("id") String id) { auth.requireManage(); UserModel user = session.users().getUserById(id, realm); if (user == null) { throw new NotFoundException("User not found"); } List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user); for (UserSessionModel userSession : userSessions) { AuthenticationManager.backchannelLogout( session, realm, userSession, uriInfo, clientConnection, headers, true); } adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success(); }
@Path("revoke-grant") @POST public Response processRevokeGrant(final MultivaluedMap<String, String> formData) { if (auth == null) { return login("applications"); } require(AccountRoles.MANAGE_ACCOUNT); csrfCheck(formData); String clientId = formData.getFirst("clientId"); if (clientId == null) { return account.setError(Messages.CLIENT_NOT_FOUND).createResponse(AccountPages.APPLICATIONS); } ClientModel client = realm.getClientById(clientId); if (client == null) { return account.setError(Messages.CLIENT_NOT_FOUND).createResponse(AccountPages.APPLICATIONS); } // Revoke grant in UserModel UserModel user = auth.getUser(); user.revokeConsentForClient(client.getId()); OfflineTokenUtils.revokeOfflineToken(session, realm, user, client); // Logout clientSessions for this user and client AuthenticationManager.backchannelUserFromClient(session, realm, user, client, uriInfo, headers); event .event(EventType.REVOKE_GRANT) .client(auth.getClient()) .user(auth.getUser()) .detail(Details.REVOKED_CLIENT, client.getClientId()) .success(); setReferrerOnPage(); UriBuilder builder = Urls.accountBase(uriInfo.getBaseUri()).path(AccountService.class, "applicationsPage"); String referrer = uriInfo.getQueryParameters().getFirst("referrer"); if (referrer != null) { builder.queryParam("referrer", referrer); } URI location = builder.build(realm.getName()); return Response.seeOther(location).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); }
/** * protocol independent registration page entry point * * @param code * @return */ @Path(REGISTRATION_PATH) @GET public Response registerPage( @QueryParam("code") String code, @QueryParam("execution") String execution) { event.event(EventType.REGISTER); if (!realm.isRegistrationAllowed()) { event.error(Errors.REGISTRATION_DISABLED); return ErrorPage.error(session, Messages.REGISTRATION_NOT_ALLOWED); } Checks checks = new Checks(); if (!checks.verifyCode(code, ClientSessionModel.Action.AUTHENTICATE.name())) { return checks.response; } event.detail(Details.CODE_ID, code); ClientSessionCode clientSessionCode = checks.clientCode; ClientSessionModel clientSession = clientSessionCode.getClientSession(); authManager.expireIdentityCookie(realm, uriInfo, clientConnection); return processRegistration(execution, clientSession, null); }
/** * 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); }
/** * 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); }
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 Response processRequireAction(final String code, String action) { event.event(EventType.CUSTOM_REQUIRED_ACTION); event.detail(Details.CUSTOM_REQUIRED_ACTION, action); if (action == null) { logger.error("required action query param was null"); event.error(Errors.INVALID_CODE); throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE)); } RequiredActionFactory factory = (RequiredActionFactory) session .getKeycloakSessionFactory() .getProviderFactory(RequiredActionProvider.class, action); if (factory == null) { logger.error("required action provider was null"); event.error(Errors.INVALID_CODE); throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE)); } RequiredActionProvider provider = factory.create(session); Checks checks = new Checks(); if (!checks.verifyCode(code, action)) { return checks.response; } final ClientSessionCode clientCode = checks.clientCode; final ClientSessionModel clientSession = clientCode.getClientSession(); if (clientSession.getUserSession() == null) { logger.error("user session was null"); event.error(Errors.USER_SESSION_NOT_FOUND); throw new WebApplicationException(ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE)); } initEvent(clientSession); event.event(EventType.CUSTOM_REQUIRED_ACTION); RequiredActionContextResult context = new RequiredActionContextResult( clientSession.getUserSession(), clientSession, realm, event, session, request, clientSession.getUserSession().getUser(), factory) { @Override public String generateAccessCode(String action) { String clientSessionAction = clientSession.getAction(); if (action.equals(clientSessionAction)) { clientSession.setTimestamp(Time.currentTime()); return code; } ClientSessionCode code = new ClientSessionCode(getRealm(), getClientSession()); code.setAction(action); return code.getCode(); } @Override public void ignore() { throw new RuntimeException("Cannot call ignore within processAction()"); } }; provider.processAction(context); if (context.getStatus() == RequiredActionContext.Status.SUCCESS) { event.clone().success(); // do both clientSession.removeRequiredAction(factory.getId()); clientSession.getUserSession().getUser().removeRequiredAction(factory.getId()); event.event(EventType.LOGIN); return AuthenticationManager.nextActionAfterAuthentication( session, clientSession.getUserSession(), clientSession, clientConnection, request, uriInfo, event); } if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) { return context.getChallenge(); } if (context.getStatus() == RequiredActionContext.Status.FAILURE) { LoginProtocol protocol = context .getSession() .getProvider(LoginProtocol.class, context.getClientSession().getAuthMethod()); protocol .setRealm(context.getRealm()) .setHttpHeaders(context.getHttpRequest().getHttpHeaders()) .setUriInfo(context.getUriInfo()); event.detail(Details.CUSTOM_REQUIRED_ACTION, action).error(Errors.REJECTED_BY_USER); return protocol.consentDenied(context.getClientSession()); } throw new RuntimeException("Unreachable"); }