/** * Endpoint for executing reset credentials flow. If code is null, a client session is created * with the account service as the client. Successful reset sends you to the account page. Note, * account service must be enabled. * * @param code * @param execution * @return */ @Path(RESET_CREDENTIALS_PATH) @GET public Response resetCredentialsGET( @QueryParam("code") String code, @QueryParam("execution") String execution) { // we allow applications to link to reset credentials without going through OAuth or SAML // handshakes // if (code == null) { if (!realm.isResetPasswordAllowed()) { event.event(EventType.RESET_PASSWORD); event.error(Errors.NOT_ALLOWED); return ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED); } // set up the account service as the endpoint to call. ClientModel client = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); ClientSessionModel clientSession = session.sessions().createClientSession(realm, client); clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret()); // clientSession.setNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true"); clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL); String redirectUri = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString(); clientSession.setRedirectUri(redirectUri); clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret()); clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE); clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri); clientSession.setNote( OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName())); return processResetCredentials(null, clientSession, null); } return resetCredentials(code, execution); }
@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(); }
public String getOauthAction() { if (this.actionuri != null) { return this.actionuri.getPath(); } return Urls.realmOauthAction(baseURI, realm).toString(); }
private ClientSessionModel createClientSession( UserModel user, String redirectUri, String clientId) { if (!user.isEnabled()) { throw new WebApplicationException( ErrorResponse.error("User is disabled", Response.Status.BAD_REQUEST)); } if (redirectUri != null && clientId == null) { throw new WebApplicationException( ErrorResponse.error("Client id missing", Response.Status.BAD_REQUEST)); } if (clientId == null) { clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID; } ClientModel client = realm.getClientByClientId(clientId); if (client == null || !client.isEnabled()) { throw new WebApplicationException( ErrorResponse.error(clientId + " not enabled", Response.Status.BAD_REQUEST)); } String redirect; if (redirectUri != null) { redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client); if (redirect == null) { throw new WebApplicationException( ErrorResponse.error("Invalid redirect uri.", Response.Status.BAD_REQUEST)); } } else { redirect = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString(); } UserSessionModel userSession = session .sessions() .createUserSession( realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "form", false, null, null); // audit.session(userSession); ClientSessionModel clientSession = session.sessions().createClientSession(realm, client); clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL); clientSession.setRedirectUri(redirect); clientSession.setUserSession(userSession); return clientSession; }
/** * Send a update account email to the user * * <p>An email contains a link the user can click to perform a set of required actions. The * redirectUri and clientId parameters are optional. The default for the redirect is the account * client. * * @param id User is * @param redirectUri Redirect uri * @param clientId Client id * @param actions required actions the user needs to complete * @return */ @Path("{id}/execute-actions-email") @PUT @Consumes(MediaType.APPLICATION_JSON) public Response executeActionsEmail( @PathParam("id") String id, @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId, List<String> actions) { auth.requireManage(); UserModel user = session.users().getUserById(id, realm); if (user == null) { return ErrorResponse.error("User not found", Response.Status.NOT_FOUND); } if (user.getEmail() == null) { return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST); } ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId); for (String action : actions) { clientSession.addRequiredAction(action); } ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession); accessCode.setAction(ClientSessionModel.Action.EXECUTE_ACTIONS.name()); try { UriBuilder builder = Urls.executeActionsBuilder(uriInfo.getBaseUri()); builder.queryParam("key", accessCode.getCode()); String link = builder.build(realm.getName()).toString(); long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction()); this.session .getProvider(EmailTemplateProvider.class) .setRealm(realm) .setUser(user) .sendExecuteActions(link, expiration); // audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, // accessCode.getCodeId()).success(); adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success(); return Response.ok().build(); } catch (EmailException e) { logger.failedToSendActionsEmail(e); return ErrorResponse.error( "Failed to send execute actions email", Response.Status.INTERNAL_SERVER_ERROR); } }
private static String verifyRedirectUri( UriInfo uriInfo, String rootUrl, String redirectUri, RealmModel realm, Set<String> validRedirects) { if (redirectUri == null) { logger.debug("No Redirect URI parameter specified"); return null; } else if (validRedirects.isEmpty()) { logger.debug("No Redirect URIs supplied"); redirectUri = null; } else { redirectUri = lowerCaseHostname(redirectUri); String r = redirectUri; Set<String> resolveValidRedirects = resolveValidRedirects(uriInfo, rootUrl, validRedirects); boolean valid = matchesRedirects(resolveValidRedirects, r); if (!valid && r.startsWith(Constants.INSTALLED_APP_URL) && r.indexOf(':', Constants.INSTALLED_APP_URL.length()) >= 0) { int i = r.indexOf(':', Constants.INSTALLED_APP_URL.length()); StringBuilder sb = new StringBuilder(); sb.append(r.substring(0, i)); i = r.indexOf('/', i); if (i >= 0) { sb.append(r.substring(i)); } r = sb.toString(); valid = matchesRedirects(resolveValidRedirects, r); } if (valid && redirectUri.startsWith("/")) { redirectUri = relativeToAbsoluteURI(uriInfo, rootUrl, redirectUri); } redirectUri = valid ? redirectUri : null; } if (Constants.INSTALLED_APP_URN.equals(redirectUri)) { return Urls.realmInstalledAppUrnCallback(uriInfo.getBaseUri(), realm.getName()).toString(); } else { return redirectUri; } }
@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(); }
public String getLogoutUrl() { return Urls.accountLogout(baseQueryURI, currentURI, realm).toString(); }
public String getTotpRemoveUrl() { return Urls.accountTotpRemove(baseQueryURI, realm, stateChecker).toString(); }
public String getRevokeClientUrl() { return Urls.accountRevokeClientPage(baseQueryURI, realm).toString(); }
public String getSessionsLogoutUrl() { return Urls.accountSessionsLogoutPage(baseQueryURI, realm, stateChecker).toString(); }
public String getLoginUpdateTotpUrl() { return Urls.loginActionUpdateTotp(baseURI, realm).toString(); }
@Override protected URI getBaseRedirectUri() { return Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()); }
public String getRegistrationAction() { return Urls.realmRegisterAction(baseURI, realm).toString(); }
public String getPasswordUrl() { return Urls.accountPasswordPage(baseQueryURI, realm).toString(); }
public String getRegistrationUrl() { return Urls.realmRegisterPage(baseURI, realm).toString(); }
public String getLoginEmailVerificationUrl() { return Urls.loginActionEmailVerification(baseURI, realm).toString(); }
public String getLoginUsernameReminderUrl() { return Urls.loginUsernameReminder(baseURI, realm).toString(); }
public String getLoginPasswordResetUrl() { return Urls.loginPasswordReset(baseURI, realm).toString(); }
public String getLoginUpdateProfileUrl() { return Urls.loginActionUpdateProfile(baseURI, realm).toString(); }
public String getResourcesPath() { URI uri = Urls.themeRoot(baseURI); return uri.getPath() + "/" + theme.getType().toString().toLowerCase() + "/" + theme.getName(); }
public String getLoginUrl() { return Urls.realmLoginPage(baseURI, realm).toString(); }
public String getLogUrl() { return Urls.accountLogPage(baseQueryURI, realm).toString(); }
@Path("federated-identity-update") @GET public Response processFederatedIdentityUpdate( @QueryParam("action") String action, @QueryParam("provider_id") String providerId, @QueryParam("stateChecker") String stateChecker) { if (auth == null) { return login("identity"); } require(AccountRoles.MANAGE_ACCOUNT); csrfCheck(stateChecker); UserModel user = auth.getUser(); if (Validation.isEmpty(providerId)) { setReferrerOnPage(); return account .setError(Messages.MISSING_IDENTITY_PROVIDER) .createResponse(AccountPages.FEDERATED_IDENTITY); } AccountSocialAction accountSocialAction = AccountSocialAction.getAction(action); if (accountSocialAction == null) { setReferrerOnPage(); return account .setError(Messages.INVALID_FEDERATED_IDENTITY_ACTION) .createResponse(AccountPages.FEDERATED_IDENTITY); } boolean hasProvider = false; for (IdentityProviderModel model : realm.getIdentityProviders()) { if (model.getAlias().equals(providerId)) { hasProvider = true; } } if (!hasProvider) { setReferrerOnPage(); return account .setError(Messages.IDENTITY_PROVIDER_NOT_FOUND) .createResponse(AccountPages.FEDERATED_IDENTITY); } if (!user.isEnabled()) { setReferrerOnPage(); return account .setError(Messages.ACCOUNT_DISABLED) .createResponse(AccountPages.FEDERATED_IDENTITY); } switch (accountSocialAction) { case ADD: String redirectUri = UriBuilder.fromUri( Urls.accountFederatedIdentityPage(uriInfo.getBaseUri(), realm.getName())) .build() .toString(); try { ClientSessionModel clientSession = auth.getClientSession(); ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession); clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); clientSession.setRedirectUri(redirectUri); clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, UUID.randomUUID().toString()); return Response.temporaryRedirect( Urls.identityProviderAuthnRequest( this.uriInfo.getBaseUri(), providerId, realm.getName(), clientSessionCode.getCode())) .build(); } catch (Exception spe) { setReferrerOnPage(); return account .setError(Messages.IDENTITY_PROVIDER_REDIRECT_ERROR) .createResponse(AccountPages.FEDERATED_IDENTITY); } case REMOVE: FederatedIdentityModel link = session.users().getFederatedIdentity(user, providerId, realm); if (link != null) { // Removing last social provider is not possible if you don't have other possibility to // authenticate if (session.users().getFederatedIdentities(user, realm).size() > 1 || user.getFederationLink() != null || isPasswordSet(user)) { session.users().removeFederatedIdentity(realm, user, providerId); logger.debugv( "Social provider {0} removed successfully from user {1}", providerId, user.getUsername()); event .event(EventType.REMOVE_FEDERATED_IDENTITY) .client(auth.getClient()) .user(auth.getUser()) .detail(Details.USERNAME, link.getUserId() + "@" + link.getIdentityProvider()) .success(); setReferrerOnPage(); return account .setSuccess(Messages.IDENTITY_PROVIDER_REMOVED) .createResponse(AccountPages.FEDERATED_IDENTITY); } else { setReferrerOnPage(); return account .setError(Messages.FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER) .createResponse(AccountPages.FEDERATED_IDENTITY); } } else { setReferrerOnPage(); return account .setError(Messages.FEDERATED_IDENTITY_NOT_ACTIVE) .createResponse(AccountPages.FEDERATED_IDENTITY); } default: throw new IllegalArgumentException(); } }
public String getSessionsUrl() { return Urls.accountSessionsPage(baseQueryURI, realm).toString(); }
public String getSocialUrl() { return Urls.accountFederatedIdentityPage(baseQueryURI, realm).toString(); }
public String getLoginUpdatePasswordUrl() { return Urls.loginActionUpdatePassword(baseURI, realm).toString(); }
/** @author <a href="mailto:[email protected]">Marek Posolda</a> */ public class AccountApplicationsPage extends AbstractAccountPage { private String path = Urls.accountApplicationsPage(UriBuilder.fromUri(Constants.AUTH_SERVER_ROOT).build(), "test") .toString(); @Override public boolean isCurrent() { return driver.getTitle().contains("Account Management") && driver.getCurrentUrl().endsWith("/account/applications"); } @Override public void open() { driver.navigate().to(path); } public void setPath(String path) { this.path = path; } public void revokeGrant(String clientId) { driver.findElement(By.id("revoke-" + clientId)).click(); } public Map<String, AppEntry> getApplications() { Map<String, AppEntry> table = new HashMap<String, AppEntry>(); for (WebElement r : driver.findElements(By.tagName("tr"))) { int count = 0; AppEntry currentEntry = null; for (WebElement col : r.findElements(By.tagName("td"))) { count++; switch (count) { case 1: currentEntry = new AppEntry(); String client = col.getText(); table.put(client, currentEntry); break; case 2: String rolesStr = col.getText(); String[] roles = rolesStr.split(","); for (String role : roles) { role = role.trim(); currentEntry.addAvailableRole(role); } break; case 3: rolesStr = col.getText(); if (rolesStr.isEmpty()) break; roles = rolesStr.split(","); for (String role : roles) { role = role.trim(); currentEntry.addGrantedRole(role); } break; case 4: String protMappersStr = col.getText(); if (protMappersStr.isEmpty()) break; String[] protMappers = protMappersStr.split(","); for (String protMapper : protMappers) { protMapper = protMapper.trim(); currentEntry.addMapper(protMapper); } break; case 5: String additionalGrant = col.getText(); if (additionalGrant.isEmpty()) break; String[] grants = additionalGrant.split(","); for (String grant : grants) { grant = grant.trim(); currentEntry.addAdditionalGrant(grant); } break; } } } table.remove("Application"); return table; } public static class AppEntry { private final List<String> rolesAvailable = new ArrayList<String>(); private final List<String> rolesGranted = new ArrayList<String>(); private final List<String> protocolMappersGranted = new ArrayList<String>(); private final List<String> additionalGrants = new ArrayList<>(); private void addAvailableRole(String role) { rolesAvailable.add(role); } private void addGrantedRole(String role) { rolesGranted.add(role); } private void addMapper(String protocolMapper) { protocolMappersGranted.add(protocolMapper); } private void addAdditionalGrant(String grant) { additionalGrants.add(grant); } public List<String> getRolesGranted() { return rolesGranted; } public List<String> getRolesAvailable() { return rolesAvailable; } public List<String> getProtocolMappersGranted() { return protocolMappersGranted; } public List<String> getAdditionalGrants() { return additionalGrants; } } }
public String getTotpUrl() { return Urls.accountTotpPage(baseQueryURI, realm).toString(); }