package net.unicon.idp.externalauth;

import net.shibboleth.idp.authn.ExternalAuthentication;
import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.saml2.core.AuthnContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;

/**
 * This is {@link CasDuoSecurityRefedsAuthnMethodTranslator}.
 *
 * @author Misagh Moayyed
 * @since 5.3.0
 */
public class CasDuoSecurityRefedsAuthnMethodTranslator implements CasToShibTranslator, EnvironmentAware {
    private final Logger logger = LoggerFactory.getLogger(CasDuoSecurityRefedsAuthnMethodTranslator.class);

    private static final String REFEDS = "https://refeds.org/profile/mfa";

    private Environment environment;

    @Override
    public void setEnvironment(final Environment environment) {
        this.environment = environment;
    }

    @Override
    public void doTranslation(final HttpServletRequest request, final HttpServletResponse response, final Assertion assertion, final String authenticationKey) throws Exception {
        final Object attribute = request.getAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM);
        if (attribute == null) {
            logger.debug("No authentication method parameter is found in the request attributes");
            return;
        }
        final String authnMethod = attribute.toString();
        logger.debug("Requested authn method provided by IdP is {}", authnMethod);
        if (!assertion.getPrincipal().getAttributes().containsKey("authnContextClass")) {
            logger.debug("No authentication context class is provided by CAS; Overriding context class to {}", AuthnContext.PPT_AUTHN_CTX);
            request.setAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM, AuthnContext.PPT_AUTHN_CTX);
            overrideAuthnContextClass(request, authenticationKey);
            return;
        }

        final Object clazz = assertion.getPrincipal().getAttributes().get("authnContextClass");
        logger.debug("Located asserted authentication context class [{}]", clazz);

        if (clazz.equals("mfa-duo")) {
            request.setAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM, REFEDS);
            overrideAuthnContextClass(request, authenticationKey);
            logger.info("Validation payload successfully asserts the authentication context class for mfa-duo; Context class is set to {}", REFEDS);
            return;
        }
        logger.debug("Authentication context class [{}] provided by CAS is not one by Duo Security. "
            + "The requested authentication method to be used shall be {}", clazz, authnMethod);
    }

    private void overrideAuthnContextClass(final HttpServletRequest request, final String authenticationKey) throws Exception {
        final ProfileRequestContext prc = ExternalAuthentication.getProfileRequestContext(authenticationKey, request);
        final AuthenticationContext authnContext = prc.getSubcontext(AuthenticationContext.class, true);
        final RequestedPrincipalContext principalCtx = authnContext.getSubcontext(RequestedPrincipalContext.class, true);

        if (principalCtx != null) {
            final List<Principal> principals = new ArrayList<>();
            final String clazz = request.getAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM).toString();
            final Principal principal = new AuthnContextClassRefPrincipal(clazz);
            principals.add(principal);
            principalCtx.setRequestedPrincipals(principals);
        }

    }
}

@@ -1544,32 +1544,33 @@
 ows Exception %7B%0A
+%0A
         final Ob
@@ -1571,89 +1571,913 @@
 nal 
-Object attribute = request.getAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM
+ProfileRequestContext prc = ExternalAuthentication.getProfileRequestContext(authenticationKey, request);%0A        final AuthenticationContext authnContext = prc.getSubcontext(AuthenticationContext.class, true);%0A        if (authnContext == null) %7B%0A            logger.debug(%22No authentication context is available%22);%0A            return;%0A        %7D%0A        final RequestedPrincipalContext principalCtx = authnContext.getSubcontext(RequestedPrincipalContext.class, true);%0A        if (principalCtx == null %7C%7C principalCtx.getRequestedPrincipals().isEmpty()) %7B%0A            logger.debug(%22No requested principal context is available in the authentication context%22);%0A            return;%0A        %7D%0A%0A        final Principal principal = new AuthnContextClassRefPrincipal(REFEDS);%0A        final Principal attribute = principalCtx.getRequestedPrincipals().stream().filter(p -%3E p.equals(principal)).findFirst().orElse(null
 );%0A 
@@ -2682,24 +2682,23 @@
 tribute.
-toString
+getName
 ();%0A    
@@ -3022,139 +3022,62 @@
     
-request.setAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM, AuthnContext.PPT_AUTHN_CTX);%0A            overrideAuthnContextClass(
+overrideAuthnContextClass(AuthnContext.PPT_AUTHN_CTX, 
 requ
@@ -3355,93 +3355,8 @@
 ) %7B%0A
-            request.setAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM, REFEDS);%0A
     
@@ -3389,16 +3389,24 @@
 xtClass(
+REFEDS, 
 request,
@@ -3780,16 +3780,39 @@
 ll be %7B%7D
+ and is left unmodified
 %22, clazz
@@ -3879,24 +3879,44 @@
 Class(final 
+String clazz, final 
 HttpServletR
@@ -4198,32 +4198,199 @@
 t.class, true);%0A
+        if (authnContext == null) %7B%0A            throw new IllegalArgumentException(%22No authentication method parameter is found in the request attributes%22);%0A        %7D%0A
         final Re
@@ -4602,117 +4602,8 @@
 ();%0A
-            final String clazz = request.getAttribute(ExternalAuthentication.AUTHN_METHOD_PARAM).toString();%0A
     
@@ -4715,24 +4715,120 @@
 principal);%0A
+            logger.debug(%22Overriding the principal authn context class ref to %7B%7D%22, principals);%0A
             

refactor extraction of authn context class