com.wso2telco.authenticationstephandler.MIFEAuthenticationStepHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.wso2telco.authenticationstephandler.MIFEAuthenticationStepHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2015-2016, WSO2.Telco Inc. (http://www.wso2telco.com) 
 * 
 * All Rights Reserved. WSO2.Telco Inc. licences this file to you 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 com.wso2telco.authenticationstephandler;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator;
import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus;
import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade;
import org.wso2.carbon.identity.application.authentication.framework.config.model.AuthenticatorConfig;
import org.wso2.carbon.identity.application.authentication.framework.config.model.SequenceConfig;
import org.wso2.carbon.identity.application.authentication.framework.config.model.StepConfig;
import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext;
import org.wso2.carbon.identity.application.authentication.framework.exception.AuthenticationFailedException;
import org.wso2.carbon.identity.application.authentication.framework.exception.FrameworkException;
import org.wso2.carbon.identity.application.authentication.framework.exception.InvalidCredentialsException;
import org.wso2.carbon.identity.application.authentication.framework.exception.LogoutFailedException;
import org.wso2.carbon.identity.application.authentication.framework.handler.step.impl.DefaultStepHandler;
import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedIdPData;
import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils;
import org.wso2.carbon.identity.application.common.model.ClaimMapping;
import org.wso2.carbon.idp.mgt.IdentityProviderManagementException;

import com.wso2telco.gsma.authenticators.LOACompositeAuthenticator;
import com.wso2telco.util.AuthenticationHealper;

// TODO: Auto-generated Javadoc
/**
 * The Class MIFEAuthenticationStepHandler.
 */
public class MIFEAuthenticationStepHandler extends DefaultStepHandler {

    /** The log. */
    private static Log log = LogFactory.getLog(MIFEAuthenticationStepHandler.class);

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework.handler.step.impl.DefaultStepHandler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext)
     */
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
            throws FrameworkException {

        StepConfig stepConfig = context.getSequenceConfig().getStepMap().get(context.getCurrentStep());
        List<AuthenticatorConfig> authConfigList = stepConfig.getAuthenticatorList();
        String authenticatorNames = FrameworkUtils.getAuthenticatorIdPMappingString(authConfigList);
        String redirectURL = ConfigurationFacade.getInstance().getAuthenticationEndpointURL();
        String fidp = request.getParameter(FrameworkConstants.RequestParams.FEDERATED_IDP);

        Map<String, AuthenticatedIdPData> authenticatedIdPs = context.getPreviousAuthenticatedIdPs();
        Map<String, AuthenticatorConfig> authenticatedStepIdps = FrameworkUtils.getAuthenticatedStepIdPs(stepConfig,
                authenticatedIdPs);

        // check passive authentication
        if (context.isPassiveAuthenticate()) {

            if (authenticatedStepIdps.isEmpty()) {
                context.setRequestAuthenticated(false);
            } else {
                String authenticatedIdP = authenticatedStepIdps.entrySet().iterator().next().getKey();
                AuthenticatedIdPData authenticatedIdPData = authenticatedIdPs.get(authenticatedIdP);
                populateStepConfigWithAuthenticationDetails(stepConfig, authenticatedIdPData);
            }

            stepConfig.setCompleted(true);
            return;
        }

        // if Request has fidp param and if this is the first step
        if (fidp != null && !fidp.isEmpty() && stepConfig.getOrder() == 1) {
            handleHomeRealmDiscovery(request, response, context);
            return;
        } else if (context.isReturning()) {
            // if this is a request from the multi-option page
            if (request.getParameter(FrameworkConstants.RequestParams.AUTHENTICATOR) != null
                    && !request.getParameter(FrameworkConstants.RequestParams.AUTHENTICATOR).isEmpty()) {
                handleRequestFromLoginPage(request, response, context);
                return;
            } else {
                // if this is a response from external parties (e.g. federated
                // IdPs)
                handleResponse(request, response, context);
                return;
            }
        }
        // if dumbMode
        else if (ConfigurationFacade.getInstance().isDumbMode()) {

            if (log.isDebugEnabled()) {
                log.debug("Executing in Dumb mode");
            }

            try {
                response.sendRedirect(redirectURL + ("?" + context.getContextIdIncludedQueryParams())
                        + "&authenticators=" + authenticatorNames + "&hrd=true");
            } catch (IOException e) {
                throw new FrameworkException(e.getMessage(), e);
            }
        } else {

            if (!context.isForceAuthenticate() && !authenticatedStepIdps.isEmpty()) {

                Map.Entry<String, AuthenticatorConfig> entry = authenticatedStepIdps.entrySet().iterator().next();
                String idp = entry.getKey();
                AuthenticatorConfig authenticatorConfig = entry.getValue();

                if (context.isReAuthenticate()) {

                    if (log.isDebugEnabled()) {
                        log.debug("Re-authenticating with " + idp + " IdP");
                    }

                    try {
                        context.setExternalIdP(ConfigurationFacade.getInstance().getIdPConfigByName(idp,
                                context.getTenantDomain()));
                    } catch (IdentityProviderManagementException e) {
                        log.error(e);
                        throw new FrameworkException(e.toString());
                    }
                    doAuthentication(request, response, context, authenticatorConfig);
                    return;
                } else {

                    if (log.isDebugEnabled()) {
                        log.debug("Already authenticated. Skipping the step");
                    }

                    // skip the step if this is a normal request
                    AuthenticatedIdPData authenticatedIdPData = authenticatedIdPs.get(idp);
                    populateStepConfigWithAuthenticationDetails(stepConfig, authenticatedIdPData);
                    stepConfig.setCompleted(true);
                    return;
                }
            } else {
                // Find if step contains only a single authenticator with a
                // single
                // IdP. If yes, don't send to the multi-option page. Call
                // directly.
                boolean sendToPage = false;
                AuthenticatorConfig authenticatorConfig = null;

                // Are there multiple authenticators?
                if (authConfigList.size() > 1) {
                    sendToPage = true;
                } else {
                    // Are there multiple IdPs in the single authenticator?
                    authenticatorConfig = authConfigList.get(0);
                    if (authenticatorConfig.getIdpNames().size() > 1) {
                        sendToPage = true;
                    }
                }

                if (!sendToPage) {
                    // call directly
                    if (authenticatorConfig.getIdpNames().size() > 0) {

                        if (log.isDebugEnabled()) {
                            log.debug("Step contains only a single IdP. Going to call it directly");
                        }

                        // set the IdP to be called in the context
                        try {
                            context.setExternalIdP(ConfigurationFacade.getInstance().getIdPConfigByName(
                                    authenticatorConfig.getIdpNames().get(0), context.getTenantDomain()));
                        } catch (IdentityProviderManagementException e) {
                            log.error(e);
                            throw new FrameworkException(e.toString());
                        }
                    }

                    doAuthentication(request, response, context, authenticatorConfig);
                    return;
                } else {
                    // else send to the multi option page.
                    if (log.isDebugEnabled()) {
                        log.debug("Sending to the Multi Option page");
                    }

                    String retryParam = "";

                    if (stepConfig.isRetrying()) {
                        context.setCurrentAuthenticator(null);
                        retryParam = "&authFailure=true&authFailureMsg=login.fail.message";
                    }

                    try {
                        response.sendRedirect(redirectURL + ("?" + context.getContextIdIncludedQueryParams())
                                + "&authenticators=" + authenticatorNames + retryParam);
                    } catch (IOException e) {
                        throw new FrameworkException(e.getMessage(), e);
                    }

                    return;
                }
            }
        }
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework.handler.step.impl.DefaultStepHandler#doAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext, org.wso2.carbon.identity.application.authentication.framework.config.model.AuthenticatorConfig)
     */
    @SuppressWarnings("unchecked")
    @Override
    protected void doAuthentication(HttpServletRequest request, HttpServletResponse response,
            AuthenticationContext context, AuthenticatorConfig authenticatorConfig) throws FrameworkException {

        SequenceConfig sequenceConfig = context.getSequenceConfig();
        int currentStep = context.getCurrentStep();
        StepConfig stepConfig = sequenceConfig.getStepMap().get(currentStep);

        // Set false for all steps

        ApplicationAuthenticator authenticator = authenticatorConfig.getApplicationAuthenticator();

        try {
            context.setAuthenticatorProperties(FrameworkUtils
                    .getAuthenticatorPropertyMapFromIdP(context.getExternalIdP(), authenticator.getName()));
            AuthenticatorFlowStatus status = authenticator.process(request, response, context);
            request.setAttribute(FrameworkConstants.RequestParams.FLOW_STATUS, status);

            if (log.isDebugEnabled()) {
                log.debug(authenticator.getName() + " returned: " + status.toString());
            }

            if (status == AuthenticatorFlowStatus.INCOMPLETE) {
                if (log.isDebugEnabled()) {
                    log.debug(authenticator.getName() + " is redirecting");
                }
                return;
            }

            // This is only a routing authenticator
            if (authenticator instanceof LOACompositeAuthenticator) {
                removeFailedStep(context, currentStep);
            } else {
                try {
                    if (Boolean.parseBoolean(authenticatorConfig.getParameterMap().get("isLastAuthenticator"))) {
                        removeAllFollowingSteps(context, currentStep);
                    }

                    // set authenticator name in the context
                    // This gets used in ID token later
                    Object amrValue = context.getProperty("amr");
                    List<String> amr;
                    if (null != amrValue && amrValue instanceof ArrayList<?>) {
                        amr = (ArrayList<String>) amrValue;
                        amr.add(authenticator.getName());
                        context.setProperty("amr", amr);
                    } else {
                        amr = new ArrayList<String>();
                        amr.add(authenticator.getName());
                        context.setProperty("amr", amr);
                    }
                } catch (NullPointerException e) {
                    // Possible exception during dashboard login
                    // Should continue even if NPE is thrown
                }

                setAuthenticationAttributes(context, stepConfig, authenticatorConfig);
            }

        } catch (AuthenticationFailedException e) {

            if (e instanceof InvalidCredentialsException) {
                log.warn("A login attempt was failed due to invalid credentials");
            } else {
                log.error(e.getMessage(), e);
            }

            // add failed authenticators
            Object amrValue = context.getProperty("failedamr");
            List<String> amr;
            if (null != amrValue && amrValue instanceof ArrayList<?>) {
                amr = (ArrayList<String>) amrValue;
                amr.add(authenticator.getName());
                context.setProperty("failedamr", amr);
            } else {
                amr = new ArrayList<String>();
                amr.add(authenticator.getName());
                context.setProperty("failedamr", amr);
            }

            // Remove failed step from step map
            removeFailedStep(context, currentStep);
            try {
                String onFailProperty = authenticatorConfig.getParameterMap().get("onFail");

                if (!"".equals(onFailProperty) && !onFailProperty.equals("continue")) {
                    // Should fail the whole LOA and continue to next if defined
                    String fallBacklevel = authenticatorConfig.getParameterMap().get("fallBack");
                    if (onFailProperty.equals("fallback") && StringUtils.isNotBlank(fallBacklevel)) {
                        removeFollowingStepsOfCurrentLOA(context,
                                authenticatorConfig.getParameterMap().get("currentLOA"), currentStep);
                    } else {
                        context.setRequestAuthenticated(false);
                        context.getSequenceConfig().setCompleted(true);
                    }
                }
            } catch (NullPointerException e1) {
                // Possible exception during dashboard login
                removeAllFollowingSteps(context, currentStep);
                context.setRequestAuthenticated(false);
                context.getSequenceConfig().setCompleted(true);
            }
        } catch (LogoutFailedException e) {
            throw new FrameworkException(e.getMessage(), e);
        }

        stepConfig.setCompleted(true);
    }

    /**
     * Sets the authentication attributes.
     *
     * @param context the context
     * @param stepConfig the step config
     * @param authenticatorConfig the authenticator config
     */
    private void setAuthenticationAttributes(AuthenticationContext context, StepConfig stepConfig,
            AuthenticatorConfig authenticatorConfig) {
        AuthenticatedIdPData authenticatedIdPData = AuthenticationHealper.createAuthenticatedIdPData(context);

        authenticatorConfig.setAuthenticatorStateInfo(context.getStateInfo());
        stepConfig.setAuthenticatedAutenticator(authenticatorConfig);

        String idpName = FrameworkConstants.LOCAL_IDP_NAME;

        if (context.getExternalIdP() != null) {
            idpName = context.getExternalIdP().getIdPName();
        }

        // store authenticated idp
        stepConfig.setAuthenticatedIdP(idpName);
        authenticatedIdPData.setIdpName(idpName);
        authenticatedIdPData.setAuthenticator(authenticatorConfig);
        // add authenticated idp data to the session wise map
        context.getCurrentAuthenticatedIdPs().put(idpName, authenticatedIdPData);

        // Set sequence config
        if (stepConfig.isSubjectAttributeStep()) {
            SequenceConfig sequenceConfig = context.getSequenceConfig();
            sequenceConfig.setAuthenticatedUser(context.getSubject());
            context.setSequenceConfig(sequenceConfig);
        }
        log.info(
                "===============================================================================setting authenticated user=============");
        // Set the authenticated user as an object. 5.1.0 onwards
        stepConfig.setAuthenticatedUser(context.getSubject());
    }

    /**
     * Removes the failed step.
     *
     * @param context the context
     * @param currentStep the current step
     */
    private void removeFailedStep(AuthenticationContext context, int currentStep) {
        context.getSequenceConfig().getStepMap().remove(currentStep);
    }

    /**
     * Removes the following steps of current loa.
     *
     * @param context the context
     * @param currentLOA the current loa
     * @param currentStep the current step
     */
    private void removeFollowingStepsOfCurrentLOA(AuthenticationContext context, String currentLOA,
            int currentStep) {
        Map<Integer, StepConfig> stepMap = new HashMap<Integer, StepConfig>(
                context.getSequenceConfig().getStepMap());

        Iterator<Integer> it = stepMap.keySet().iterator();
        while (it.hasNext()) {
            Integer key = it.next();
            StepConfig config = stepMap.get(key);

            try {
                if (currentLOA.equals(config.getAuthenticatorList().get(0).getParameterMap().get("currentLOA"))) {
                    context.getSequenceConfig().getStepMap().remove(key);
                }
            } catch (NullPointerException e) {
                continue;
            }
        }

        // Increment the current step
        for (int i = currentStep; i < 30; i++) {
            if (context.getSequenceConfig().getStepMap().keySet().contains(i)) {
                context.setCurrentStep(i);
                break;
            }
        }
    }

    /**
     * Removes the all following steps.
     *
     * @param context the context
     * @param currentStep the current step
     */
    private void removeAllFollowingSteps(AuthenticationContext context, int currentStep) {
        Map<Integer, StepConfig> stepMap = new HashMap<Integer, StepConfig>(
                context.getSequenceConfig().getStepMap());

        Iterator<Integer> it = stepMap.keySet().iterator();
        while (it.hasNext()) {
            Integer key = it.next();

            try {
                if (key > currentStep) {
                    context.getSequenceConfig().getStepMap().remove(key);
                }
            } catch (NullPointerException e) {
                continue;
            }
        }
    }
}