/* * Copyright 2017 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.authentication.actiontoken.resetcred; import org.keycloak.TokenVerifier.Predicate; import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.authentication.actiontoken.*; import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator; import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext; import org.keycloak.events.Errors; import org.keycloak.events.EventType; import org.keycloak.models.UserModel; import org.keycloak.services.ErrorPage; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.LoginActionsService; import org.keycloak.services.resources.LoginActionsServiceChecks.IsActionRequired; import org.keycloak.sessions.CommonClientSessionModel.Action; import javax.ws.rs.core.Response; import static org.keycloak.services.resources.LoginActionsService.RESET_CREDENTIALS_PATH; /** * * @author hmlnarik */ public class ResetCredentialsActionTokenHandler extends AbstractActionTokenHander<ResetCredentialsActionToken> { public ResetCredentialsActionTokenHandler() { super( ResetCredentialsActionToken.TOKEN_TYPE, ResetCredentialsActionToken.class, Messages.RESET_CREDENTIAL_NOT_ALLOWED, EventType.RESET_PASSWORD, Errors.NOT_ALLOWED ); } @Override public Predicate<? super ResetCredentialsActionToken>[] getVerifiers(ActionTokenContext<ResetCredentialsActionToken> tokenContext) { return new Predicate[] { TokenUtils.checkThat(tokenContext.getRealm()::isResetPasswordAllowed, Errors.NOT_ALLOWED, Messages.RESET_CREDENTIAL_NOT_ALLOWED), new IsActionRequired(tokenContext, Action.AUTHENTICATE) }; } @Override public Response handleToken(ResetCredentialsActionToken token, ActionTokenContext tokenContext) { AuthenticationProcessor authProcessor = new ResetCredsAuthenticationProcessor(); return tokenContext.processFlow( false, RESET_CREDENTIALS_PATH, tokenContext.getRealm().getResetCredentialsFlow(), null, authProcessor ); } @Override public boolean canUseTokenRepeatedly(ResetCredentialsActionToken token, ActionTokenContext tokenContext) { return false; } public static class ResetCredsAuthenticationProcessor extends AuthenticationProcessor { @Override protected Response authenticationComplete() { boolean firstBrokerLoginInProgress = (authenticationSession.getAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE) != null); if (firstBrokerLoginInProgress) { UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, authenticationSession); if (!linkingUser.getId().equals(authenticationSession.getAuthenticatedUser().getId())) { return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE, authenticationSession.getAuthenticatedUser().getUsername(), linkingUser.getUsername() ); } SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE); authenticationSession.setAuthNote(AbstractIdpAuthenticator.FIRST_BROKER_LOGIN_SUCCESS, serializedCtx.getIdentityProviderId()); logger.debugf("Forget-password flow finished when authenticated user '%s' after first broker login with identity provider '%s'.", linkingUser.getUsername(), serializedCtx.getIdentityProviderId()); return LoginActionsService.redirectToAfterBrokerLoginEndpoint(session, realm, uriInfo, authenticationSession, true); } else { return super.authenticationComplete(); } } } }