All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.unicon.cas.mfa.web.flow.ValidateInitialMultiFactorAuthenticationRequestAction Maven / Gradle / Ivy

Go to download

This module is intended to include all the Java you need to add to a CAS implementation to take advantage of the extended multifactor authentication features in this project.

There is a newer version: 2.0.0-RC3
Show newest version
package net.unicon.cas.mfa.web.flow;

import net.unicon.cas.addons.authentication.AuthenticationSupport;
import net.unicon.cas.mfa.authentication.MultiFactorAuthenticationTransactionContext;
import net.unicon.cas.mfa.authentication.RequestedAuthenticationMethodRankingStrategy;
import net.unicon.cas.mfa.util.MultiFactorUtils;
import net.unicon.cas.mfa.web.flow.event.MultiFactorAuthenticationSpringWebflowEventBuilder;
import net.unicon.cas.mfa.web.flow.util.MultiFactorRequestContextUtils;
import net.unicon.cas.mfa.web.support.MultiFactorAuthenticationSupportingWebApplicationService;
import org.apache.commons.lang.StringUtils;
import org.jasig.cas.authentication.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;

import java.util.Set;

/**
 * Determines whether the login flow needs to branch *now* to honor the authentication method requirements of
 * 

*

* If the Service expresses a requirement for how the user must authenticate, * and there's an existing single sign-on session, and there is not a record in the user's * single sign-on session of having already fulfilled that requirement, then fires the `requireMfa` event indicating * that exceptional handling is required. Otherwise (i.e., if no exceptional authentication method is required, * or there is no existing single sign-on session, * or the required exceptional authentication method is already fulfilled) then fire the `requireTgt` event indicating * that the login flow should proceed as per normal. *

* More explicitly: *

*

*

    *
  1. If an authentication context does not exist * (i.e., the user does not have an existing single sign-on session with a record of a prior authentication), * continue the login flow as usual by firing the `requireTgt` event.
  2. *
  3. If an authentication context exists without any authentication method decoration, fire the * `requireMfa` event indicating that an exceptional flow is required to fulfill the service's authentication * requirements
  4. *
  5. If an authentication context exists with an authentication method decoration indicating an authentication * method other than that required by the service, fire the `requireMfa` event indicating that an exceptional flow * is required to fulfill the service's authentication requirements.
  6. *
  7. Otherwise, fire the `requireTgt` event to continue the login flow as per usual.
  8. *
*

* This means that in the case where there is not an existing single sign-on session, this Action will continue * the login flow as per normal even though additional authentication will be required * later in the flow to fulfill the authentication requirements of the CAS-using service. * * @author Misagh Moayyed */ public final class ValidateInitialMultiFactorAuthenticationRequestAction extends AbstractAction { private final Logger logger = LoggerFactory.getLogger(ValidateInitialMultiFactorAuthenticationRequestAction.class); /** * The Constant EVENT_ID_REQUIRE_TGT. */ public static final String EVENT_ID_REQUIRE_TGT = "requireTgt"; /** * The authentication support. */ private final AuthenticationSupport authenticationSupport; /** * Authentication method ranking strategy. */ private final RequestedAuthenticationMethodRankingStrategy authnMethodRankingStrategy; /** * Instantiates a new validate initial multifactor authentication request action. * * @param authSupport the authN support * @param authenticationMethodRankingStrategy authenticationMethodRankingStrategy */ public ValidateInitialMultiFactorAuthenticationRequestAction(final AuthenticationSupport authSupport, final RequestedAuthenticationMethodRankingStrategy authenticationMethodRankingStrategy) { this.authenticationSupport = authSupport; this.authnMethodRankingStrategy = authenticationMethodRankingStrategy; } /* (non-Javadoc) * @see org.springframework.webflow.action.AbstractAction#doExecute(org.springframework.webflow.execution.RequestContext) */ @Override protected Event doExecute(final RequestContext context) throws Exception { final MultiFactorAuthenticationTransactionContext mfaTx = MultiFactorRequestContextUtils.getMfaTransaction(context); if (mfaTx == null) { return new Event(this, EVENT_ID_REQUIRE_TGT); } final MultiFactorAuthenticationSupportingWebApplicationService mfaService = this.authnMethodRankingStrategy.computeHighestRankingAuthenticationMethod(mfaTx); final String requestedAuthenticationMethod = (mfaService != null) ? mfaService.getAuthenticationMethod() : null; final String tgt = MultiFactorRequestContextUtils.getTicketGrantingTicketId(context); /* * If the TGT is blank i.e. there is no existing SSO session, proceed with normal login flow * (Note that flow may need interrupted later if the CAS-using service requires an authentication method * not fulfilled by the normal login flow) */ if (StringUtils.isBlank(tgt)) { logger.trace("TGT is blank; proceed flow normally."); return new Event(this, EVENT_ID_REQUIRE_TGT); } /* * If the authentication method the CAS-using service has specified is blank, * proceed with the normal login flow. */ if (StringUtils.isBlank(requestedAuthenticationMethod)) { logger.trace("Since required authentication method is blank, proceed flow normally."); return new Event(this, EVENT_ID_REQUIRE_TGT); } logger.trace("Service [{}] requires authentication method [{}]", mfaTx.getTargetServiceId(), requestedAuthenticationMethod); final Authentication authentication = this.authenticationSupport.getAuthenticationFrom(tgt); /* * If somehow the TGT were to have no authentication, then interpret as an existing SSO session insufficient * to fulfill the requirements of this service, and branch to fulfill the authentication requirement. */ if (authentication == null) { logger.warn("TGT had no Authentication, which is odd. " + "Proceeding as if additional authentication required."); //Place the ranked mfa service into the flow scope to be available in the actual mfa subflows MultiFactorRequestContextUtils.setMultifactorWebApplicationService(context, mfaService); return new Event(this, getMultiFactorEventIdByAuthenticationMethod(requestedAuthenticationMethod)); } final Set previouslyAchievedAuthenticationMethods = MultiFactorUtils.getSatisfiedAuthenticationMethods(authentication); /* * If any of the recorded authentication methods from the prior Authentication are 'stronger' * than the authentication method requested to access the CAS-using service, proceed with the normal authentication flow. */ if (this.authnMethodRankingStrategy .anyPreviouslyAchievedAuthenticationMethodsStrongerThanRequestedOne(previouslyAchievedAuthenticationMethods, requestedAuthenticationMethod)) { logger.trace("Authentication method [{}] is EQUAL -- OR -- WEAKER than any previously fulfilled methods [{}]; " + "proceeding with flow normally...", requestedAuthenticationMethod, previouslyAchievedAuthenticationMethods); return new Event(this, EVENT_ID_REQUIRE_TGT); } logger.trace("Authentication method [{}] is STRONGER than any previously fulfilled methods [{}]; " + "branching to prompt for required authentication method.", requestedAuthenticationMethod, previouslyAchievedAuthenticationMethods); //Place the ranked mfa service into the flow scope to be available in the actual mfa subflows MultiFactorRequestContextUtils.setMultifactorWebApplicationService(context, mfaService); return new Event(this, getMultiFactorEventIdByAuthenticationMethod(requestedAuthenticationMethod)); } /** * Construct the next MFA event id based on the given authentication method. * * @param authnMethod the authentication method provided * * @return the next event in the flow, that is effectively the value of * {@link MultiFactorAuthenticationSpringWebflowEventBuilder#MFA_EVENT_ID_PREFIX} * prepended to the authentication method. */ private String getMultiFactorEventIdByAuthenticationMethod(final String authnMethod) { return MultiFactorAuthenticationSpringWebflowEventBuilder.MFA_EVENT_ID_PREFIX + authnMethod; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy