use of org.keycloak.events.EventBuilder in project keycloak by keycloak.
the class UpdateTotp method processAction.
@Override
public void processAction(RequiredActionContext context) {
EventBuilder event = context.getEvent();
event.event(EventType.UPDATE_TOTP);
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
String challengeResponse = formData.getFirst("totp");
String totpSecret = formData.getFirst("totpSecret");
String mode = formData.getFirst("mode");
String userLabel = formData.getFirst("userLabel");
OTPPolicy policy = context.getRealm().getOTPPolicy();
OTPCredentialModel credentialModel = OTPCredentialModel.createFromPolicy(context.getRealm(), totpSecret, userLabel);
if (Validation.isBlank(challengeResponse)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_CODE, Messages.MISSING_TOTP)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
} else if (!validateOTPCredential(context, challengeResponse, credentialModel, policy)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_CODE, Messages.INVALID_TOTP)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
}
OTPCredentialProvider otpCredentialProvider = (OTPCredentialProvider) context.getSession().getProvider(CredentialProvider.class, "keycloak-otp");
final Stream<CredentialModel> otpCredentials = (otpCredentialProvider.isConfiguredFor(context.getRealm(), context.getUser())) ? context.getSession().userCredentialManager().getStoredCredentialsByTypeStream(context.getRealm(), context.getUser(), OTPCredentialModel.TYPE) : Stream.empty();
if (otpCredentials.count() >= 1 && Validation.isBlank(userLabel)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_LABEL, Messages.MISSING_TOTP_DEVICE_NAME)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
}
if (!CredentialHelper.createOTPCredential(context.getSession(), context.getRealm(), context.getUser(), challengeResponse, credentialModel)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_CODE, Messages.INVALID_TOTP)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
}
context.success();
}
use of org.keycloak.events.EventBuilder in project keycloak by keycloak.
the class VerifyEmail method requiredActionChallenge.
@Override
public void requiredActionChallenge(RequiredActionContext context) {
AuthenticationSessionModel authSession = context.getAuthenticationSession();
if (context.getUser().isEmailVerified()) {
context.success();
authSession.removeAuthNote(Constants.VERIFY_EMAIL_KEY);
return;
}
String email = context.getUser().getEmail();
if (Validation.isBlank(email)) {
context.ignore();
return;
}
LoginFormsProvider loginFormsProvider = context.form();
Response challenge;
authSession.setClientNote(AuthorizationEndpointBase.APP_INITIATED_FLOW, null);
// Do not allow resending e-mail by simple page refresh, i.e. when e-mail sent, it should be resent properly via email-verification endpoint
if (!Objects.equals(authSession.getAuthNote(Constants.VERIFY_EMAIL_KEY), email)) {
authSession.setAuthNote(Constants.VERIFY_EMAIL_KEY, email);
EventBuilder event = context.getEvent().clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, email);
challenge = sendVerifyEmail(context.getSession(), loginFormsProvider, context.getUser(), context.getAuthenticationSession(), event);
} else {
challenge = loginFormsProvider.createResponse(UserModel.RequiredAction.VERIFY_EMAIL);
}
context.challenge(challenge);
}
use of org.keycloak.events.EventBuilder in project keycloak by keycloak.
the class AccountFormService method processPasswordUpdate.
/**
* Update account password
* <p>
* Form params:
* <p>
* password - old password
* password-new
* pasword-confirm
*
* @return
*/
@Path("password")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processPasswordUpdate() {
MultivaluedMap<String, String> formData = request.getDecodedFormParameters();
if (auth == null) {
return login("password");
}
auth.require(AccountRoles.MANAGE_ACCOUNT);
csrfCheck(formData);
UserModel user = auth.getUser();
boolean requireCurrent = isPasswordSet(session, realm, user);
account.setPasswordSet(requireCurrent);
String password = formData.getFirst("password");
String passwordNew = formData.getFirst("password-new");
String passwordConfirm = formData.getFirst("password-confirm");
EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR).client(auth.getClient()).user(auth.getSession().getUser());
if (requireCurrent) {
if (Validation.isBlank(password)) {
setReferrerOnPage();
errorEvent.error(Errors.PASSWORD_MISSING);
return account.setError(Status.OK, Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
}
UserCredentialModel cred = UserCredentialModel.password(password);
if (!session.userCredentialManager().isValid(realm, user, cred)) {
setReferrerOnPage();
errorEvent.error(Errors.INVALID_USER_CREDENTIALS);
return account.setError(Status.OK, Messages.INVALID_PASSWORD_EXISTING).createResponse(AccountPages.PASSWORD);
}
}
if (Validation.isBlank(passwordNew)) {
setReferrerOnPage();
errorEvent.error(Errors.PASSWORD_MISSING);
return account.setError(Status.OK, Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
}
if (!passwordNew.equals(passwordConfirm)) {
setReferrerOnPage();
errorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
return account.setError(Status.OK, Messages.INVALID_PASSWORD_CONFIRM).createResponse(AccountPages.PASSWORD);
}
try {
session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password(passwordNew, false));
} catch (ReadOnlyException mre) {
setReferrerOnPage();
errorEvent.error(Errors.NOT_ALLOWED);
return account.setError(Response.Status.BAD_REQUEST, Messages.READ_ONLY_PASSWORD).createResponse(AccountPages.PASSWORD);
} catch (ModelException me) {
ServicesLogger.LOGGER.failedToUpdatePassword(me);
setReferrerOnPage();
errorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
return account.setError(Response.Status.NOT_ACCEPTABLE, me.getMessage(), me.getParameters()).createResponse(AccountPages.PASSWORD);
} catch (Exception ape) {
ServicesLogger.LOGGER.failedToUpdatePassword(ape);
setReferrerOnPage();
errorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
return account.setError(Response.Status.INTERNAL_SERVER_ERROR, ape.getMessage()).createResponse(AccountPages.PASSWORD);
}
session.sessions().getUserSessionsStream(realm, user).filter(s -> !Objects.equals(s.getId(), auth.getSession().getId())).collect(// collect to avoid concurrent modification as backchannelLogout removes the user sessions.
Collectors.toList()).forEach(s -> AuthenticationManager.backchannelLogout(session, realm, s, session.getContext().getUri(), 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);
}
use of org.keycloak.events.EventBuilder in project keycloak by keycloak.
the class AdminEventQueryTest method testQuery.
@Test
public void testQuery() {
inRolledBackTransaction(null, (session, t) -> {
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
RealmModel realm = session.realms().createRealm("realm");
ClientConnection cc = new DummyClientConnection();
eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u1").getEvent());
eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u2").getEvent());
eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u3").getEvent());
eventStore.onEvent(new EventBuilder(realm, null, cc).event(EventType.LOGIN).user("u4").getEvent());
assertThat(eventStore.createQuery().firstResult(2).getResultStream().collect(Collectors.counting()), is(2L));
});
}
use of org.keycloak.events.EventBuilder in project keycloak-project-example by thomasdarimont.
the class UpdateEmailRequiredAction method processAction.
@Override
public void processAction(RequiredActionContext context) {
if (isCancelApplicationInitiatedAction(context)) {
RequiredActionUtils.cancelApplicationInitiatedAction(context, ID, authSession -> {
authSession.removeAuthNote(AUTH_NOTE_CODE);
authSession.removeAuthNote(UPDATE_EMAIL_AUTH_NOTE);
});
return;
}
// TODO trigger email verification via email
// user submitted the form
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
EventBuilder event = context.getEvent().clone().event(EventType.UPDATE_EMAIL);
AuthenticationSessionModel authSession = context.getAuthenticationSession();
RealmModel realm = context.getRealm();
UserModel currentUser = context.getUser();
UserModel user = currentUser;
KeycloakSession session = context.getSession();
String newEmail = String.valueOf(formData.getFirst(EMAIL_FIELD)).trim();
event.detail(Details.EMAIL, newEmail);
EventBuilder errorEvent = event.clone().event(EventType.UPDATE_EMAIL_ERROR).client(authSession.getClient()).user(authSession.getAuthenticatedUser());
if (formData.getFirst("update") != null) {
final String emailError;
if (Validation.isBlank(newEmail) || !Validation.isEmailValid(newEmail)) {
emailError = "invalidEmailMessage";
errorEvent.detail("error", "invalid-email-format");
} else if (Objects.equals(newEmail, user.getEmail())) {
emailError = "invalidEmailSameAddressMessage";
errorEvent.detail("error", "invalid-email-same-email");
} else if (session.users().getUserByEmail(realm, newEmail) != null) {
emailError = "invalidEmailMessage";
errorEvent.detail("error", "invalid-email-already-in-use");
} else {
emailError = null;
}
if (emailError != null) {
errorEvent.error(Errors.INVALID_INPUT);
Response challenge = createForm(context, form -> {
form.addError(new FormMessage(EMAIL_FIELD, emailError));
});
context.challenge(challenge);
return;
}
String code = RandomString.randomCode(VERIFY_CODE_LENGTH).toLowerCase();
authSession.setAuthNote(AUTH_NOTE_CODE, code);
LoginFormsProvider form = context.form();
form.setAttribute("currentEmail", newEmail);
try {
EmailTemplateProvider emailTemplateProvider = session.getProvider(EmailTemplateProvider.class);
emailTemplateProvider.setRealm(realm);
// adapt current user to be able to override the email for the verification email
UserModel userAdapter = new InMemoryUserAdapter(session, realm, currentUser.getId());
userAdapter.setEmail(newEmail);
userAdapter.setUsername(currentUser.getUsername());
userAdapter.setFirstName(currentUser.getFirstName());
userAdapter.setLastName(currentUser.getLastName());
emailTemplateProvider.setUser(userAdapter);
Map<String, Object> attributes = new HashMap<>();
attributes.put("code", code);
attributes.put("user", new ProfileBean(user) {
@Override
public String getEmail() {
return newEmail;
}
});
String realmDisplayName = realm.getDisplayName();
if (realmDisplayName == null) {
realmDisplayName = realm.getName();
}
emailTemplateProvider.send("acmeEmailVerifySubject", List.of(realmDisplayName), "acme-email-verification-with-code.ftl", attributes);
authSession.setAuthNote(UPDATE_EMAIL_AUTH_NOTE, newEmail);
form.setInfo("emailSentInfo", newEmail);
context.challenge(form.createForm("verify-email-form.ftl"));
} catch (EmailException e) {
log.errorf(e, "Could not send verify email.");
context.failure();
}
return;
}
if (formData.getFirst("verify") != null) {
String emailFromAuthNote = authSession.getAuthNote(UPDATE_EMAIL_AUTH_NOTE);
String expectedCode = authSession.getAuthNote(AUTH_NOTE_CODE);
String actualCode = String.valueOf(formData.getFirst("code")).trim();
if (!expectedCode.equals(actualCode)) {
LoginFormsProvider form = context.form();
form.setAttribute("currentEmail", emailFromAuthNote);
form.setErrors(List.of(new FormMessage("code", "error-invalid-code")));
context.challenge(form.createForm("verify-email-form.ftl"));
return;
}
user.setEmail(emailFromAuthNote);
user.setEmailVerified(true);
user.removeRequiredAction(ID);
event.success();
context.success();
return;
}
context.failure();
}
Aggregations