/*
   * Find the Subject identifier among federated claims
   */
  public static String getFederatedSubjectFromClaims(
      AuthenticationContext context, String otherDialect) throws FrameworkException {
    String value;
    boolean useLocalClaimDialect = context.getExternalIdP().useDefaultLocalIdpDialect();
    String userIdClaimURI = context.getExternalIdP().getUserIdClaimUri();
    Map<ClaimMapping, String> claimMappings = context.getSubject().getUserAttributes();

    if (useLocalClaimDialect) {
      Map<String, String> extAttributesValueMap =
          FrameworkUtils.getClaimMappings(claimMappings, false);
      Map<String, String> mappedAttrs = null;
      try {
        mappedAttrs =
            ClaimMetadataHandler.getInstance()
                .getMappingsMapFromOtherDialectToCarbon(
                    otherDialect, extAttributesValueMap.keySet(), context.getTenantDomain(), true);
      } catch (ClaimMetadataException e) {
        throw new FrameworkException("Error while loading claim mappings.", e);
      }

      String spUserIdClaimURI = mappedAttrs.get(userIdClaimURI);
      value = extAttributesValueMap.get(spUserIdClaimURI);
    } else {
      ClaimMapping claimMapping = new ClaimMapping();
      Claim claim = new Claim();
      claim.setClaimUri(userIdClaimURI);
      claimMapping.setRemoteClaim(claim);
      value = claimMappings.get(claimMapping);
    }
    return value;
  }
  /* (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 httpServletRequest,
      HttpServletResponse httpServletResponse,
      AuthenticationContext context)
      throws AuthenticationFailedException {

    // String msisdn = httpServletRequest.getParameter("msisdn");
    log.info("MSS PIN Authenticator authentication Start ");
    String sessionDataKey = httpServletRequest.getParameter("sessionDataKey");
    String msisdn = (String) context.getProperty("msisdn");
    boolean isAuthenticated = false;

    try {
      String responseStatus = DBUtils.getUserResponse(sessionDataKey);

      if (responseStatus.equalsIgnoreCase(UserResponse.APPROVED.toString())) {
        isAuthenticated = true;
      }

    } catch (AuthenticatorException e) {
      log.error("SMS Authentication failed while trying to authenticate", e);
      throw new AuthenticationFailedException(e.getMessage(), e);
    }

    if (!isAuthenticated) {
      log.info("MSS PIN Authenticator authentication failed ");
      context.setProperty("faileduser", msisdn);
      if (log.isDebugEnabled()) {
        log.debug("User authentication failed due to not existing user MSISDN.");
      }

      throw new AuthenticationFailedException("Authentication Failed");
    }
    log.info("MSS PIN Authenticator authentication success for MSISDN - " + msisdn);

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

    if (rememberMe != null && "on".equals(rememberMe)) {
      context.setRememberMe(true);
    }
  }
  /* (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);
    }
  }
  private boolean isForceAuthenticate(AuthenticationContext context) {

    boolean forceAuthenticate = false;
    String forceAuthenticateProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.FORCE_AUTHENTICATION);
    if ("yes".equalsIgnoreCase(forceAuthenticateProp)) {
      forceAuthenticate = true;
    } else if ("as_request".equalsIgnoreCase(forceAuthenticateProp)) {
      forceAuthenticate = context.isForceAuthenticate();
    }
    return forceAuthenticate;
  }
 /** initiate the authentication request */
 @Override
 protected void initiateAuthenticationRequest(
     HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
     throws AuthenticationFailedException {
   String loginPage = ConfigurationFacade.getInstance().getAuthenticationEndpointURL();
   loginPage = loginPage.replace(InweboConstants.INWEBO_LOGINPAGE, InweboConstants.INWEBO_PAGE);
   try {
     String retryParam = "";
     if (context.isRetrying()) {
       retryParam = InweboConstants.RETRY_PARAM;
     }
     response.sendRedirect(
         response.encodeRedirectURL(
             loginPage
                 + "?"
                 + FrameworkConstants.SESSION_DATA_KEY
                 + "="
                 + context.getContextIdentifier()
                 + retryParam));
   } catch (IOException e) {
     throw new AuthenticationFailedException("Error while redirecting", e);
   }
 }
  /* (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 {

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

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

    try {

      String retryParam = "";

      if (context.isRetrying()) {
        retryParam = "&authFailure=true&authFailureMsg=login.fail.message";
      } else {
        // Insert entry to DB only if this is not a retry
        DBUtils.insertUserResponse(
            context.getContextIdentifier(), String.valueOf(MSSAuthenticator.UserResponse.PENDING));
      }

      // MSISDN will be saved in the context in the MSISDNAuthenticator
      String msisdn = (String) context.getProperty("msisdn");
      MSSRequest mssRequest = new MSSRequest();
      mssRequest.setMsisdnNo("+" + msisdn);
      mssRequest.setSendString(
          DataHolder.getInstance().getMobileConnectConfig().getMSS().getMssText());

      String contextIdentifier = context.getContextIdentifier();
      MSSRestClient mssRestClient = new MSSRestClient(contextIdentifier, mssRequest);
      mssRestClient.start();

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

    } catch (IOException e) {
      throw new AuthenticationFailedException(e.getMessage(), e);
    } catch (AuthenticatorException e) {
      throw new AuthenticationFailedException(e.getMessage(), e);
    }
  }
  protected AuthnRequest getAuthnRequest(AuthenticationContext context) throws SAMLSSOException {

    AuthnRequest authnRequest = null;
    AuthenticationRequest authenticationRequest = context.getAuthenticationRequest();
    String[] samlRequestParams =
        authenticationRequest.getRequestQueryParam(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ);
    String samlRequest = null;
    if (samlRequestParams != null && samlRequestParams.length > 0) {
      samlRequest = samlRequestParams[0];
      XMLObject xmlObject;
      if (authenticationRequest.isPost()) {
        xmlObject = unmarshall(SSOUtils.decodeForPost(samlRequest));
      } else {
        xmlObject = unmarshall(SSOUtils.decode(samlRequest));
      }
      if (xmlObject instanceof AuthnRequest) {
        authnRequest = (AuthnRequest) xmlObject;
      }
    }
    return authnRequest;
  }
  /**
   * @param request
   * @param isLogout
   * @param isPassive
   * @param loginPage
   * @return return encoded SAML Auth request
   * @throws SAMLSSOException
   */
  public String buildPostRequest(
      HttpServletRequest request,
      boolean isLogout,
      boolean isPassive,
      String loginPage,
      AuthenticationContext context)
      throws SAMLSSOException {

    doBootstrap();
    RequestAbstractType requestMessage;
    String signatureAlgoProp = null;
    String digestAlgoProp = null;
    String includeCertProp = null;
    String signatureAlgo = null;
    String digestAlgo = null;
    boolean includeCert = false;

    // get Signature Algorithm
    signatureAlgoProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SIGNATURE_ALGORITHM);
    if (StringUtils.isEmpty(signatureAlgoProp)) {
      signatureAlgoProp = IdentityApplicationConstants.XML.SignatureAlgorithm.RSA_SHA1;
    }
    signatureAlgo =
        IdentityApplicationManagementUtil.getXMLSignatureAlgorithms().get(signatureAlgoProp);

    // get Digest Algorithm
    digestAlgoProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.DIGEST_ALGORITHM);
    if (StringUtils.isEmpty(digestAlgoProp)) {
      digestAlgoProp = IdentityApplicationConstants.XML.DigestAlgorithm.SHA1;
    }
    digestAlgo = IdentityApplicationManagementUtil.getXMLDigestAlgorithms().get(digestAlgoProp);

    includeCertProp =
        properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.INCLUDE_CERT);
    if (StringUtils.isEmpty(includeCertProp) || Boolean.parseBoolean(includeCertProp)) {
      includeCert = true;
    }

    if (!isLogout) {
      requestMessage = buildAuthnRequest(request, isPassive, loginPage, context);
      if (SSOUtils.isAuthnRequestSigned(properties)) {
        SSOUtils.setSignature(
            requestMessage,
            signatureAlgo,
            digestAlgo,
            includeCert,
            new X509CredentialImpl(context.getTenantDomain(), null));
      }
    } else {
      String username = (String) request.getSession().getAttribute(SSOConstants.LOGOUT_USERNAME);
      String sessionIndex =
          (String) request.getSession().getAttribute(SSOConstants.LOGOUT_SESSION_INDEX);
      String nameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.NAME_QUALIFIER);
      String spNameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.SP_NAME_QUALIFIER);

      requestMessage =
          buildLogoutRequest(username, sessionIndex, loginPage, nameQualifier, spNameQualifier);
      if (SSOUtils.isLogoutRequestSigned(properties)) {
        SSOUtils.setSignature(
            requestMessage,
            signatureAlgo,
            digestAlgo,
            includeCert,
            new X509CredentialImpl(context.getTenantDomain(), null));
      }
    }

    return SSOUtils.encode(SSOUtils.marshall(requestMessage));
  }
  /**
   * Returns the redirection URL with the appended SAML2 Request message
   *
   * @param request SAML 2 request
   * @return redirectionUrl
   */
  @Override
  public String buildRequest(
      HttpServletRequest request,
      boolean isLogout,
      boolean isPassive,
      String loginPage,
      AuthenticationContext context)
      throws SAMLSSOException {

    doBootstrap();
    String contextIdentifier = context.getContextIdentifier();
    RequestAbstractType requestMessage;

    if (request.getParameter(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ) == null) {
      String queryParam = context.getQueryParams();
      if (queryParam != null) {
        String[] params = queryParam.split("&");
        for (String param : params) {
          String[] values = param.split("=");
          if (values.length == 2 && SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ.equals(values[0])) {
            request.setAttribute(SSOConstants.HTTP_POST_PARAM_SAML2_AUTH_REQ, values[1]);
            break;
          }
        }
      }
    }

    if (!isLogout) {
      requestMessage = buildAuthnRequest(request, isPassive, loginPage, context);
    } else {
      String username = (String) request.getSession().getAttribute(SSOConstants.LOGOUT_USERNAME);
      String sessionIndex =
          (String) request.getSession().getAttribute(SSOConstants.LOGOUT_SESSION_INDEX);
      String nameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.NAME_QUALIFIER);
      String spNameQualifier =
          (String) request.getSession().getAttribute(SSOConstants.SP_NAME_QUALIFIER);

      requestMessage =
          buildLogoutRequest(username, sessionIndex, loginPage, nameQualifier, spNameQualifier);
    }
    String idpUrl = null;
    boolean isSignAuth2SAMLUsingSuperTenant = false;

    String encodedRequestMessage = encodeRequestMessage(requestMessage);
    StringBuilder httpQueryString = new StringBuilder("SAMLRequest=" + encodedRequestMessage);

    try {
      httpQueryString.append("&RelayState=" + URLEncoder.encode(contextIdentifier, "UTF-8").trim());
    } catch (UnsupportedEncodingException e) {
      throw new SAMLSSOException("Error occurred while url encoding RelayState", e);
    }

    if (SSOUtils.isAuthnRequestSigned(properties)) {
      String signatureAlgoProp =
          properties.get(IdentityApplicationConstants.Authenticator.SAML2SSO.SIGNATURE_ALGORITHM);
      if (StringUtils.isEmpty(signatureAlgoProp)) {
        signatureAlgoProp = IdentityApplicationConstants.XML.SignatureAlgorithm.RSA_SHA1;
      }
      String signatureAlgo =
          IdentityApplicationManagementUtil.getXMLSignatureAlgorithms().get(signatureAlgoProp);

      Map<String, String> parameterMap =
          FileBasedConfigurationBuilder.getInstance()
              .getAuthenticatorBean(SSOConstants.AUTHENTICATOR_NAME)
              .getParameterMap();
      if (parameterMap.size() > 0) {
        isSignAuth2SAMLUsingSuperTenant =
            Boolean.parseBoolean(parameterMap.get(SIGN_AUTH2_SAML_USING_SUPER_TENANT));
      }
      if (isSignAuth2SAMLUsingSuperTenant) {
        SSOUtils.addSignatureToHTTPQueryString(
            httpQueryString,
            signatureAlgo,
            new X509CredentialImpl(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, null));
      } else {
        SSOUtils.addSignatureToHTTPQueryString(
            httpQueryString,
            signatureAlgo,
            new X509CredentialImpl(context.getTenantDomain(), null));
      }
    }
    if (loginPage.indexOf("?") > -1) {
      idpUrl = loginPage.concat("&").concat(httpQueryString.toString());
    } else {
      idpUrl = loginPage.concat("?").concat(httpQueryString.toString());
    }
    return idpUrl;
  }
  /**
   * This is override because of query string values hard coded and input values validations are not
   * required.
   *
   * @param request
   * @param response
   * @param context
   * @throws AuthenticationFailedException
   */
  @Override
  protected void initiateAuthenticationRequest(
      HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
      throws AuthenticationFailedException {

    try {
      Map<String, String> authenticatorProperties = context.getAuthenticatorProperties();
      if (authenticatorProperties != null) {
        String clientId = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_ID);
        String authorizationEP;
        if (getAuthorizationServerEndpoint(authenticatorProperties) != null) {
          authorizationEP = getAuthorizationServerEndpoint(authenticatorProperties);
        } else {
          authorizationEP =
              authenticatorProperties.get(OIDCAuthenticatorConstants.OAUTH2_AUTHZ_URL);
        }

        String callBackUrl =
            authenticatorProperties.get(GoogleOAuth2AuthenticationConstant.CALLBACK_URL);

        if (log.isDebugEnabled()) {
          log.debug("Google-callback-url : " + callBackUrl);
        }

        if (callBackUrl == null) {
          callBackUrl = CarbonUIUtil.getAdminConsoleURL(request);
          callBackUrl = callBackUrl.replace("commonauth/carbon/", "commonauth");
        }

        String state = context.getContextIdentifier() + "," + OIDCAuthenticatorConstants.LOGIN_TYPE;

        state = getState(state, authenticatorProperties);

        OAuthClientRequest authzRequest;

        // This is the query string need to send in order to get email and
        // profile
        String queryString = GoogleOAuth2AuthenticationConstant.QUERY_STRING;

        authzRequest =
            OAuthClientRequest.authorizationLocation(authorizationEP)
                .setClientId(clientId)
                .setRedirectURI(callBackUrl)
                .setResponseType(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE)
                .setState(state)
                .buildQueryMessage();

        String loginPage = authzRequest.getLocationUri();
        String domain = request.getParameter("domain");

        if (domain != null) {
          loginPage = loginPage + "&fidp=" + domain;
        }

        if (queryString != null) {
          if (!queryString.startsWith("&")) {
            loginPage = loginPage + "&" + queryString;
          } else {
            loginPage = loginPage + queryString;
          }
        }
        response.sendRedirect(loginPage);

      } else {
        if (log.isDebugEnabled()) {
          log.debug("Error while retrieving properties. Authenticator Properties cannot be null");
        }
        throw new AuthenticationFailedException(
            "Error while retrieving properties. Authenticator Properties cannot be null");
      }
    } catch (IOException e) {
      throw new AuthenticationFailedException("Exception while sending to the login page", e);
    } catch (OAuthSystemException e) {
      throw new AuthenticationFailedException(
          "Exception while building authorization code request", e);
    }
  }
  /**
   * this method are overridden for extra claim request to google end-point
   *
   * @param request
   * @param response
   * @param context
   * @throws AuthenticationFailedException
   */
  @Override
  protected void processAuthenticationResponse(
      HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
      throws AuthenticationFailedException {

    try {

      Map<String, String> authenticatorProperties = context.getAuthenticatorProperties();
      String clientId = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_ID);
      String clientSecret = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_SECRET);
      String tokenEndPoint;
      if (getTokenEndpoint(authenticatorProperties) != null) {
        tokenEndPoint = getTokenEndpoint(authenticatorProperties);
      } else {
        tokenEndPoint = authenticatorProperties.get(OIDCAuthenticatorConstants.OAUTH2_TOKEN_URL);
      }

      String callBackUrl =
          authenticatorProperties.get(GoogleOAuth2AuthenticationConstant.CALLBACK_URL);

      log.debug("callBackUrl : " + callBackUrl);

      if (callBackUrl == null) {
        callBackUrl = CarbonUIUtil.getAdminConsoleURL(request);
        callBackUrl = callBackUrl.replace("commonauth/carbon/", "commonauth");
      }

      @SuppressWarnings({"unchecked"})
      Map<String, String> paramValueMap =
          (Map<String, String>) context.getProperty("oidc:param.map");

      if (paramValueMap != null && paramValueMap.containsKey("redirect_uri")) {
        callBackUrl = paramValueMap.get("redirect_uri");
      }

      OAuthAuthzResponse authzResponse = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
      String code = authzResponse.getCode();

      OAuthClientRequest accessRequest = null;
      accessRequest = getAccessRequest(tokenEndPoint, clientId, clientSecret, callBackUrl, code);

      // create OAuth client that uses custom http client under the hood
      OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
      OAuthClientResponse oAuthResponse = null;
      oAuthResponse = getOAuthResponse(accessRequest, oAuthClient, oAuthResponse);
      // TODO : return access token and id token to framework
      String accessToken = "";
      String idToken = "";
      if (oAuthResponse != null) {
        accessToken = oAuthResponse.getParam(OIDCAuthenticatorConstants.ACCESS_TOKEN);
        idToken = oAuthResponse.getParam(OIDCAuthenticatorConstants.ID_TOKEN);
      }

      if (accessToken != null && (idToken != null || !requiredIDToken(authenticatorProperties))) {

        context.setProperty(OIDCAuthenticatorConstants.ACCESS_TOKEN, accessToken);

        if (idToken != null) {
          context.setProperty(OIDCAuthenticatorConstants.ID_TOKEN, idToken);

          String base64Body = idToken.split("\\.")[1];
          byte[] decoded = Base64.decodeBase64(base64Body.getBytes());
          String json = new String(decoded, Charset.forName("utf-8"));

          if (log.isDebugEnabled()) {
            log.debug("Id token json string : " + json);
          }

          Map<String, Object> jsonObject = JSONUtils.parseJSON(json);

          if (jsonObject != null) {
            Map<ClaimMapping, String> claims = getSubjectAttributes(oAuthResponse);

            String authenticatedUser =
                (String) jsonObject.get(OIDCAuthenticatorConstants.Claim.EMAIL);
            AuthenticatedUser authenticatedUserObj =
                AuthenticatedUser.createFederateAuthenticatedUserFromSubjectIdentifier(
                    authenticatedUser);
            authenticatedUserObj.setUserAttributes(claims);
            context.setSubject(authenticatedUserObj);
          } else {
            if (log.isDebugEnabled()) {
              log.debug("Decoded json object is null");
            }
            throw new AuthenticationFailedException("Decoded json object is null");
          }
        } else {
          if (log.isDebugEnabled()) {
            log.debug("Authentication Failed");
          }
          throw new AuthenticationFailedException("Authentication Failed");
        }

      } else {
        throw new AuthenticationFailedException("Authentication Failed");
      }
    } catch (OAuthProblemException e) {
      throw new AuthenticationFailedException("Error occurred while acquiring access token", e);
    } catch (JSONException e) {
      throw new AuthenticationFailedException("Error occurred while parsing json object", e);
    }
  }
  /** Process the response of the Inwebo end-point */
  @Override
  protected void processAuthenticationResponse(
      HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
      throws AuthenticationFailedException {
    int waitTime;
    int retryInterval;
    String username = null;

    // Getting the last authenticated local user
    for (Integer stepMap : context.getSequenceConfig().getStepMap().keySet())
      if (context.getSequenceConfig().getStepMap().get(stepMap).getAuthenticatedUser() != null
          && context
                  .getSequenceConfig()
                  .getStepMap()
                  .get(stepMap)
                  .getAuthenticatedAutenticator()
                  .getApplicationAuthenticator()
              instanceof LocalApplicationAuthenticator) {
        username =
            String.valueOf(
                context.getSequenceConfig().getStepMap().get(stepMap).getAuthenticatedUser());
        break;
      }
    if (username != null) {
      UserRealm userRealm = null;
      try {
        String tenantDomain = MultitenantUtils.getTenantDomain(username);
        int tenantId = IdentityTenantUtil.getTenantId(tenantDomain);
        RealmService realmService = IdentityTenantUtil.getRealmService();
        userRealm = (UserRealm) realmService.getTenantUserRealm(tenantId);
        username = MultitenantUtils.getTenantAwareUsername(username);
        if (userRealm != null) {
          userId =
              userRealm
                  .getUserStoreManager()
                  .getUserClaimValue(username, InweboConstants.INWEBO_USERID, null)
                  .toString();
        } else {
          throw new AuthenticationFailedException(
              "Cannot find the user claim for the given userId: " + userId);
        }
      } catch (UserStoreException e) {
        throw new AuthenticationFailedException(
            "Error while getting the user realm" + e.getMessage(), e);
      }
    }
    Map<String, String> authenticatorProperties = context.getAuthenticatorProperties();
    if (authenticatorProperties != null) {
      String serviceId = authenticatorProperties.get(InweboConstants.SERVICE_ID);
      String p12file = authenticatorProperties.get(InweboConstants.INWEBO_P12FILE);
      String p12password = authenticatorProperties.get(InweboConstants.INWEBO_P12PASSWORD);
      if (!StringUtils.isEmpty(authenticatorProperties.get(InweboConstants.RETRY_COUNT))) {
        waitTime = Integer.parseInt(authenticatorProperties.get(InweboConstants.RETRY_COUNT));
      } else {
        waitTime = Integer.parseInt(InweboConstants.WAITTIME_DEFAULT);
      }
      if (!StringUtils.isEmpty(authenticatorProperties.get(InweboConstants.RETRY_INTERVAL))) {
        retryInterval =
            Integer.parseInt(authenticatorProperties.get(InweboConstants.RETRY_INTERVAL));
      } else {
        retryInterval = Integer.parseInt(InweboConstants.RETRYINTERVAL_DEFAULT);
      }
      PushRestCall push =
          new PushRestCall(serviceId, p12file, p12password, userId, waitTime, retryInterval);
      pushResponse = push.run();

      if (pushResponse.contains(InweboConstants.PUSHRESPONSE)) {
        if (log.isDebugEnabled()) {
          log.info("Authentication successful");
        }
        context.setSubject(
            AuthenticatedUser.createLocalAuthenticatedUserFromSubjectIdentifier(userId));
      } else {
        throw new AuthenticationFailedException("Authentication failed");
      }
      pushResponse = null;
      userId = null;
    } else {
      throw new AuthenticationFailedException("Required parameters are empty");
    }
  }
  @Override
  protected void processAuthenticationResponse(
      HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
      throws AuthenticationFailedException {

    try {

      Map<String, String> authenticatorProperties = context.getAuthenticatorProperties();

      String clientId = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_ID);
      String clientSecret = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_SECRET);
      String tokenEndPoint = getTokenEndpoint(authenticatorProperties);

      if (tokenEndPoint == null) {
        tokenEndPoint = authenticatorProperties.get(OIDCAuthenticatorConstants.OAUTH2_TOKEN_URL);
      }

      String callbackUrl = getCallbackUrl(authenticatorProperties);

      if (StringUtils.isBlank(callbackUrl)) {
        callbackUrl = IdentityUtil.getServerURL(FrameworkConstants.COMMONAUTH, true, true);
      }

      @SuppressWarnings({"unchecked"})
      Map<String, String> paramValueMap =
          (Map<String, String>) context.getProperty("oidc:param.map");

      if (paramValueMap != null && paramValueMap.containsKey("redirect_uri")) {
        callbackUrl = paramValueMap.get("redirect_uri");
      }

      OAuthAuthzResponse authzResponse = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
      String code = authzResponse.getCode();

      OAuthClientRequest accessRequest =
          getaccessRequest(tokenEndPoint, clientId, code, clientSecret, callbackUrl);

      // Create OAuth client that uses custom http client under the hood
      OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
      OAuthClientResponse oAuthResponse = getOauthResponse(oAuthClient, accessRequest);

      // TODO : return access token and id token to framework
      String accessToken = oAuthResponse.getParam(OIDCAuthenticatorConstants.ACCESS_TOKEN);

      if (StringUtils.isBlank(accessToken)) {
        throw new AuthenticationFailedException("Access token is empty or null");
      }

      String idToken = oAuthResponse.getParam(OIDCAuthenticatorConstants.ID_TOKEN);

      if (StringUtils.isBlank(idToken) && requiredIDToken(authenticatorProperties)) {
        throw new AuthenticationFailedException("Id token is required and is missing");
      }

      context.setProperty(OIDCAuthenticatorConstants.ACCESS_TOKEN, accessToken);

      AuthenticatedUser authenticatedUserObj;
      Map<ClaimMapping, String> claims = new HashMap<>();
      Map<String, Object> jsonObject = new HashMap<>();

      if (StringUtils.isNotBlank(idToken)) {

        context.setProperty(OIDCAuthenticatorConstants.ID_TOKEN, idToken);

        String base64Body = idToken.split("\\.")[1];
        byte[] decoded = Base64.decodeBase64(base64Body.getBytes());
        String json = new String(decoded);

        jsonObject = JSONUtils.parseJSON(json);

        if (jsonObject == null) {

          if (log.isDebugEnabled()) {
            log.debug("Decoded json object is null");
          }

          throw new AuthenticationFailedException("Decoded json object is null");
        }

        if (log.isDebugEnabled()
            && IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.USER_ID_TOKEN)) {
          log.debug("Retrieved the User Information:" + jsonObject);
        }

        String authenticatedUser = null;
        String isSubjectInClaimsProp =
            context
                .getAuthenticatorProperties()
                .get(IdentityApplicationConstants.Authenticator.SAML2SSO.IS_USER_ID_IN_CLAIMS);

        if (StringUtils.equalsIgnoreCase("true", isSubjectInClaimsProp)) {

          authenticatedUser = getSubjectFromUserIDClaimURI(context);

          if (authenticatedUser == null && log.isDebugEnabled()) {
            log.debug(
                "Subject claim could not be found amongst subject attributes. "
                    + "Defaulting to the sub attribute in IDToken.");
          }
        }

        if (authenticatedUser == null) {

          authenticatedUser = getAuthenticateUser(context, jsonObject, oAuthResponse);

          if (authenticatedUser == null) {
            throw new AuthenticationFailedException("Cannot find federated User Identifier");
          }
        }

        String attributeSeparator = null;

        try {

          String tenantDomain = context.getTenantDomain();

          if (StringUtils.isBlank(tenantDomain)) {
            tenantDomain = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
          }

          int tenantId =
              OpenIDConnectAuthenticatorServiceComponent.getRealmService()
                  .getTenantManager()
                  .getTenantId(tenantDomain);
          UserRealm userRealm =
              OpenIDConnectAuthenticatorServiceComponent.getRealmService()
                  .getTenantUserRealm(tenantId);

          if (userRealm != null) {
            UserStoreManager userStore = (UserStoreManager) userRealm.getUserStoreManager();
            attributeSeparator =
                userStore
                    .getRealmConfiguration()
                    .getUserStoreProperty(IdentityCoreConstants.MULTI_ATTRIBUTE_SEPARATOR);
            if (log.isDebugEnabled()) {
              log.debug(
                  "For the claim mapping: "
                      + attributeSeparator
                      + " is used as the attributeSeparator in tenant: "
                      + tenantDomain);
            }
          }

        } catch (UserStoreException e) {
          throw new AuthenticationFailedException(
              "Error while retrieving multi attribute " + "separator", e);
        }

        for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
          buildClaimMappings(claims, entry, attributeSeparator);
        }

        authenticatedUserObj =
            AuthenticatedUser.createFederateAuthenticatedUserFromSubjectIdentifier(
                authenticatedUser);
      } else {

        if (log.isDebugEnabled()) {
          log.debug("The IdToken is null");
        }

        authenticatedUserObj =
            AuthenticatedUser.createFederateAuthenticatedUserFromSubjectIdentifier(
                getAuthenticateUser(context, jsonObject, oAuthResponse));
      }

      claims.putAll(getSubjectAttributes(oAuthResponse, authenticatorProperties));
      authenticatedUserObj.setUserAttributes(claims);

      context.setSubject(authenticatedUserObj);

    } catch (OAuthProblemException e) {
      throw new AuthenticationFailedException("Authentication process failed", e);
    }
  }
  @Override
  protected void initiateAuthenticationRequest(
      HttpServletRequest request, HttpServletResponse response, AuthenticationContext context)
      throws AuthenticationFailedException {

    try {
      Map<String, String> authenticatorProperties = context.getAuthenticatorProperties();
      if (authenticatorProperties != null) {
        String clientId = authenticatorProperties.get(OIDCAuthenticatorConstants.CLIENT_ID);
        String authorizationEP = getAuthorizationServerEndpoint(authenticatorProperties);

        if (authorizationEP == null) {
          authorizationEP =
              authenticatorProperties.get(OIDCAuthenticatorConstants.OAUTH2_AUTHZ_URL);
        }

        String callbackurl = getCallbackUrl(authenticatorProperties);

        if (StringUtils.isBlank(callbackurl)) {
          callbackurl = IdentityUtil.getServerURL(FrameworkConstants.COMMONAUTH, true, true);
        }

        String state = context.getContextIdentifier() + "," + OIDCAuthenticatorConstants.LOGIN_TYPE;

        state = getState(state, authenticatorProperties);

        OAuthClientRequest authzRequest;

        String queryString = getQueryString(authenticatorProperties);
        Map<String, String> paramValueMap = new HashMap<>();

        if (StringUtils.isNotBlank(queryString)) {
          String[] params = queryString.split("&");
          if (params != null && params.length > 0) {
            for (String param : params) {
              String[] intParam = param.split("=");
              paramValueMap.put(intParam[0], intParam[1]);
            }
            context.setProperty("oidc:param.map", paramValueMap);
          }
        }

        String scope = paramValueMap.get("scope");

        if (scope == null) {
          scope = OIDCAuthenticatorConstants.OAUTH_OIDC_SCOPE;
        }

        scope = getScope(scope, authenticatorProperties);

        if (queryString != null
            && queryString.toLowerCase().contains("scope=")
            && queryString.toLowerCase().contains("redirect_uri=")) {
          authzRequest =
              OAuthClientRequest.authorizationLocation(authorizationEP)
                  .setClientId(clientId)
                  .setResponseType(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE)
                  .setState(state)
                  .buildQueryMessage();
        } else if (queryString != null && queryString.toLowerCase().contains("scope=")) {
          authzRequest =
              OAuthClientRequest.authorizationLocation(authorizationEP)
                  .setClientId(clientId)
                  .setRedirectURI(callbackurl)
                  .setResponseType(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE)
                  .setState(state)
                  .buildQueryMessage();
        } else if (queryString != null && queryString.toLowerCase().contains("redirect_uri=")) {
          authzRequest =
              OAuthClientRequest.authorizationLocation(authorizationEP)
                  .setClientId(clientId)
                  .setResponseType(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE)
                  .setScope(OIDCAuthenticatorConstants.OAUTH_OIDC_SCOPE)
                  .setState(state)
                  .buildQueryMessage();

        } else {
          authzRequest =
              OAuthClientRequest.authorizationLocation(authorizationEP)
                  .setClientId(clientId)
                  .setRedirectURI(callbackurl)
                  .setResponseType(OIDCAuthenticatorConstants.OAUTH2_GRANT_TYPE_CODE)
                  .setScope(scope)
                  .setState(state)
                  .buildQueryMessage();
        }

        String loginPage = authzRequest.getLocationUri();
        String domain = request.getParameter("domain");

        if (domain != null) {
          loginPage = loginPage + "&fidp=" + domain;
        }

        if (queryString != null) {
          if (!queryString.startsWith("&")) {
            loginPage = loginPage + "&" + queryString;
          } else {
            loginPage = loginPage + queryString;
          }
        }
        response.sendRedirect(loginPage);
      } else {
        if (log.isDebugEnabled()) {
          log.debug("Error while retrieving properties. Authenticator Properties cannot be null");
        }
        throw new AuthenticationFailedException(
            "Error while retrieving properties. Authenticator Properties cannot be null");
      }
    } catch (IOException e) {
      log.error("Exception while sending to the login page", e);
      throw new AuthenticationFailedException(e.getMessage(), e);
    } catch (OAuthSystemException e) {
      log.error("Exception while building authorization code request", e);
      throw new AuthenticationFailedException(e.getMessage(), e);
    }
    return;
  }