com.wso2telco.gsma.authenticators.GSMAMSISDNAuthenticator.java Source code

Java tutorial

Introduction

Here is the source code for com.wso2telco.gsma.authenticators.GSMAMSISDNAuthenticator.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.gsma.authenticators;

import com.wso2telco.core.config.service.ConfigurationService;
import com.wso2telco.core.config.service.ConfigurationServiceImpl;
import com.wso2telco.gsma.authenticators.util.AuthenticationContextHelper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.identity.application.authentication.framework.AbstractApplicationAuthenticator;
import org.wso2.carbon.identity.application.authentication.framework.AuthenticatorFlowStatus;
import org.wso2.carbon.identity.application.authentication.framework.LocalApplicationAuthenticator;
import org.wso2.carbon.identity.application.authentication.framework.config.ConfigurationFacade;
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.LogoutFailedException;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils;
import org.wso2.carbon.identity.oauth.cache.CacheKey;
import org.wso2.carbon.identity.oauth.cache.SessionDataCache;
import org.wso2.carbon.identity.oauth.cache.SessionDataCacheEntry;
import org.wso2.carbon.identity.oauth.cache.SessionDataCacheKey;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;

import javax.crypto.Cipher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.LinkedHashSet;

;

// TODO: Auto-generated Javadoc

/**
 * The Class GSMAMSISDNAuthenticator.
 */
