Search in sources :

Example 6 with EventBuilder

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();
}
Also used : Response(javax.ws.rs.core.Response) EventBuilder(org.keycloak.events.EventBuilder) CredentialModel(org.keycloak.credential.CredentialModel) OTPCredentialModel(org.keycloak.models.credential.OTPCredentialModel) OTPCredentialProvider(org.keycloak.credential.OTPCredentialProvider) CredentialProvider(org.keycloak.credential.CredentialProvider) OTPCredentialModel(org.keycloak.models.credential.OTPCredentialModel) OTPPolicy(org.keycloak.models.OTPPolicy) FormMessage(org.keycloak.models.utils.FormMessage) OTPCredentialProvider(org.keycloak.credential.OTPCredentialProvider)

Example 7 with EventBuilder

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);
}
Also used : AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) LoginFormsProvider(org.keycloak.forms.login.LoginFormsProvider) EventBuilder(org.keycloak.events.EventBuilder)

Example 8 with EventBuilder

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);
}
Also used : UserModel(org.keycloak.models.UserModel) EventBuilder(org.keycloak.events.EventBuilder) ModelException(org.keycloak.models.ModelException) UserCredentialModel(org.keycloak.models.UserCredentialModel) ReadOnlyException(org.keycloak.storage.ReadOnlyException) ReadOnlyException(org.keycloak.storage.ReadOnlyException) NotFoundException(javax.ws.rs.NotFoundException) ForbiddenException(org.keycloak.services.ForbiddenException) IOException(java.io.IOException) ModelException(org.keycloak.models.ModelException) ValidationException(org.keycloak.userprofile.ValidationException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes)

Example 9 with EventBuilder

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));
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) EventBuilder(org.keycloak.events.EventBuilder) ClientConnection(org.keycloak.common.ClientConnection) EventStoreProvider(org.keycloak.events.EventStoreProvider) KeycloakModelTest(org.keycloak.testsuite.model.KeycloakModelTest) Test(org.junit.Test)

Example 10 with EventBuilder

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();
}
Also used : ProfileBean(org.keycloak.email.freemarker.beans.ProfileBean) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) HashMap(java.util.HashMap) RandomString(org.keycloak.common.util.RandomString) RealmModel(org.keycloak.models.RealmModel) UserModel(org.keycloak.models.UserModel) Response(javax.ws.rs.core.Response) LoginFormsProvider(org.keycloak.forms.login.LoginFormsProvider) EventBuilder(org.keycloak.events.EventBuilder) InMemoryUserAdapter(org.keycloak.storage.adapter.InMemoryUserAdapter) KeycloakSession(org.keycloak.models.KeycloakSession) EmailTemplateProvider(org.keycloak.email.EmailTemplateProvider) EmailException(org.keycloak.email.EmailException) FormMessage(org.keycloak.models.utils.FormMessage)

Aggregations

EventBuilder (org.keycloak.events.EventBuilder)35 RealmModel (org.keycloak.models.RealmModel)20 UserModel (org.keycloak.models.UserModel)13 AuthenticationSessionModel (org.keycloak.sessions.AuthenticationSessionModel)12 Response (javax.ws.rs.core.Response)11 Path (javax.ws.rs.Path)8 KeycloakSession (org.keycloak.models.KeycloakSession)7 ClientModel (org.keycloak.models.ClientModel)6 UserSessionModel (org.keycloak.models.UserSessionModel)6 FormMessage (org.keycloak.models.utils.FormMessage)6 ClientSessionContext (org.keycloak.models.ClientSessionContext)5 HashMap (java.util.HashMap)4 List (java.util.List)4 ClientConnection (org.keycloak.common.ClientConnection)4 LoginFormsProvider (org.keycloak.forms.login.LoginFormsProvider)4 AccessToken (org.keycloak.representations.AccessToken)4 EmailException (org.keycloak.email.EmailException)3 KeycloakContext (org.keycloak.models.KeycloakContext)3 TokenManager (org.keycloak.protocol.oidc.TokenManager)3 RootAuthenticationSessionModel (org.keycloak.sessions.RootAuthenticationSessionModel)3