/*
* 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.idpverifyemail;
import org.keycloak.authentication.actiontoken.AbstractActionTokenHander;
import org.keycloak.TokenVerifier.Predicate;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.actiontoken.*;
import org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticator;
import org.keycloak.events.*;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.UserModel;
import org.keycloak.services.managers.AuthenticationSessionManager;
import org.keycloak.services.messages.Messages;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.sessions.AuthenticationSessionProvider;
import java.util.Collections;
import javax.ws.rs.core.Response;
/**
* Action token handler for verification of e-mail address.
* @author hmlnarik
*/
public class IdpVerifyAccountLinkActionTokenHandler extends AbstractActionTokenHander<IdpVerifyAccountLinkActionToken> {
public IdpVerifyAccountLinkActionTokenHandler() {
super(
IdpVerifyAccountLinkActionToken.TOKEN_TYPE,
IdpVerifyAccountLinkActionToken.class,
Messages.STALE_CODE,
EventType.IDENTITY_PROVIDER_LINK_ACCOUNT,
Errors.INVALID_TOKEN
);
}
@Override
public Predicate<? super IdpVerifyAccountLinkActionToken>[] getVerifiers(ActionTokenContext<IdpVerifyAccountLinkActionToken> tokenContext) {
return TokenUtils.predicates(
);
}
@Override
public Response handleToken(IdpVerifyAccountLinkActionToken token, ActionTokenContext<IdpVerifyAccountLinkActionToken> tokenContext) {
UserModel user = tokenContext.getAuthenticationSession().getAuthenticatedUser();
EventBuilder event = tokenContext.getEvent();
event.event(EventType.IDENTITY_PROVIDER_LINK_ACCOUNT)
.detail(Details.EMAIL, user.getEmail())
.detail(Details.IDENTITY_PROVIDER, token.getIdentityProviderAlias())
.detail(Details.IDENTITY_PROVIDER_USERNAME, token.getIdentityProviderUsername())
.success();
// verify user email as we know it is valid as this entry point would never have gotten here.
user.setEmailVerified(true);
AuthenticationSessionModel authSession = tokenContext.getAuthenticationSession();
if (tokenContext.isAuthenticationSessionFresh()) {
AuthenticationSessionManager asm = new AuthenticationSessionManager(tokenContext.getSession());
asm.removeAuthenticationSession(tokenContext.getRealm(), authSession, true);
AuthenticationSessionProvider authSessProvider = tokenContext.getSession().authenticationSessions();
authSession = authSessProvider.getAuthenticationSession(tokenContext.getRealm(), token.getAuthenticationSessionId());
if (authSession != null) {
authSession.setAuthNote(IdpEmailVerificationAuthenticator.VERIFY_ACCOUNT_IDP_USERNAME, token.getIdentityProviderUsername());
} else {
authSessProvider.updateNonlocalSessionAuthNotes(
token.getAuthenticationSessionId(),
Collections.singletonMap(IdpEmailVerificationAuthenticator.VERIFY_ACCOUNT_IDP_USERNAME, token.getIdentityProviderUsername())
);
}
return tokenContext.getSession().getProvider(LoginFormsProvider.class)
.setSuccess(Messages.IDENTITY_PROVIDER_LINK_SUCCESS, token.getIdentityProviderAlias(), token.getIdentityProviderUsername())
.setAttribute("skipLink", true)
.createInfoPage();
}
authSession.setAuthNote(IdpEmailVerificationAuthenticator.VERIFY_ACCOUNT_IDP_USERNAME, token.getIdentityProviderUsername());
return tokenContext.brokerFlow(null, authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH));
}
}