public class GSMAMSISDNAuthenticator extends AbstractApplicationAuthenticator
        implements LocalApplicationAuthenticator {

    /**
     * The Constant serialVersionUID.
     */
    private static final long serialVersionUID = 6817280268460894001L;

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

    /**
     * The Configuration service
     */
    private static ConfigurationService configurationService = new ConfigurationServiceImpl();

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator#canHandle(javax
     * .servlet.http.HttpServletRequest)
     */
    @Override
    public boolean canHandle(HttpServletRequest request) {
        if (log.isDebugEnabled()) {
            log.debug("GSMA MSISDN Authenticator canHandle invoked");
        }

        if ((request.getParameter("msisdn") != null) || (getLoginHintValues(request) != null)) {
            return true;
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework.AbstractApplicationAuthenticator#process
     * (javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.wso2.carbon.identity
     * .application.authentication.framework.context.AuthenticationContext)
     */
    @Override
    public AuthenticatorFlowStatus process(HttpServletRequest request, HttpServletResponse response,
            AuthenticationContext context) throws AuthenticationFailedException, LogoutFailedException {

        if (context.isLogoutRequest()) {
            return AuthenticatorFlowStatus.SUCCESS_COMPLETED;
        } else {
            return super.process(request, response, context);
        }
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework
     * .AbstractApplicationAuthenticator#initiateAuthenticationRequest(javax.servlet.http.HttpServletRequest, javax
     * .servlet.http.HttpServletResponse, org.wso2.carbon.identity.application.authentication.framework.context
     * .AuthenticationContext)
     */
    @Override
    protected void initiateAuthenticationRequest(HttpServletRequest request, HttpServletResponse response,
            AuthenticationContext context) throws AuthenticationFailedException {
        log.info("Initiating authentication request");

        // Retrieve entry LOA and set to authentication context
        LinkedHashSet<?> acrs = getACRValues(request);
        String selectedLOA = (String) acrs.iterator().next();
        context.setProperty("entryLOA", selectedLOA);

        String loginPage = ConfigurationFacade.getInstance().getAuthenticationEndpointURL();

        String queryParams = FrameworkUtils.getQueryStringWithFrameworkContextId(context.getQueryParams(),
                context.getCallerSessionKey(), context.getContextIdentifier());

        if (log.isDebugEnabled()) {
            log.debug("Query parameters : " + queryParams);
        }

        try {

            String retryParam = "";

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

            response.sendRedirect(response.encodeRedirectURL(loginPage + ("?" + queryParams)) + "&authenticators="
                    + getName() + ":" + "LOCAL" + retryParam);

        } catch (IOException e) {
            throw new AuthenticationFailedException(e.getMessage(), e);
        }
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework
     * .AbstractApplicationAuthenticator#processAuthenticationResponse(javax.servlet.http.HttpServletRequest, javax
     * .servlet.http.HttpServletResponse, org.wso2.carbon.identity.application.authentication.framework.context
     * .AuthenticationContext)
     */
    @Override
    protected void processAuthenticationResponse(HttpServletRequest request, HttpServletResponse response,
            AuthenticationContext context) throws AuthenticationFailedException {
        log.info("Processing authentication response");

        String msisdn = request.getParameter("msisdn");

        if (log.isDebugEnabled()) {
            log.debug("MSISDN : " + msisdn);
        }

        boolean isAuthenticated = false;

        // Check the authentication by checking if username exists
        try {

            if (msisdn == null) {
                String loginHint = getLoginHintValues(request); // request.getParameter("login_hint");

                if (loginHint != null) {
                    // String encryptappend =
                    // DataHolder.getInstance().getMobileConnectConfig().getEncryptAppend();
                    // encryptappend not used as per latest comment hence
                    // subsstring for 11 digits
                    loginHint = loginHint.replace(" ", "+");
                    msisdn = (decryptData(loginHint)).split("\\|")[0]; // .replace(encryptappend,
                    // "");
                }
            }

            // Accept any MSISDN and consider as authenticated.
            // Intended functionality for GSMA hub
            isAuthenticated = true;
        } catch (IOException e) {
            log.error("GSMA MSISDN Authentication failed while trying to obtain login hint value", e);
        }

        if (!isAuthenticated) {
            log.info("Authentication failed. MSISDN doesn't exist.");
            throw new AuthenticationFailedException("Authentication Failed");
        }
        log.info("Authentication success");

        context.setProperty("msisdn", msisdn);
        //context.setSubject(msisdn);
        /*AuthenticatedUser user=new AuthenticatedUser();
        context.setSubject(user);*/
        AuthenticationContextHelper.setSubject(context, msisdn);
        String rememberMe = request.getParameter("chkRemember");

        if (rememberMe != null && "on".equals(rememberMe)) {
            context.setRememberMe(true);
        }
    }

    /**
     * Decrypt data.
     *
     * @param strData the str data
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private String decryptData(String strData) throws IOException {

        //byte[] data = new BASE64Decoder().decodeBuffer(strData);
        byte[] data = Base64.decodeBase64(strData.getBytes());
        byte[] descryptedData = null;

        try {
            String filename = configurationService.getDataHolder().getMobileConnectConfig().getKeyfile();
            PrivateKey privateKey = readPrivateKeyFromFile(filename);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            descryptedData = cipher.doFinal(data);
            return new String(descryptedData);
        } catch (Exception e) {
            log.error("Error" + e);
        }

        log.info("login_hint decryption completed");
        return null;

    }

    /**
     * Read private key from file.
     *
     * @param fileName the file name
     * @return the private key
     * @throws IOException              Signals that an I/O exception has occurred.
     * @throws NoSuchAlgorithmException the no such algorithm exception
     * @throws InvalidKeySpecException  the invalid key spec exception
     */
    public PrivateKey readPrivateKeyFromFile(String fileName)
            throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {

        String publicK = readStringKey(fileName);
        //byte[] keyBytes = new BASE64Decoder().decodeBuffer(publicK);
        byte[] keyBytes = Base64.decodeBase64(publicK.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory fact = KeyFactory.getInstance("RSA");
        return fact.generatePrivate(keySpec);
    }

    /**
     * Read string key.
     *
     * @param fileName the file name
     * @return the string
     */
    public static String readStringKey(String fileName) {

        BufferedReader reader = null;
        StringBuffer fileData = null;
        try {

            fileData = new StringBuffer(2048);
            reader = new BufferedReader(new FileReader(fileName));
            char[] buf = new char[1024];
            int numRead = 0;
            while ((numRead = reader.read(buf)) != -1) {
                String readData = String.valueOf(buf, 0, numRead);
                fileData.append(readData);
                buf = new char[1024];
            }

            reader.close();

        } catch (Exception e) {
            log.error("Error " + e);
        } finally {
            if (reader != null) {
                reader = null;
            }
        }
        return fileData.toString();

    }

    /**
     * Validate msisdn.
     *
     * @param msisdn the msisdn
     * @return true, if successful
     */
    protected boolean validateMsisdn(String msisdn) {
        boolean isvalid = false;
        if (msisdn != null && ((msisdn.length() == 11 && msisdn.indexOf('+') < 0)
                || (msisdn.length() == 12 && msisdn.matches("[0-9]+")))) {
            isvalid = true;
        }
        return isvalid;
    }

    /**
     * Gets the login hint values.
     *
     * @param request the request
     * @return the login hint values
     */
    private String getLoginHintValues(HttpServletRequest request) {
        String loginHintValues = null;

        try {
            String sdk = request.getParameter(OAuthConstants.SESSION_DATA_KEY);
            CacheKey ck = new SessionDataCacheKey(sdk);
            SessionDataCacheKey sessionDataCacheKey = new SessionDataCacheKey(sdk);
            SessionDataCacheEntry sdce = (SessionDataCacheEntry) SessionDataCache.getInstance()
                    .getValueFromCache(sessionDataCacheKey);
            loginHintValues = sdce.getoAuth2Parameters().getLoginHint();
        } catch (Exception e) {
            log.error("Error while getting login_hint values " + e);
        }

        return loginHintValues;
    }

    /**
     * Gets the ACR values.
     *
     * @param request the request
     * @return the ACR values
     */
    private LinkedHashSet<?> getACRValues(HttpServletRequest request) {
        String sdk = request.getParameter(OAuthConstants.SESSION_DATA_KEY);
        CacheKey ck = new SessionDataCacheKey(sdk);
        SessionDataCacheKey sessionDataCacheKey = new SessionDataCacheKey(sdk);
        SessionDataCacheEntry sdce = (SessionDataCacheEntry) SessionDataCache.getInstance()
                .getValueFromCache(sessionDataCacheKey);
        LinkedHashSet<?> acrValues = sdce.getoAuth2Parameters().getACRValues();
        return acrValues;
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework
     * .AbstractApplicationAuthenticator#retryAuthenticationEnabled()
     */
    @Override
    protected boolean retryAuthenticationEnabled() {
        // Setting retry to true as we need the correct MSISDN to continue
        return true;
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework
     * .ApplicationAuthenticator#getContextIdentifier(javax.servlet.http.HttpServletRequest)
     */
    @Override
    public String getContextIdentifier(HttpServletRequest request) {
        return request.getParameter("sessionDataKey");
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator#getFriendlyName()
     */
    @Override
    public String getFriendlyName() {
        return Constants.GSMA_MSISDN_AUTHENTICATOR_FRIENDLY_NAME;
    }

    /**
     * Gets the private key file.
     *
     * @return the private key file
     */
    private String getPrivateKeyFile() {
        return Constants.PRIVATE_KEYFILE;
    }

    /* (non-Javadoc)
     * @see org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator#getName()
     */
    @Override
    public String getName() {
        return Constants.GSMA_MSISDN_AUTHENTICATOR_NAME;
    }
}