package org.apereo.cas.web.flow;
import org.apereo.cas.authentication.PrincipalException;
import org.apereo.cas.authentication.RememberMeUsernamePasswordCredential;
import org.apereo.cas.authentication.UsernamePasswordCredential;
import org.apereo.cas.authentication.adaptive.UnauthorizedAuthenticationException;
import org.apereo.cas.authentication.exceptions.AccountDisabledException;
import org.apereo.cas.authentication.exceptions.AccountPasswordMustChangeException;
import org.apereo.cas.authentication.exceptions.InvalidLoginLocationException;
import org.apereo.cas.authentication.exceptions.InvalidLoginTimeException;
import org.apereo.cas.authentication.principal.Response;
import org.apereo.cas.services.UnauthorizedServiceException;
import org.apereo.cas.services.UnauthorizedServiceForPrincipalException;
import org.apereo.cas.services.UnauthorizedSsoServiceException;
import org.apereo.cas.ticket.UnsatisfiedAuthenticationPolicyException;
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
import org.springframework.webflow.engine.ActionState;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.engine.builder.BinderConfiguration;
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
import org.springframework.webflow.engine.support.TransitionExecutingFlowExecutionExceptionHandler;
import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException;
import javax.security.auth.login.AccountLockedException;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.FailedLoginException;
/**
* This is {@link DefaultWebflowConfigurer}.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
public class DefaultWebflowConfigurer extends AbstractCasWebflowConfigurer {
/**
* Instantiates a new Default webflow configurer.
*
* @param flowBuilderServices the flow builder services
* @param flowDefinitionRegistry the flow definition registry
*/
public DefaultWebflowConfigurer(final FlowBuilderServices flowBuilderServices,
final FlowDefinitionRegistry flowDefinitionRegistry) {
super(flowBuilderServices, flowDefinitionRegistry);
}
@Override
protected void doInitialize() throws Exception {
final Flow flow = getLoginFlow();
if (flow != null) {
createDefaultGlobalExceptionHandlers(flow);
createDefaultEndStates(flow);
createDefaultDecisionStates(flow);
createDefaultActionStates(flow);
createRememberMeAuthnWebflowConfig(flow);
}
}
/**
* Create remember me authn webflow config.
*
* @param flow the flow
*/
protected void createRememberMeAuthnWebflowConfig(final Flow flow) {
if (casProperties.getTicket().getTgt().getRememberMe().isEnabled()) {
createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, RememberMeUsernamePasswordCredential.class);
final ViewState state = (ViewState) flow.getState(CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);
final BinderConfiguration cfg = getViewStateBinderConfiguration(state);
cfg.addBinding(new BinderConfiguration.Binding("rememberMe", null, false));
} else {
createFlowVariable(flow, CasWebflowConstants.VAR_ID_CREDENTIAL, UsernamePasswordCredential.class);
}
}
/**
* Create default action states.
*
* @param flow the flow
*/
protected void createDefaultActionStates(final Flow flow) {
createTerminateSessionAction(flow);
createGatewayServicesMgmtAction(flow);
createServiceAuthorizationCheckAction(flow);
createRedirectToServiceActionState(flow);
createHandleAuthenticationFailureAction(flow);
}
/**
* Create handle authentication failure action.
*
* @param flow the flow
*/
protected void createHandleAuthenticationFailureAction(final Flow flow) {
final ActionState handler = createActionState(flow,
"handleAuthenticationFailure",
createEvaluateAction("authenticationExceptionHandler"));
createTransition(AccountDisabledException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_ACCOUNT_DISABLED);
createTransition(AccountLockedException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_ACCOUNT_LOCKED);
createTransition(AccountPasswordMustChangeException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD);
createTransition(CredentialExpiredException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_EXPIRED_PASSWORD);
createTransition(InvalidLoginLocationException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_INVALID_WORKSTATION);
createTransition(InvalidLoginTimeException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_INVALID_AUTHENTICATION_HOURS);
createTransition(FailedLoginException.class.getSimpleName(), CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
createTransition(AccountNotFoundException.class.getSimpleName(), CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
createTransition(UnauthorizedServiceForPrincipalException.class.getSimpleName(), CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
createTransition(PrincipalException.class.getSimpleName(), CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
createTransition(UnsatisfiedAuthenticationPolicyException.class.getSimpleName(), CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
createTransition(UnauthorizedAuthenticationException.class.getSimpleName(), CasWebflowConstants.VIEW_ID_AUTHENTICATION_BLOCKED);
createStateDefaultTransition(handler, CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
}
/**
* Create redirect to service action state.
*
* @param flow the flow
*/
protected void createRedirectToServiceActionState(final Flow flow) {
final ActionState redirectToView = createActionState(flow,
CasWebflowConstants.STATE_ID_REDIRECT,
createEvaluateAction("redirectToServiceAction"));
createTransitionForState(redirectToView, Response.ResponseType.POST.name().toLowerCase(), CasWebflowConstants.STATE_ID_POST_VIEW);
createTransitionForState(redirectToView, Response.ResponseType.REDIRECT.name().toLowerCase(), CasWebflowConstants.STATE_ID_REDIR_VIEW);
}
/**
* Create service authorization check action.
*
* @param flow the flow
*/
private void createServiceAuthorizationCheckAction(final Flow flow) {
final ActionState serviceAuthorizationCheck = createActionState(flow,
CasWebflowConstants.STATE_ID_SERVICE_AUTHZ_CHECK, createEvaluateAction("serviceAuthorizationCheck"));
createStateDefaultTransition(serviceAuthorizationCheck, CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
}
/**
* Create gateway services mgmt action.
*
* @param flow the flow
*/
protected void createGatewayServicesMgmtAction(final Flow flow) {
final ActionState gatewayServicesManagementCheck = createActionState(flow,
CasWebflowConstants.STATE_ID_GATEWAY_SERVICES_MGMT_CHECK, createEvaluateAction("gatewayServicesManagementCheck"));
createTransitionForState(gatewayServicesManagementCheck, CasWebflowConstants.STATE_ID_SUCCESS,
CasWebflowConstants.STATE_ID_REDIRECT);
}
/**
* Create terminate session action.
*
* @param flow the flow
*/
protected void createTerminateSessionAction(final Flow flow) {
final ActionState terminateSession = createActionState(flow,
CasWebflowConstants.STATE_ID_TERMINATE_SESSION, createEvaluateAction("terminateSessionAction"));
createStateDefaultTransition(terminateSession, CasWebflowConstants.STATE_ID_GATEWAY_REQUEST_CHECK);
}
/**
* Create default global exception handlers.
*
* @param flow the flow
*/
protected void createDefaultEndStates(final Flow flow) {
createRedirectUnauthorizedServiceUrlEndState(flow);
createServiceErrorEndState(flow);
createRedirectEndState(flow);
createPostEndState(flow);
createGenericLoginSuccessEndState(flow);
createServiceWarningViewState(flow);
}
/**
* Create redirect end state.
*
* @param flow the flow
*/
protected void createRedirectEndState(final Flow flow) {
createEndState(flow, CasWebflowConstants.STATE_ID_REDIR_VIEW, "requestScope.url", true);
}
/**
* Create post end state.
*
* @param flow the flow
*/
protected void createPostEndState(final Flow flow) {
createEndState(flow, CasWebflowConstants.STATE_ID_POST_VIEW, CasWebflowConstants.VIEW_ID_POST_RESPONSE);
}
/**
* Create redirect unauthorized service url end state.
*
* @param flow the flow
*/
protected void createRedirectUnauthorizedServiceUrlEndState(final Flow flow) {
createEndState(flow, CasWebflowConstants.STATE_ID_VIEW_REDIR_UNAUTHZ_URL, "flowScope.unauthorizedRedirectUrl", true);
}
/**
* Create service error end state.
*
* @param flow the flow
*/
private void createServiceErrorEndState(final Flow flow) {
createEndState(flow, CasWebflowConstants.STATE_ID_VIEW_SERVICE_ERROR, CasWebflowConstants.VIEW_ID_SERVICE_ERROR);
}
/**
* Create generic login success end state.
*
* @param flow the flow
*/
private void createGenericLoginSuccessEndState(final Flow flow) {
final EndState state = createEndState(flow, CasWebflowConstants.STATE_ID_VIEW_GENERIC_LOGIN_SUCCESS, CasWebflowConstants.VIEW_ID_GENERIC_SUCCESS);
state.getEntryActionList().add(createEvaluateAction("genericSuccessViewAction"));
}
/**
* Create service warning view state.
*
* @param flow the flow
*/
protected void createServiceWarningViewState(final Flow flow) {
final ViewState stateWarning = createViewState(flow, CasWebflowConstants.STATE_ID_SHOW_WARNING_VIEW, CasWebflowConstants.VIEW_ID_CONFIRM);
createTransitionForState(stateWarning, CasWebflowConstants.TRANSITION_ID_SUCCESS, "finalizeWarning");
final ActionState finalizeWarn = createActionState(flow, "finalizeWarning", createEvaluateAction("serviceWarningAction"));
createTransitionForState(finalizeWarn, CasWebflowConstants.STATE_ID_REDIRECT, CasWebflowConstants.STATE_ID_REDIRECT);
}
/**
* Create default global exception handlers.
*
* @param flow the flow
*/
protected void createDefaultGlobalExceptionHandlers(final Flow flow) {
final TransitionExecutingFlowExecutionExceptionHandler h = new TransitionExecutingFlowExecutionExceptionHandler();
h.add(UnauthorizedSsoServiceException.class, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM);
h.add(NoSuchFlowExecutionException.class, CasWebflowConstants.STATE_ID_VIEW_SERVICE_ERROR);
h.add(UnauthorizedServiceException.class, CasWebflowConstants.STATE_ID_SERVICE_UNAUTHZ_CHECK);
h.add(UnauthorizedServiceForPrincipalException.class, CasWebflowConstants.STATE_ID_SERVICE_UNAUTHZ_CHECK);
flow.getExceptionHandlerSet().add(h);
}
/**
* Create default decision states.
*
* @param flow the flow
*/
protected void createDefaultDecisionStates(final Flow flow) {
createServiceUnauthorizedCheckDecisionState(flow);
createServiceCheckDecisionState(flow);
createWarnDecisionState(flow);
createGatewayRequestCheckDecisionState(flow);
createHasServiceCheckDecisionState(flow);
createRenewCheckDecisionState(flow);
}
/**
* Create service unauthorized check decision state.
*
* @param flow the flow
*/
protected void createServiceUnauthorizedCheckDecisionState(final Flow flow) {
createDecisionState(flow, CasWebflowConstants.STATE_ID_SERVICE_UNAUTHZ_CHECK,
"flowScope.unauthorizedRedirectUrl != null",
CasWebflowConstants.STATE_ID_VIEW_REDIR_UNAUTHZ_URL,
CasWebflowConstants.STATE_ID_VIEW_SERVICE_ERROR);
}
/**
* Create service check decision state.
*
* @param flow the flow
*/
protected void createServiceCheckDecisionState(final Flow flow) {
createDecisionState(flow, CasWebflowConstants.STATE_ID_SERVICE_CHECK,
"flowScope.service != null",
CasWebflowConstants.STATE_ID_GENERATE_SERVICE_TICKET,
CasWebflowConstants.STATE_ID_VIEW_GENERIC_LOGIN_SUCCESS);
}
/**
* Create warn decision state.
*
* @param flow the flow
*/
protected void createWarnDecisionState(final Flow flow) {
createDecisionState(flow, CasWebflowConstants.STATE_ID_WARN,
"flowScope.warnCookieValue",
CasWebflowConstants.STATE_ID_SHOW_WARNING_VIEW,
CasWebflowConstants.STATE_ID_REDIRECT);
}
/**
* Create gateway request check decision state.
*
* @param flow the flow
*/
protected void createGatewayRequestCheckDecisionState(final Flow flow) {
createDecisionState(flow, CasWebflowConstants.STATE_ID_GATEWAY_REQUEST_CHECK,
"requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null",
CasWebflowConstants.STATE_ID_GATEWAY_SERVICES_MGMT_CHECK,
CasWebflowConstants.STATE_ID_SERVICE_AUTHZ_CHECK);
}
/**
* Create has service check decision state.
*
* @param flow the flow
*/
protected void createHasServiceCheckDecisionState(final Flow flow) {
createDecisionState(flow, CasWebflowConstants.STATE_ID_HAS_SERVICE_CHECK,
"flowScope.service != null",
CasWebflowConstants.STATE_ID_RENEW_REQUEST_CHECK,
CasWebflowConstants.STATE_ID_VIEW_GENERIC_LOGIN_SUCCESS);
}
/**
* Create renew check decision state.
*
* @param flow the flow
*/
protected void createRenewCheckDecisionState(final Flow flow) {
createDecisionState(flow, CasWebflowConstants.STATE_ID_RENEW_REQUEST_CHECK,
"requestParameters.renew != '' and requestParameters.renew != null",
CasWebflowConstants.STATE_ID_SERVICE_AUTHZ_CHECK,
CasWebflowConstants.STATE_ID_GENERATE_SERVICE_TICKET);
}
}