Beispiel #1
0
  static {
    String status = SystemProperties.get(Constants.AM_LOGSTATUS, "INACTIVE");
    if ("ACTIVE".equalsIgnoreCase(status)) {
      logStatus = true;
    }

    // Get Directory Port value
    try {
      directoryPort = Integer.parseInt(SystemProperties.get(Constants.AM_DIRECTORY_PORT));
    } catch (java.lang.NumberFormatException nfex) {
      directoryPort = 0;
    }

    // Get Session store
    String useHttpSessionStr = SystemProperties.get(ISAuthConstants.SESSION_STORE);
    if (useHttpSessionStr != null && useHttpSessionStr.equalsIgnoreCase("HttpSession")) {
      useHttpSession = true;
    }

    debug = Debug.getInstance(BUNDLE_NAME);
    if (debug.messageEnabled()) {
      debug.message("Directory Host: " + directoryHostName + "\nDirectory PORT : " + directoryPort);
      debug.message("Session store using " + useHttpSessionStr);
    }
  }
Beispiel #2
0
  /** Creates <code>AuthXMLHandler</code> object */
  public AuthXMLHandler() {
    localAuthServerProtocol = SystemProperties.get(Constants.AM_SERVER_PROTOCOL);
    localAuthServer = SystemProperties.get(Constants.AM_SERVER_HOST);
    localAuthServerPort = SystemProperties.get(Constants.AM_SERVER_PORT);

    AuthContext.localAuthServiceID =
        localAuthServerProtocol + "://" + localAuthServer + ":" + localAuthServerPort;
    locale = (new ISLocaleContext()).getLocale();
  }
Beispiel #3
0
  /**
   * Updates the <code>iPlanetAMLoggingService<code> service schema.
   *
   * @return true if successful otherwise false.
   */
  public boolean migrateService() {
    boolean isSuccess = false;
    try {
      // read the values from AMConfig.properties
      String logStatus = SystemProperties.get("com.iplanet.am.logStatus");
      String resolveHostName = SystemProperties.get("com.sun.identity.log.resolveHostName");

      // update default value
      Set defaultValues = new HashSet();
      defaultValues.add("NameID");
      UpgradeUtils.addAttributeDefaultValues(
          SERVICE_NAME, null, schemaType, LOG_ALL_FIELDS_ATTR_NAME, defaultValues);

      // update choice value
      Map choiceValuesMap = new HashMap();
      choiceValuesMap.put("choiceNameID", defaultValues);
      UpgradeUtils.addAttributeChoiceValues(
          SERVICE_NAME, null, schemaType, LOG_ATTR_NAME, choiceValuesMap);

      // add new attribute schema
      String fileName = UpgradeUtils.getAbsolutePath(SERVICE_DIR, SCHEMA_FILE);
      UpgradeUtils.addAttributeToSchema(SERVICE_NAME, schemaType, fileName);

      // populate the default values for logstatus & resolveHostName
      // from amconfig.properties
      defaultValues.clear();
      defaultValues.add(logStatus);
      UpgradeUtils.setAttributeDefaultValues(
          SERVICE_NAME, null, schemaType, LOG_STATUS_ATTR, defaultValues);
      defaultValues.clear();
      defaultValues.add(resolveHostName);
      UpgradeUtils.setAttributeDefaultValues(
          SERVICE_NAME, null, schemaType, RESOLVE_HOSTNAME_ATTR, defaultValues);
      String histNumFile =
          UpgradeUtils.getAttributeValueString(SERVICE_NAME, LOG_HIST_NUM_ATTR_NAME, schemaType);
      if (histNumFile != null && histNumFile.equals(DEFAULT_HIST_NUM)) {
        defaultValues.clear();
        defaultValues.add(NEW_DEFAULT_HIST_NUM);
        UpgradeUtils.setAttributeDefaultValues(
            SERVICE_NAME, null, schemaType, LOG_HIST_NUM_ATTR_NAME, defaultValues);
      }

      String maxLogSize =
          UpgradeUtils.getAttributeValueString(
              SERVICE_NAME, LOG_MAX_FILE_SIZE_ATTR_NAME, schemaType);
      if (maxLogSize != null && maxLogSize.equals(DEFAULT_LOG_SIZE)) {
        defaultValues.clear();
        defaultValues.add(NEW_DEFAULT_LOG_SIZE);
        UpgradeUtils.setAttributeDefaultValues(
            SERVICE_NAME, null, schemaType, LOG_MAX_FILE_SIZE_ATTR_NAME, defaultValues);
      }
      isSuccess = true;
    } catch (UpgradeException e) {
      UpgradeUtils.debug.error("Error loading data:" + SERVICE_NAME, e);
    }
    return isSuccess;
  }
 @Override
 public void updateExternalLdapConfiguration(
     ModifiedProperty<String> hosts,
     ModifiedProperty<String> username,
     ModifiedProperty<String> password,
     ModifiedProperty<String> maxConnections,
     ModifiedProperty<Boolean> sslMode,
     ModifiedProperty<Integer> heartbeat) {
   hosts.set(SystemProperties.get(STORE_HOSTNAME));
   username.set(SystemProperties.get(STORE_USERNAME));
   password.set(AMPasswordUtil.decrypt(SystemProperties.get(STORE_PASSWORD)));
   maxConnections.set(SystemProperties.get(STORE_MAX_CONNECTIONS));
   sslMode.set(SystemProperties.getAsBoolean(STORE_SSL_ENABLED, false));
   heartbeat.set(SystemProperties.getAsInt(STORE_HEARTBEAT, -1));
 }
Beispiel #5
0
 /* build the trust source set*/
 private static Set getTrustedSourceList() throws SessionException {
   Set result = new HashSet();
   try {
     String rawList = SystemProperties.get(Constants.TRUSTED_SOURCE_LIST);
     if (rawList != null) {
       StringTokenizer stk = new StringTokenizer(rawList, ",");
       while (stk.hasMoreTokens()) {
         result.add(InetAddress.getByName(stk.nextToken()));
       }
     } else {
       // use platform server list as a default fallback
       Vector psl = WebtopNaming.getPlatformServerList();
       if (psl == null) {
         throw new SessionException(SessionBundle.rbName, "emptyTrustedSourceList", null);
       }
       for (Enumeration e = psl.elements(); e.hasMoreElements(); ) {
         try {
           URL url = new URL((String) e.nextElement());
           result.add(InetAddress.getByName(url.getHost()));
         } catch (Exception ex) {
           debug.error("SessionUtils.getTrustedSourceList : " + "Validating Host exception", ex);
         }
       }
     }
   } catch (Exception e) {
     throw new SessionException(e);
   }
   return result;
 }
Beispiel #6
0
  /**
   * Returns Replication Status by invoking OpenDJ <code>dsreplication</code> CLI
   *
   * @param port LDAP port number of embedded OpenDJ
   * @param passwd Directory Manager password
   * @param oo Standard output
   * @param err : Standard error
   * @return <code>dsreplication</code> CLI exit code.
   */
  public static int getReplicationStatus(
      String port, String passwd, OutputStream oo, OutputStream err) {
    Debug debug = Debug.getInstance(SetupConstants.DEBUG_NAME);
    String baseDir = SystemProperties.get(SystemProperties.CONFIG_PATH);

    String[] statusCmd = {
      "status",
      "--no-prompt",
      "-h",
      "localhost",
      "-p",
      port,
      "--adminUID",
      "admin",
      "--adminPassword",
      passwd,
      "-s",
      "--configFile",
      baseDir + "/opends/config/config.ldif"
    };
    if (debug.messageEnabled()) {
      String dbgcmd = concat(statusCmd).replaceAll(passwd, "****");
      debug.message("EmbeddedOpenDS:getReplicationStatus:exec dsreplication :" + dbgcmd);
    }
    int ret = ReplicationCliMain.mainCLI(statusCmd, false, oo, err, null);
    if (debug.messageEnabled()) {
      debug.message("EmbeddedOpenDS:getReplicationStatus:dsreplication ret:" + ret);
    }
    return ret;
  }
Beispiel #7
0
 private AuthD() {
   debug.message("AuthD initializing");
   try {
     rootSuffix = defaultOrg = ServiceManager.getBaseDN();
     initAuthSessions();
     initAuthServiceGlobalSettings();
     initPlatformServiceGlobalSettings();
     initSessionServiceDynamicSettings();
     initAuthConfigGlobalSettings();
     bundle = com.sun.identity.shared.locale.Locale.getInstallResourceBundle(BUNDLE_NAME);
     ResourceBundle platBundle =
         com.sun.identity.shared.locale.Locale.getInstallResourceBundle("amPlatform");
     platformCharset = platBundle.getString(ISAuthConstants.PLATFORM_CHARSET_ATTR);
     printProfileAttrs();
     // Initialize AuthXMLHandler so that AdminTokenAction can
     // generate DPro Session's SSOToken
     new com.sun.identity.authentication.server.AuthXMLHandler();
     authInitFailed = false;
   } catch (Exception ex) {
     debug.error("AuthD init()", ex);
     authInitFailed = true;
   }
   try {
     enforceJAASThread =
         Boolean.valueOf(SystemProperties.get(Constants.ENFORCE_JAAS_THREAD)).booleanValue();
   } catch (Exception e) {
     if (debug.messageEnabled()) {
       debug.message("Wrong format of " + Constants.ENFORCE_JAAS_THREAD);
     }
   }
 }
 /**
  * @param config the ServletConfig object that contains configutation information for this
  *     servlet.
  * @exception ServletException if an exception occurs that interrupts the servlet's normal
  *     operation.
  */
 public void init(ServletConfig config) throws ServletException {
   super.init(config);
   if (debug.messageEnabled()) {
     debug.message("CDCClientServlet.init:CDCClientServlet " + "Initializing...");
   }
   try {
     tokenManager = SSOTokenManager.getInstance();
   } catch (SSOException ssoe) {
     debug.error("CDCClientServlet.init:unable to get SSOTokenManager", ssoe);
   }
   authURLCookieName =
       SystemProperties.get(Constants.AUTH_UNIQUE_COOKIE_NAME, "sunIdentityServerAuthNServer");
   authURLCookieDomain = SystemProperties.get(Constants.AUTH_UNIQUE_COOKIE_DOMAIN, "");
   deployDescriptor =
       SystemProperties.get(Constants.AM_DISTAUTH_DEPLOYMENT_DESCRIPTOR, "/distauth");
 }
 @Override
 public StoreMode getStoreMode() {
   String mode = SystemProperties.get(STORE_LOCATION);
   if (StringUtils.isNotEmpty(mode)) {
     return StoreMode.valueOf(mode.toUpperCase());
   } else {
     return StoreMode.DEFAULT;
   }
 }
  /**
   * Retrieves all server info set on the server.
   *
   * @param context Current Server Context.
   * @param realm realm in whose security context we use.
   */
  private Promise<ResourceResponse, ResourceException> getAllServerInfo(
      Context context, String realm) {
    JsonValue result = new JsonValue(new LinkedHashMap<String, Object>(1));
    Set<String> cookieDomains;
    ResourceResponse resource;

    // added for the XUI to be able to understand its locale to request the appropriate translations
    // to cache
    ISLocaleContext localeContext = new ISLocaleContext();
    HttpContext httpContext = context.asContext(HttpContext.class);
    localeContext.setLocale(
        httpContext); // we have nothing else to go on at this point other than their request

    SelfServiceInfo selfServiceInfo = configHandler.getConfig(realm, SelfServiceInfoBuilder.class);
    RestSecurity restSecurity = restSecurityProvider.get(realm);
    Set<String> protectedUserAttributes = new HashSet<>();
    protectedUserAttributes.addAll(selfServiceInfo.getProtectedUserAttributes());
    protectedUserAttributes.addAll(restSecurity.getProtectedUserAttributes());

    try {
      cookieDomains = AuthClientUtils.getCookieDomains();
      result.put("domains", cookieDomains);
      result.put("protectedUserAttributes", protectedUserAttributes);
      result.put(
          "cookieName", SystemProperties.get(Constants.AM_COOKIE_NAME, "iPlanetDirectoryPro"));
      result.put("secureCookie", CookieUtils.isCookieSecure());
      result.put("forgotPassword", String.valueOf(selfServiceInfo.isForgottenPasswordEnabled()));
      result.put("forgotUsername", String.valueOf(selfServiceInfo.isForgottenUsernameEnabled()));
      result.put("kbaEnabled", String.valueOf(selfServiceInfo.isKbaEnabled()));
      result.put("selfRegistration", String.valueOf(selfServiceInfo.isUserRegistrationEnabled()));
      result.put("lang", getJsLocale(localeContext.getLocale()));
      result.put("successfulUserRegistrationDestination", "default");
      result.put("socialImplementations", getSocialAuthnImplementations(realm));
      result.put("referralsEnabled", Boolean.FALSE.toString());
      result.put("zeroPageLogin", AuthUtils.getZeroPageLoginConfig(realm));
      result.put("realm", realm);
      result.put(
          "xuiUserSessionValidationEnabled",
          SystemProperties.getAsBoolean(Constants.XUI_USER_SESSION_VALIDATION_ENABLED, true));

      if (debug.messageEnabled()) {
        debug.message(
            "ServerInfoResource.getAllServerInfo ::"
                + " Added resource to response: "
                + ALL_SERVER_INFO);
      }

      resource =
          newResourceResponse(ALL_SERVER_INFO, Integer.toString(result.asMap().hashCode()), result);

      return newResultPromise(resource);
    } catch (Exception e) {
      debug.error(
          "ServerInfoResource.getAllServerInfo : Cannot retrieve all server info domains.", e);
      return new NotFoundException(e.getMessage()).asPromise();
    }
  }
Beispiel #11
0
  private static void initConfig() {
    adviceParams.add("module");
    adviceParams.add("authlevel");
    adviceParams.add("role");
    adviceParams.add("service");
    adviceParams.add("user");
    adviceParams.add("realm");
    adviceParams.add("org");
    adviceParams.add("resource");
    adviceParams.add("sunamcompositeadvice");
    String invalidStrings = SystemPropertiesManager.get(Constants.INVALID_GOTO_STRINGS);
    if (INVALID_SET.isEmpty()) {
      debug.message("CDCClientServlet.initConfig: creating invalidSet");
      if (invalidStrings == null) {
        debug.message("CDCClientServlet.initConfig: invalidStrings is null");
        INVALID_SET.add(LEFT_ANGLE);
        INVALID_SET.add(RIGHT_ANGLE);
        INVALID_SET.add(URLENC_LEFT_ANGLE);
        INVALID_SET.add(URLENC_RIGHT_ANGLE);
        INVALID_SET.add(JAVASCRIPT);
        INVALID_SET.add(URLENC_JAVASCRIPT);
      } else {
        if (debug.messageEnabled()) {
          debug.message("CDCClientServlet.initConfig: invalidStrings is: " + invalidStrings);
        }
        StringTokenizer st = new StringTokenizer(invalidStrings, DELIM);
        while (st.hasMoreTokens()) {
          INVALID_SET.add(st.nextToken());
        }
      }
      debug.message("CDCClientServlet.initConfig: created invalidSet " + INVALID_SET);
    }

    String urlFromProps = SystemProperties.get(Constants.CDCSERVLET_LOGIN_URL);
    cdcAuthURI = (urlFromProps != null) ? urlFromProps : AUTHURI;

    String validLoginURIStrings = SystemPropertiesManager.get(Constants.VALID_LOGIN_URIS);
    debug.message("CDCClientServlet.initConfig: creating validLoginURISet");
    if (validLoginURIStrings == null) {
      debug.message(
          "CDCClientServlet.initConfig: validLoginURIStrings is null, creating default set");
      VALID_LOGIN_URIS.add(cdcAuthURI);
    } else {
      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.initConfig: validLoginURIStrings is: " + validLoginURIStrings);
      }
      StringTokenizer st = new StringTokenizer(validLoginURIStrings, DELIM);
      while (st.hasMoreTokens()) {
        VALID_LOGIN_URIS.add(st.nextToken());
      }
    }
    debug.message("CDCClientServlet.initConfig: created validLoginURISet " + VALID_LOGIN_URIS);
  }
Beispiel #12
0
 private static HashSet getPropertyRetryErrorCodes(String key) {
   HashSet codes = new HashSet();
   String retryErrorStr = SystemProperties.get(key);
   if (retryErrorStr != null && retryErrorStr.trim().length() > 0) {
     StringTokenizer stz = new StringTokenizer(retryErrorStr, ",");
     while (stz.hasMoreTokens()) {
       codes.add(stz.nextToken().trim());
     }
   }
   return codes;
 }
  static {
    String tmp = SystemProperties.get("com.iplanet.am.jssproxy.trustAllServerCerts");
    trustAllServerCerts = (tmp != null && tmp.equalsIgnoreCase("true"));

    tmp = SystemProperties.get("com.iplanet.am.jssproxy.checkSubjectAltName");
    checkSubjectAltName = (tmp != null && tmp.equalsIgnoreCase("true"));

    tmp = SystemProperties.get("com.iplanet.am.jssproxy.resolveIPAddress");
    resolveIPAddress = (tmp != null && tmp.equalsIgnoreCase("true"));

    tmp = SystemProperties.get("com.iplanet.am.jssproxy.SSLTrustHostList", null);
    if (tmp != null) {
      getSSLTrustHosts(tmp);
    }

    if (debug.messageEnabled()) {
      debug.message("AMHostnameVerifier trustAllServerCerts = " + trustAllServerCerts);
      debug.message("AMHostnameVerifier checkSubjectAltName = " + checkSubjectAltName);
      debug.message("AMHostnameVerifier  resolveIPAddress = " + resolveIPAddress);
      debug.message("AMHostnameVerifier  SSLTrustHostList = " + sslTrustHosts.toString());
    }
  }
Beispiel #14
0
 public Class<? extends DataLayerConnectionModule> getConfigurationClass() {
   String configuredTypeKey = CONFIGURATION_CLASS_PROPERTY_PREFIX + this.name();
   String configuredType = SystemProperties.get(configuredTypeKey);
   if (StringUtils.isNotBlank(configuredType)) {
     try {
       return Class.forName(configuredType).asSubclass(DataLayerConnectionModule.class);
     } catch (ClassNotFoundException e) {
       throw new IllegalStateException(
           "Configured data layer configuration type does not exist: "
               + configuredTypeKey
               + " is configured as "
               + configuredType);
     }
   }
   return configurationClass;
 }
  // Static Initialization Stanza.
  static {
    sessionDebug = Debug.getInstance("amSession");

    if (doRequestFlag != null) {
      if (doRequestFlag.equals("false")) doRequest = false;
    }
    if (hcPath == null) {
      String deployuri =
          SystemProperties.get(Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR, "/openam");
      hcPath = deployuri + "/namingservice";
      if (!hcPath.startsWith("/")) {
        hcPath += "/" + hcPath;
      }

      GET_REQUEST = "GET " + hcPath + " HTTP/1.0";
    }
  } // End of Static Initialization Stanza
 /**
  * Method to check if caching is enabled or disabled and configure the size of the cache
  * accordingly.
  */
 private static void initializeParams() {
   // Check if the caching property is set in System runtime.
   String cacheSize = SystemProperties.get(CACHE_MAX_SIZE_KEY, "10000");
   try {
     maxSize = Integer.parseInt(cacheSize);
     if (maxSize < 1) {
       maxSize = 10000; // Default
     }
     if (getDebug().messageEnabled()) {
       getDebug()
           .message(
               "CachedRemoteServicesImpl." + "intializeParams() Caching size set to: " + maxSize);
     }
   } catch (NumberFormatException ne) {
     maxSize = 10000;
     getDebug()
         .warning(
             "CachedRemoteServicesImpl.initializeParams() "
                 + "- invalid value for cache size specified. Setting "
                 + "to default value: "
                 + maxSize);
   }
 }
Beispiel #17
0
  private int validateTokenId(HttpServletRequest request) throws ServletException, IOException {
    String tokenId = request.getHeader(RestServiceManager.SUBJECT_HEADER_NAME);
    String hashed = request.getParameter(RestServiceManager.HASHED_SUBJECT_QUERY);

    if (((tokenId == null) || (tokenId.trim().length() == 0))
        && ((hashed == null) || (hashed.trim().length() == 0))) {
      // by pass the check
      return HttpServletResponse.SC_OK;
    }

    if ((tokenId == null) || (tokenId.trim().length() == 0)) {
      try {
        SSOTokenManager mgr = SSOTokenManager.getInstance();
        SSOToken token = mgr.createSSOToken(request);
        tokenId = token.getTokenID().toString();
      } catch (SSOException e) {
        return HttpServletResponse.SC_UNAUTHORIZED;
      }
    }

    if (!Boolean.parseBoolean(
        SystemProperties.get(RestServiceManager.DISABLE_HASHED_SUBJECT_CHECK, "false"))) {
      if ((hashed == null) || (hashed.trim().length() == 0)) {
        return HttpServletResponse.SC_UNAUTHORIZED;
      } else {
        int idx = tokenId.indexOf(':');
        if (idx != -1) {
          tokenId = tokenId.substring(idx + 1);
        }
        if (!Hash.hash(tokenId).equals(hashed)) {
          return HttpServletResponse.SC_UNAUTHORIZED;
        }
      }
    }

    return HttpServletResponse.SC_OK;
  }
Beispiel #18
0
  private static int getPropertyIntValue(String key, int defaultValue) {
    int value = defaultValue;
    String valueStr = SystemProperties.get(key);
    if (valueStr != null && valueStr.trim().length() > 0) {
      try {
        value = Integer.parseInt(valueStr);
      } catch (NumberFormatException e) {
        value = defaultValue;
        if (debugger.warningEnabled()) {
          debugger.warning(
              "EventService.getPropertyIntValue(): "
                  + "Invalid value for property: "
                  + EVENT_CONNECTION_NUM_RETRIES
                  + " Defaulting to value: "
                  + defaultValue);
        }
      }
    }

    if (debugger.messageEnabled()) {
      debugger.message("EventService.getPropertyIntValue(): " + key + " = " + value);
    }
    return value;
  }
 private String getSsoTokenId(OAuth2Request request) {
   return cookieExtractor.extract(
       ServletUtils.getRequest(request.<Request>getRequest()),
       SystemProperties.get("com.iplanet.am.cookie.name"));
 }
Beispiel #20
0
/**
 * This class is used to initialize the Authentication service and retrieve the Global attributes
 * for the Authentication service. It also initializes the other dependent services in the OpenSSO
 * system and hence used as bootstrap class for the authentication server.
 */
public class AuthD {
  /** Debug instance for error / message logging */
  public static Debug debug;

  private static Map bundles = new HashMap();
  private static AuthD authInstance;
  private static boolean authInitFailed = false;

  private static String superAdmin =
      DNUtils.normalizeDN(SystemProperties.get(Constants.AUTHENTICATION_SUPER_USER, ""));
  private static AMIdentity superUserIdentity = null;
  private static String specialUser =
      SystemProperties.get(Constants.AUTHENTICATION_SPECIAL_USERS, "");

  // Admin Console properties
  private static final String consoleProto =
      SystemProperties.get(Constants.AM_CONSOLE_PROTOCOL, "http");
  private static final String consoleHost = SystemProperties.get(Constants.AM_CONSOLE_HOST);
  private static final String consolePort = SystemProperties.get(Constants.AM_CONSOLE_PORT);
  private static final boolean isConsoleRemote =
      Boolean.valueOf(SystemProperties.get(Constants.AM_CONSOLE_REMOTE)).booleanValue();

  /** Default auth level for auth module */
  public static final String DEFAULT_AUTH_LEVEL = "0";
  /** Configured value for access logging */
  public static final int LOG_ACCESS = 0;
  /** Configured value for error logging */
  public static final int LOG_ERROR = 1;

  /** supported Auth Modules cache - lw */
  public static Hashtable sAuth;

  /** Flag to force to use JAAS thread. Default is false. */
  public static boolean enforceJAASThread = false;
  /** Configured directory server host name for auth */
  public static String directoryHostName = SystemProperties.get(Constants.AM_DIRECTORY_HOST);
  /** Configured directory server port number for auth */
  public static int directoryPort;

  /** Configured revisionNumber for auth service */
  public static int revisionNumber;

  private static HashMap idRepoMap = new HashMap();
  private static HashMap orgMap = new HashMap();
  private static HashMap orgValidDomains = new HashMap();

  /** Configured bundle name for auth service */
  public static final String BUNDLE_NAME = ISAuthConstants.AUTH_BUNDLE_NAME;

  private String defaultOrg;
  private String platformLocale;
  private String platformCharset;
  /** ResourceBundle for auth service */
  public ResourceBundle bundle = null;

  private SSOToken ssoAuthSession = null;
  private Session authSession = null;
  private AMStoreConnection dpStore = null;

  //  client detection and client type variable
  String clientDetectionClass = null;

  /** locale read from AMConfig.properties used for remote client auth. */
  public static String platLocale = SystemProperties.get(Constants.AM_LOCALE);

  // auth default locale defined in iPlanetAMAuthService
  private String defaultAuthLocale;

  // platform service schema
  ServiceSchema platformSchema;
  // session service schema
  ServiceSchema sessionSchema;

  // table for service templates
  private static boolean logStatus = false;
  /** Set of default URLs for login success */
  public Set defaultSuccessURLSet = null;
  /** Current default URLs for login success */
  public String defaultSuccessURL = null;
  /** Set of default URLs for login failure */
  public Set defaultFailureURLSet = null;
  /** Current default URLs for login failure */
  public String defaultFailureURL = null;
  /** Set of default URLs for service success */
  public Set defaultServiceSuccessURLSet = null;
  /** Set of default URLs for service failure */
  public Set defaultServiceFailureURLSet = null;

  private String adminAuthModule;
  /** Default auth level for module */
  public String defaultAuthLevel;

  private Hashtable authMethods = new Hashtable();
  private long defaultSleepTime = 300; /* 5 minutes */

  private ServletContext servletContext;
  private static boolean useHttpSession;

  static {
    String status = SystemProperties.get(Constants.AM_LOGSTATUS, "INACTIVE");
    if ("ACTIVE".equalsIgnoreCase(status)) {
      logStatus = true;
    }

    // Get Directory Port value
    try {
      directoryPort = Integer.parseInt(SystemProperties.get(Constants.AM_DIRECTORY_PORT));
    } catch (java.lang.NumberFormatException nfex) {
      directoryPort = 0;
    }

    // Get Session store
    String useHttpSessionStr = SystemProperties.get(ISAuthConstants.SESSION_STORE);
    if (useHttpSessionStr != null && useHttpSessionStr.equalsIgnoreCase("HttpSession")) {
      useHttpSession = true;
    }

    debug = Debug.getInstance(BUNDLE_NAME);
    if (debug.messageEnabled()) {
      debug.message("Directory Host: " + directoryHostName + "\nDirectory PORT : " + directoryPort);
      debug.message("Session store using " + useHttpSessionStr);
    }
  }

  String rootSuffix = null;

  private AuthD() {
    debug.message("AuthD initializing");
    try {
      rootSuffix = defaultOrg = ServiceManager.getBaseDN();
      initAuthSessions();
      initAuthServiceGlobalSettings();
      initPlatformServiceGlobalSettings();
      initSessionServiceDynamicSettings();
      initAuthConfigGlobalSettings();
      bundle = com.sun.identity.shared.locale.Locale.getInstallResourceBundle(BUNDLE_NAME);
      ResourceBundle platBundle =
          com.sun.identity.shared.locale.Locale.getInstallResourceBundle("amPlatform");
      platformCharset = platBundle.getString(ISAuthConstants.PLATFORM_CHARSET_ATTR);
      printProfileAttrs();
      // Initialize AuthXMLHandler so that AdminTokenAction can
      // generate DPro Session's SSOToken
      new com.sun.identity.authentication.server.AuthXMLHandler();
      authInitFailed = false;
    } catch (Exception ex) {
      debug.error("AuthD init()", ex);
      authInitFailed = true;
    }
    try {
      enforceJAASThread =
          Boolean.valueOf(SystemProperties.get(Constants.ENFORCE_JAAS_THREAD)).booleanValue();
    } catch (Exception e) {
      if (debug.messageEnabled()) {
        debug.message("Wrong format of " + Constants.ENFORCE_JAAS_THREAD);
      }
    }
  }

  /**
   * Initialized auth service global attributes
   *
   * @throws SMSException if it fails to get auth service for name
   * @throws SSOException if admin <code>SSOToken</code> is not valid
   * @throws Exception
   */
  private void initAuthServiceGlobalSettings() throws SMSException, SSOException, Exception {
    ServiceSchemaManager scm =
        new ServiceSchemaManager(ISAuthConstants.AUTH_SERVICE_NAME, ssoAuthSession);
    revisionNumber = scm.getRevisionNumber();
    if (debug.messageEnabled()) {
      debug.message("revision number = " + revisionNumber);
    }
    updateAuthServiceGlobals(scm);
    new AuthConfigMonitor(scm);
  }

  /**
   * Update the AuthService global and organization settings. most of the code is moved in from
   * AuthenticatorManager.java.
   *
   * @param scm <code>ServiceSchemaManager</code> to be used for update
   * @throws SMSException if it fails to update auth service
   * @throws Exception
   */
  synchronized void updateAuthServiceGlobals(ServiceSchemaManager scm)
      throws SMSException, Exception {

    ServiceSchema schema = scm.getOrganizationSchema();
    Map attrs = schema.getAttributeDefaults();

    // get Global type attributes for iPlanetAMAuthService
    schema = scm.getGlobalSchema();

    attrs.putAll(schema.getAttributeDefaults());
    if (debug.messageEnabled()) {
      debug.message("attrs : " + attrs);
    }

    defaultAuthLocale = CollectionHelper.getMapAttr(attrs, ISAuthConstants.AUTH_LOCALE_ATTR);
    adminAuthModule = CollectionHelper.getMapAttr(attrs, ISAuthConstants.ADMIN_AUTH_MODULE);
    defaultAuthLevel =
        CollectionHelper.getMapAttr(attrs, ISAuthConstants.DEFAULT_AUTH_LEVEL, DEFAULT_AUTH_LEVEL);

    Set s = (Set) attrs.get(ISAuthConstants.AUTHENTICATORS);
    Iterator iter = s.iterator();
    while (iter.hasNext()) {
      String name = (String) iter.next();
      int dot = name.lastIndexOf('.');
      if (dot > -1) {
        String tmp = name.substring(dot + 1, name.length());
        authMethods.put(tmp, name);
      } else {
        authMethods.put(name, name);
      }
    }
    if (debug.messageEnabled()) {
      debug.message("AM.update authMethods = " + authMethods.toString());
    }

    defaultSuccessURLSet = (Set) attrs.get(ISAuthConstants.LOGIN_SUCCESS_URL);
    defaultFailureURLSet = (Set) attrs.get(ISAuthConstants.LOGIN_FAILURE_URL);

    if (debug.messageEnabled()) {
      debug.message("Default Success URL Set = " + defaultSuccessURLSet);
      debug.message("Default Failure URL Set = " + defaultFailureURLSet);
    }

    Integer sleepTime =
        new Integer(CollectionHelper.getMapAttr(attrs, ISAuthConstants.SLEEP_INTERVAL));
    defaultSleepTime = sleepTime.longValue();
  }

  /**
   * Initialize the AuthConfiguration global attributes.
   *
   * @throws SMSException if it fails to get auth service for name
   * @throws SSOException if admin <code>SSOToken</code> is not valid
   * @throws Exception
   */
  private void initAuthConfigGlobalSettings() throws SMSException, SSOException, Exception {

    ServiceSchemaManager scm =
        new ServiceSchemaManager(ISAuthConstants.AUTHCONFIG_SERVICE_NAME, ssoAuthSession);
    updateAuthConfigGlobals(scm);
    new AuthConfigMonitor(scm);
  }

  /**
   * Update the AuthConfiguration organization attributes.
   *
   * @param scm <code>ServiceSchemaManager</code> to be used for update
   * @throws SMSException if it fails to update auth service
   */
  synchronized void updateAuthConfigGlobals(ServiceSchemaManager scm) throws SMSException {

    ServiceSchema schema = scm.getOrganizationSchema();

    schema = schema.getSubSchema("Configurations");
    schema = schema.getSubSchema("NamedConfiguration");
    Map attrs = schema.getAttributeDefaults();

    if (attrs != null) {
      defaultServiceSuccessURLSet = (Set) attrs.get(ISAuthConstants.LOGIN_SUCCESS_URL);
      defaultServiceFailureURLSet = (Set) attrs.get(ISAuthConstants.LOGIN_FAILURE_URL);
    }
    if (debug.messageEnabled()) {
      debug.message("Default Service Success URL Set = " + defaultServiceSuccessURLSet);
      debug.message("Default Service Failure URL Set = " + defaultServiceFailureURLSet);
    }
  }

  /**
   * Initialized platform service global attributes
   *
   * @throws SMSException if it fails to initialize platform service
   * @throws SSOException if admin <code>SSOToken</code> is not valid
   */
  private void initPlatformServiceGlobalSettings() throws SMSException, SSOException {
    ServiceSchemaManager scm =
        new ServiceSchemaManager(ISAuthConstants.PLATFORM_SERVICE_NAME, ssoAuthSession);
    updatePlatformServiceGlobals(scm);
    new AuthConfigMonitor(scm);
  }

  /**
   * Update the PlatformService global attributes.
   *
   * @param scm <code>ServiceSchemaManager</code> to be used for update
   * @throws SMSException if it fails to initialize platform service
   */
  synchronized void updatePlatformServiceGlobals(ServiceSchemaManager scm) throws SMSException {
    platformSchema = scm.getGlobalSchema();
    Map attrs = platformSchema.getAttributeDefaults();

    platformLocale = CollectionHelper.getMapAttr(attrs, ISAuthConstants.PLATFORM_LOCALE_ATTR);

    if (debug.messageEnabled()) {
      debug.message("PlatformLocale = " + platformLocale);
    }
  }

  /**
   * Initialize iPlanetAMSessionService Dynamic attributes
   *
   * @throws SMSException if it fails to initialize session service
   * @throws SSOException if admin <code>SSOToken</code> is not valid
   */
  private void initSessionServiceDynamicSettings() throws SMSException, SSOException {
    ServiceSchemaManager scm =
        new ServiceSchemaManager(ISAuthConstants.SESSION_SERVICE_NAME, ssoAuthSession);
    updateSessionServiceDynamics(scm);
    new AuthConfigMonitor(scm);
  }

  /**
   * Update the SessionService dynamic attributes.
   *
   * @param scm <code>ServiceSchemaManager</code> to be used for update
   * @throws SMSException if it fails to update session service
   */
  synchronized void updateSessionServiceDynamics(ServiceSchemaManager scm) throws SMSException {

    sessionSchema = scm.getDynamicSchema();
    if (debug.messageEnabled()) {
      Map attrs = sessionSchema.getAttributeDefaults();
      String defaultMaxSessionTime =
          CollectionHelper.getMapAttr(attrs, ISAuthConstants.MAX_SESSION_TIME, "120");
      String defaultMaxIdleTime =
          CollectionHelper.getMapAttr(attrs, ISAuthConstants.SESS_MAX_IDLE_TIME, "30");
      String defaultMaxCachingTime =
          CollectionHelper.getMapAttr(attrs, ISAuthConstants.SESS_MAX_CACHING_TIME, "3");
      debug.message(
          "AuthD.defaultMaxSessionTime="
              + defaultMaxSessionTime
              + "\nAuthD.defaultMaxIdleTime="
              + defaultMaxIdleTime
              + "\nAuthD.defaultMaxCachingTime="
              + defaultMaxCachingTime);
    }
  }

  /**
   * Return max session time
   *
   * @return max session time
   */
  String getDefaultMaxSessionTime() {
    return CollectionHelper.getMapAttr(
        sessionSchema.getAttributeDefaults(), ISAuthConstants.MAX_SESSION_TIME, "120");
  }

  /**
   * Return max session idle time
   *
   * @return max session idle time
   */
  String getDefaultMaxIdleTime() {
    return CollectionHelper.getMapAttr(
        sessionSchema.getAttributeDefaults(), ISAuthConstants.SESS_MAX_IDLE_TIME, "30");
  }

  /**
   * Return max session caching time
   *
   * @return max session caching time
   */
  String getDefaultMaxCachingTime() {
    return CollectionHelper.getMapAttr(
        sessionSchema.getAttributeDefaults(), ISAuthConstants.SESS_MAX_CACHING_TIME, "3");
  }

  /**
   * Returns attribute map of the specified service in the specified organization.
   *
   * @param orgDN Organization DN in which the service exists.
   * @param serviceName Service name of which the attributes are retrieved.
   * @return Map containing the attributes of the service.
   */
  public Map getOrgServiceAttributes(String orgDN, String serviceName) {
    Map map = Collections.EMPTY_MAP;
    try {
      AMIdentityRepository idRepo = getAMIdentityRepository(orgDN);
      AMIdentity realmIdentity = idRepo.getRealmIdentity();
      Set set = realmIdentity.getAssignedServices();
      if (set.contains(serviceName)) {
        map = realmIdentity.getServiceAttributes(serviceName);
      }
    } catch (Exception e) {
      if (debug.messageEnabled()) {
        debug.message(
            "Exception in getting service attributes for " + serviceName + " in org " + orgDN);
      }
    }
    return map;
  }

  /**
   * Returns Authenticator singleton instance.
   *
   * @return Authenticator singleton instance.
   */
  public static AuthD getAuth() {
    if (authInstance == null) {
      synchronized (AuthD.class) {
        if (authInstance == null) {
          authInstance = new AuthD();
          if (authInitFailed) {
            authInstance = null;
          }
        }
      }
    }
    return authInstance;
  }

  /**
   * Destroy sessionfor given <code>SessionID</code>
   *
   * @param sid <code>SessionID</code> to be destroyed
   */
  public void destroySession(SessionID sid) {
    getSS().destroyInternalSession(sid);
  }

  /**
   * Logout sessionfor given <code>SessionID</code>
   *
   * @param sid <code>SessionID</code> to be logout
   */
  public void logoutSession(SessionID sid) {
    getSS().logoutInternalSession(sid);
  }

  /**
   * Creates a new session.
   *
   * @param domain Domain Name.
   * @param httpSession HTTP Session.
   * @return new <code>InternalSession</code>
   */
  public static InternalSession newSession(String domain, HttpSession httpSession) {
    InternalSession is = null;
    try {
      is = getSS().newInternalSession(domain, httpSession);
    } catch (Exception ex) {
      ex.printStackTrace();
      debug.error("Error creating session: ", ex);
    }
    return is;
  }

  /**
   * Returns the session associated with a session ID.
   *
   * @param sessId Session ID.
   * @return the <code>InternalSession</code> associated with a session ID.
   */
  public static InternalSession getSession(String sessId) {
    if (debug.messageEnabled()) {
      debug.message("getSession for " + sessId);
    }
    InternalSession is = null;
    if (sessId != null) {
      SessionID sid = new SessionID(sessId);
      is = getSession(sid);
    }
    if (is == null) {
      debug.message("getSession returned null");
    }
    return is;
  }

  /**
   * Returns the session associated with a session ID.
   *
   * @param sid Session ID.
   * @return the <code>InternalSession</code> associated with a session ID.
   */
  public static InternalSession getSession(SessionID sid) {
    InternalSession is = null;
    if (sid != null) {
      is = getSS().getInternalSession(sid);
    }
    return is;
  }

  /**
   * Returns the session associated with an HTTP Servlet Request.
   *
   * @param req HTTP Servlet Request.
   * @return the <code>InternalSession</code> associated with anHTTP Servlet Request.
   */
  public InternalSession getSession(HttpServletRequest req) {
    SessionID sid = new SessionID(req);
    return getSession(sid);
  }

  ////////////////////////////////////////////////////////////////
  //  AuthD utilities
  ////////////////////////////////////////////////////////////////

  /**
   * Returns an Authenticator for a specific module name.
   *
   * @param moduleName Module name example <code>LDAP</code>.
   * @return Authenticator for a specific module name.
   */
  public String getAuthenticatorForName(String moduleName) {
    return (String) authMethods.get(moduleName);
  }

  /**
   * Returns <code>true</code> if the specified module is one of the authenticators.
   *
   * @param module Module name example <code>LDAP</code>.
   * @return <code>true</code> if the specified module is one of the authenticators.
   */
  public boolean containsAuthenticator(String module) {
    return authMethods.containsKey(module);
  }

  /**
   * Return configured Authenticators
   *
   * @return list of configured Authenticators
   */
  public Iterator getAuthenticators() {
    return authMethods.keySet().iterator();
  }

  /**
   * Return number configured Authenticators
   *
   * @return number configured Authenticators
   */
  public int getAuthenticatorCount() {
    return authMethods.size();
  }

  /**
   * Return configured PlatformCharset
   *
   * @return configured PlatformCharset
   */
  public String getPlatformCharset() {
    return platformCharset;
  }

  /**
   * Return configured PlatformLocale
   *
   * @return configured PlatformLocale
   */
  public String getPlatformLocale() {
    return platformLocale;
  }

  /**
   * Return configured <code>Locale</code> for auth service
   *
   * @return configured <code>Locale</code> for auth service
   */
  public String getCoreAuthLocaleFromAuthService() {
    /* Method used by LoginState to find out core
     * auth locale is defined or not
     */
    return defaultAuthLocale;
  }

  /**
   * Return default <code>Locale</code> for auth service
   *
   * @return default <code>Locale</code> for auth service
   */
  public String getDefaultAuthLocale() {
    /* Since this method returned a fallback locale "en_US"
     * and is a public method,
     * It is configured to return en_US in case defaultAuthLocale == null
     */
    if (defaultAuthLocale == null || defaultAuthLocale.length() == 0) return "en_US";
    return defaultAuthLocale;
  }
  /** Log Logout status */
  public void logLogout(SSOToken ssot) {
    try {
      String logLogout = bundle.getString("logout");
      List dataList = new ArrayList();
      dataList.add(logLogout);
      StringBuilder messageId = new StringBuilder();
      messageId.append("LOGOUT");
      String indexType = ssot.getProperty(ISAuthConstants.INDEX_TYPE);
      if (indexType != null) {
        messageId.append("_").append(indexType.toString().toUpperCase());
        dataList.add(indexType.toString());
        if (indexType.equals(AuthContext.IndexType.USER.toString())) {
          dataList.add(ssot.getProperty(ISAuthConstants.PRINCIPAL));
        } else if (indexType.equals(AuthContext.IndexType.ROLE.toString())) {
          dataList.add(ssot.getProperty(ISAuthConstants.ROLE));
        } else if (indexType.equals(AuthContext.IndexType.SERVICE.toString())) {
          dataList.add(ssot.getProperty(ISAuthConstants.SERVICE));
        } else if (indexType.equals(AuthContext.IndexType.LEVEL.toString())) {
          dataList.add(ssot.getProperty(ISAuthConstants.AUTH_LEVEL));
        } else if (indexType.equals(AuthContext.IndexType.MODULE_INSTANCE.toString())) {
          dataList.add(ssot.getProperty(ISAuthConstants.AUTH_TYPE));
        }
      }

      Hashtable props = new Hashtable();
      String client = ssot.getProperty(ISAuthConstants.HOST);
      if (client != null) {
        props.put(LogConstants.IP_ADDR, client);
      }
      String userDN = ssot.getProperty(ISAuthConstants.PRINCIPAL);
      if (userDN != null) {
        props.put(LogConstants.LOGIN_ID, userDN);
      }
      String orgDN = ssot.getProperty(ISAuthConstants.ORGANIZATION);
      if (orgDN != null) {
        props.put(LogConstants.DOMAIN, orgDN);
      }
      String authMethName = ssot.getProperty(ISAuthConstants.AUTH_TYPE);
      if (authMethName != null) {
        props.put(LogConstants.MODULE_NAME, authMethName);
      }
      String contextId = null;
      contextId = ssot.getProperty(Constants.AM_CTX_ID);
      if (contextId != null) {
        props.put(LogConstants.CONTEXT_ID, contextId);
      }
      props.put(LogConstants.LOGIN_ID_SID, ssot.getTokenID().toString());

      String[] data = (String[]) dataList.toArray(new String[0]);
      this.logIt(data, this.LOG_ACCESS, messageId.toString(), props);
    } catch (SSOException ssoExp) {
      debug.error("AuthD.logLogout: SSO Error", ssoExp);
    } catch (Exception e) {
      debug.error("AuthD.logLogout: Error ", e);
    }
  }

  ////////////////////////////////////////////////////////////////
  //  Other utilities
  ////////////////////////////////////////////////////////////////
  com.sun.identity.log.Logger logger = null;

  /**
   * Writes a log record.
   *
   * @param s Array of data information for the log record.
   * @param type Type of log either <code>LOG_ERROR</code> or <code>LOG_ACCESS</code>.
   * @param messageName Message ID for the log record.
   * @param ssoProperties Single Sign On Properties to be written to the log record. If this is
   *     <code>null</code>, properties will be retrieved from administrator Single Sign On Token.
   */
  public void logIt(String[] s, int type, String messageName, Hashtable ssoProperties) {
    if (logStatus && (s != null)) {
      try {
        LogMessageProviderBase provider =
            (LogMessageProviderBase) MessageProviderFactory.getProvider("Authentication");

        com.sun.identity.log.LogRecord lr = null;

        SSOToken ssot = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
        if (ssoProperties == null) {
          lr = provider.createLogRecord(messageName, s, ssot);
        } else {
          lr = provider.createLogRecord(messageName, s, ssoProperties);
        }

        switch (type) {
          case LOG_ACCESS:
            logger = (com.sun.identity.log.Logger) Logger.getLogger("amAuthentication.access");
            logger.log(lr, ssot);
            break;
          case LOG_ERROR:
            logger = (com.sun.identity.log.Logger) Logger.getLogger("amAuthentication.error");
            logger.log(lr, ssot);
            break;
          default:
            logger = (com.sun.identity.log.Logger) Logger.getLogger("amAuthentication.access");
            logger.log(lr, ssot);
            break;
        }
      } catch (IOException ex) {
        ex.printStackTrace();
        debug.error("Logging exception : " + ex.getMessage());
      }
    }
  }

  /**
   * Returns connection for AM store. Only used for backward compatibilty support, for retrieving
   * user container DN and usernaming attr.
   *
   * @return connection for AM store
   */
  public AMStoreConnection getSDK() {
    if (dpStore == null) {
      try {
        dpStore = new AMStoreConnection(ssoAuthSession);
      } catch (SSOException e) {
        debug.warning("AuthD.getSDK", e);
      }
    }
    return dpStore;
  }

  void printProfileAttrs() {
    if (!debug.messageEnabled()) {
      return;
    }
    debug.message("Authd Profile Attributes");

    String adminAuthName = adminAuthModule;
    int index = adminAuthModule.lastIndexOf(".");
    if (index > 0) {
      adminAuthName = adminAuthModule.substring(index + 1);
    }
    if (debug.messageEnabled()) {
      debug.message(
          "adminAuthModule->"
              + adminAuthModule
              + "\nadminAuthName->"
              + adminAuthName
              + "\ndefaultOrg->"
              + defaultOrg
              + "\nlocale->"
              + platformLocale
              + "\ncharset>"
              + platformCharset);
    }
  }

  static SessionService getSS() {
    SessionService ss = SessionService.getSessionService();
    if (ss == null) {
      debug.error("AuthD failed to get session service instance");
    }
    return ss;
  }

  /**
   * Return default organization
   *
   * @return default organization
   */
  public String getDefaultOrg() {
    return defaultOrg;
  }

  /**
   * Return current session for auth
   *
   * @return current session for auth
   */
  public Session getAuthSession() {
    return authSession;
  }

  /**
   * Return current sso session for auth
   *
   * @return current sso session for auth
   */
  public SSOToken getSSOAuthSession() {
    return ssoAuthSession;
  }

  private void initAuthSessions() throws SSOException, SessionException {
    if (authSession == null) {
      authSession = getSS().getAuthenticationSession(defaultOrg, null);
      if (authSession == null) {
        debug.error("AuthD failed to get auth session");
        throw new SessionException(BUNDLE_NAME, "gettingSessionFailed", null);
      }

      String clientID = authSession.getClientID();
      authSession.setProperty("Principal", clientID);
      authSession.setProperty("Organization", defaultOrg);
      authSession.setProperty("Host", authSession.getID().getSessionServer());
      DN dn = new DN(clientID);
      if (dn.isDN()) {
        String[] tokens = dn.explodeDN(true);
        String id = "id=" + tokens[0] + ",ou=user," + ServiceManager.getBaseDN();
        authSession.setProperty(Constants.UNIVERSAL_IDENTIFIER, id);
      }
      SSOTokenManager ssoManager = SSOTokenManager.getInstance();
      ssoAuthSession = ssoManager.createSSOToken(authSession.getID().toString());
    }
  }

  /**
   * get inetDomainStatus attribute for the org
   *
   * @param orgName org name to check inetDomainStatus
   * @return true if org is active
   * @throws IdRepoException if can not can any information for org
   * @throws SSOException if can not use <code>SSOToken</code> for admin
   */
  boolean getInetDomainStatus(String orgName) throws IdRepoException, SSOException {
    return IdUtils.isOrganizationActive(ssoAuthSession, orgName);
  }

  /**
   * Returns <code>true</code> if distinguished user name is a super administrator DN.
   *
   * @param dn Distinguished name of user.
   * @return <code>true</code> if user is super administrator.
   */
  public boolean isSuperAdmin(String dn) {
    boolean isAdmin = false;
    String nDN = DNUtils.normalizeDN(dn);
    if ((nDN != null) && (superAdmin != null || specialUser != null)) {
      if (debug.messageEnabled()) {
        debug.message("passed dn is :" + dn);
      }
      if (superAdmin != null) {
        if (debug.messageEnabled()) {
          debug.message("normalized super dn is :" + superAdmin);
        }
        isAdmin = nDN.equals(superAdmin);
      }
      if (!isAdmin) {
        isAdmin = isSpecialUser(nDN);
      }
    }
    if (debug.messageEnabled()) {
      debug.message("is Super Admin :" + isAdmin);
    }
    return isAdmin;
  }

  /**
   * Returns <code>true</code> if and only if the user name belongs to a super user
   *
   * @param dn DN of the user
   * @return <code>true</code> if the user is an admin user.
   */
  public boolean isSuperUser(String dn) {
    if (superUserIdentity == null) {
      superUserIdentity =
          new AMIdentity(
              AccessController.doPrivileged(AdminTokenAction.getInstance()),
              superAdmin,
              IdType.USER,
              "/",
              null);
    }
    return superUserIdentity.getUniversalId().equalsIgnoreCase(dn);
  }

  /**
   * Returns <code>true</code> if distinguished user name is a special user DN.
   *
   * @param dn Distinguished name of user.
   * @return <code>true</code> if user is a special user.
   */
  public boolean isSpecialUser(String dn) {
    // dn in all the invocation is normalized.
    boolean isSpecialUser = false;
    String nDN = DNUtils.normalizeDN(dn);
    if ((nDN != null) && (specialUser != null)) {
      StringTokenizer st = new StringTokenizer(specialUser, "|");
      while (st.hasMoreTokens()) {
        String specialAdminDN = (String) st.nextToken();
        if (specialAdminDN != null) {
          String normSpecialAdmin = DNUtils.normalizeDN(specialAdminDN);

          if (debug.messageEnabled()) {
            debug.message("normalized special dn is :" + normSpecialAdmin);
          }
          if (nDN.equals(normSpecialAdmin)) {
            isSpecialUser = true;
            break;
          }
        }
      }
    }
    if (debug.messageEnabled()) {
      debug.message("is Special User :"******"userOrg is : " + userOrg);
      debug.message("rootSuffix is : " + rootSuffix);
      debug.message("rootSuffixDN is : " + rootSuffixDN);
      debug.message("userOrgDN is : " + userOrgDN);
    }

    if ((userOrgDN.equals(rootSuffixDN)) || (userOrgDN.isDescendantOf(rootSuffixDN))) {
      orgDN = userOrgDN.toString();
    } else {
      orgDN =
          (new StringBuffer(50))
              .append(userOrgDN.toString())
              .append(",")
              .append(rootSuffixDN)
              .toString();
    }

    if (debug.messageEnabled()) {
      debug.message("Returning OrgDN is : " + orgDN);
    }
    return orgDN.toString();
  }

  /**
   * Returns the dynamic replacement of the URL from the Success or Failure URLs.
   *
   * @param URL
   * @param servletRequest
   * @return the dynamic replacement of the URL from the Success or Failure URLs.
   */
  public String processURL(String URL, HttpServletRequest servletRequest) {
    String url = URL;

    if (url != null) {
      url = processDynamicVariables(url, servletRequest);
    }
    if (debug.messageEnabled()) {
      debug.message("processURL : " + url);
    }
    return url;
  }

  /**
   * This function returns the dynamic replacement of the protocol from the Success or Failure urls
   *
   * @param rawURL Raw url with out real protocol
   * @param servletRequest Servlet request has real protocol value
   * @return the dynamic replacement of the protocol from the Success or Failure urls
   */
  private String processDynamicVariables(String rawURL, HttpServletRequest servletRequest) {
    if (rawURL.indexOf("%") != -1) {
      int index;
      StringBuilder sb = new StringBuilder(200);
      // protocol processing
      if ((index = rawURL.indexOf("%protocol")) != -1) {
        sb.append(rawURL.substring(0, index));
        if (isConsoleRemote) {
          sb.append(consoleProto);
        } else {
          String protocol = null;
          if (servletRequest != null) {
            protocol =
                RequestUtils.getRedirectProtocol(
                    servletRequest.getScheme(), servletRequest.getServerName());
          }
          if (protocol != null) {
            sb.append(protocol);
          } else {
            sb.append(consoleProto);
          }
        }
        sb.append(rawURL.substring(index + "%protocol".length()));
        rawURL = sb.toString();
      }
      if ((index = rawURL.indexOf("%host")) != -1) {
        int hostlen = "%host".length();
        sb.delete(0, 200);
        sb.append(rawURL.substring(0, index));
        if (isConsoleRemote) {
          sb.append(consoleHost);
        } else {
          String host = null;
          if (servletRequest != null) {
            host = servletRequest.getHeader("Host");
          }
          if (host != null) {
            sb.append(host);
            // This is to remove extra ":"
            hostlen = hostlen + 1;
          } else {
            sb.append(consoleHost);
          }
        }
        sb.append(rawURL.substring(index + hostlen));
        rawURL = sb.toString();
      }
      if ((index = rawURL.indexOf("%port")) != -1) {
        sb.delete(0, 200);
        sb.append(rawURL.substring(0, index));
        if (isConsoleRemote) {
          sb.append(consolePort);
        }
        sb.append(rawURL.substring(index + "%port".length()));
        rawURL = sb.toString();
      }
    }
    return rawURL;
  }

  /**
   * Sets the Servlet Context.
   *
   * @param servletContext Servlet Context to be set.
   */
  public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
    if (debug.messageEnabled()) {
      debug.message("Setting servletContext" + servletContext);
    }
  }

  /**
   * Returns the Servlet Context.
   *
   * @return Servlet Context.
   */
  public ServletContext getServletContext() {
    return servletContext;
  }

  /**
   * Returns the OpenSSO Identity Repository for an organization.
   *
   * @param orgDN name of the organization
   * @return OpenSSO Identity Repository.
   */
  public AMIdentityRepository getAMIdentityRepository(String orgDN) {
    AMIdentityRepository amIdentityRepository = null;
    try {
      if ((idRepoMap != null) && (!idRepoMap.isEmpty())) {
        amIdentityRepository = (AMIdentityRepository) idRepoMap.get(orgDN);
      }
      if (amIdentityRepository == null) {
        amIdentityRepository = new AMIdentityRepository(ssoAuthSession, orgDN);
        synchronized (idRepoMap) {
          idRepoMap.put(orgDN, amIdentityRepository);
        }
      }
    } catch (Exception id) {
      if (debug.messageEnabled()) {
        debug.message("Error getAMIdentityRepository", id);
      }
    }
    return amIdentityRepository;
  }

  /**
   * Returns the Organization Configuration Manager for an organization.
   *
   * @param orgDN Name of the organization.
   * @return Organization Configuration Manager for an organization.
   */
  public OrganizationConfigManager getOrgConfigManager(String orgDN) {
    OrganizationConfigManager orgConfigMgr = null;
    try {
      if ((orgMap != null) && (!orgMap.isEmpty())) {
        orgConfigMgr = (OrganizationConfigManager) orgMap.get(orgDN);
      }
      synchronized (orgMap) {
        if (orgConfigMgr == null) {
          orgConfigMgr = new OrganizationConfigManager(ssoAuthSession, orgDN);
          orgMap.put(orgDN, orgConfigMgr);
        }
      }
    } catch (Exception id) {
      if (debug.messageEnabled()) {
        debug.message("Error getAMIdentityRepository", id);
      }
    }
    return orgConfigMgr;
  }

  /**
   * Returns the <code>AMIdentity</code> object for the given parameters. If there is no such
   * identity, or there is more then one matching identity, then an AuthException will be thrown.
   *
   * @param idType Identity Type.
   * @param idName Identity Name.
   * @param orgName organization name.
   * @return <code>AMIdentity</code> object.
   * @throws AuthException if there was no result, or if there was more results then one.
   */
  public AMIdentity getIdentity(IdType idType, String idName, String orgName) throws AuthException {
    if (debug.messageEnabled()) {
      debug.message("IdType is :" + idType);
      debug.message("IdName is :" + idName);
      debug.message("orgName is :" + orgName);
    }
    AMIdentity amIdentity = null;

    // Try getting the identity using IdUtils.getIdentity(...)
    try {
      if (debug.messageEnabled()) {
        debug.message("AuthD.getIdentity() from IdUtils Name: " + idName + " Org: " + orgName);
      }
      amIdentity = IdUtils.getIdentity(getSSOAuthSession(), idName, orgName);
      if ((amIdentity != null)
          && (amIdentity.isExists())
          && (amIdentity.getType().equals(idType))
          && (amIdentity.getAttributes() != null)) {
        if (debug.messageEnabled()) {
          debug.message(
              "AuthD.getIdentity obtained identity" + "using IdUtil.getIdentity: " + amIdentity);
        }
        return (amIdentity);
      }
    } catch (IdRepoException e) {
      // Ignore this exception and continue with search
      if (debug.messageEnabled()) {
        debug.message(
            "AuthD.getIdentity: Got IdRepoException while "
                + "getting Identity from IdUtils: "
                + e.getMessage());
      }
    } catch (SSOException ssoe) {
      // Ignore this exception and continue with search
      if (debug.messageEnabled()) {
        debug.message(
            "AuthD.getIdentity: Got SSOException while "
                + "getting Identity from IdUtils: "
                + ssoe.getMessage());
      }
    }

    // Obtain AMIdentity object by searching within IdRepo
    try {
      amIdentity = null;
      idName = DNUtils.DNtoName(idName);
      AMIdentityRepository amIdRepo = getAMIdentityRepository(orgName);
      IdSearchControl idsc = new IdSearchControl();
      idsc.setRecursive(true);
      idsc.setTimeOut(0);
      idsc.setMaxResults(0);
      idsc.setAllReturnAttributes(false);
      IdSearchResults searchResults = amIdRepo.searchIdentities(idType, idName, idsc);
      Set results = Collections.EMPTY_SET;
      if (searchResults != null) {
        results = searchResults.getSearchResults();
      }

      if ((results != null) && (results.size() > 1)) {
        // multiple user match found, throw exception,
        // user need to login as super admin to fix it
        debug.error("getIdentity: Multiple matches found for " + "user '" + idName);
        throw new AuthException(AMAuthErrorCode.AUTH_ERROR, null);
      }

      Iterator users = results.iterator();
      if (users.hasNext()) {
        amIdentity = (AMIdentity) users.next();
      }
    } catch (SSOException sso) {
      if (debug.messageEnabled()) {
        debug.message("getIdentity error " + sso.getMessage());
      }
    } catch (IdRepoException ide) {
      if (debug.messageEnabled()) {
        debug.message("IdRepoException error " + ide.getMessage());
      }
    }
    if (amIdentity == null) {
      throw new AuthException(AMAuthErrorCode.AUTH_PROFILE_ERROR, null);
    }

    return amIdentity;
  }

  /**
   * Returns the Super Admin user Name.
   *
   * @return super admin user name.
   */
  public String getSuperUserName() {
    return superAdmin;
  }

  /**
   * Return <code>true</code> if it use http session
   *
   * @return <code>true</code> if it use http session
   */
  public static boolean isHttpSessionUsed() {
    return useHttpSession;
  }

  /**
   * Returns the authentication service or chain configured for the given organization.
   *
   * @param orgDN organization DN.
   * @return the authentication service or chain configured for the given organization.
   */
  public String getOrgConfiguredAuthenticationChain(String orgDN) {
    String orgAuthConfig = null;
    try {
      OrganizationConfigManager orgConfigMgr = getOrgConfigManager(orgDN);
      ServiceConfig svcConfig = orgConfigMgr.getServiceConfig(ISAuthConstants.AUTH_SERVICE_NAME);
      Map attrs = svcConfig.getAttributes();
      orgAuthConfig = Misc.getMapAttr(attrs, ISAuthConstants.AUTHCONFIG_ORG);
    } catch (Exception e) {
      debug.error("Error in getOrgConfiguredAuthenticationChain : ", e);
    }
    return orgAuthConfig;
  }

  /**
   * Returns a list of domains defined by iplanet-am-auth-valid-goto-domains in iPlanetAMAuthService
   * plus organization aliases
   *
   * @param orgDN organization DN.
   * @return a Set object containing a list of valid domains, null if
   *     iplanet-am-auth-valid-goto-domains is empty.
   */
  private Set getValidGotoUrlDomains(String orgDN) {
    Set validGotoUrlDomains = null;
    try {
      OrganizationConfigManager orgConfigMgr = getOrgConfigManager(orgDN);
      ServiceConfig svcConfig = orgConfigMgr.getServiceConfig(ISAuthConstants.AUTH_SERVICE_NAME);
      Map attrs = svcConfig.getAttributes();
      validGotoUrlDomains = (Set) attrs.get(ISAuthConstants.AUTH_GOTO_DOMAINS);
      if (debug.messageEnabled()) {
        debug.message("AuthD.getValidGotoUrlDomains(): " + validGotoUrlDomains);
      }
    } catch (Exception e) {
      debug.error("AuthD.getValidGotoUrlDomains():" + "Error in getValidGotoUrlDomains : ", e);
    }
    return validGotoUrlDomains;
  }

  /**
   * Checks whether an input URL is valid in an organization
   *
   * @param url a String representing a URL to be validated
   * @param orgDN organization DN.
   * @return true if input URL is valid, else false.
   */
  public boolean isGotoUrlValid(String url, String orgDN) {

    Set validGotoUrlDomains = null;
    if ((!orgValidDomains.isEmpty()) && (orgValidDomains.containsKey(orgDN))) {
      validGotoUrlDomains = (Set) orgValidDomains.get(orgDN);
    } else {
      validGotoUrlDomains = getValidGotoUrlDomains(orgDN);
      synchronized (orgValidDomains) {
        if (!orgValidDomains.containsKey(orgDN)) {
          orgValidDomains.put(orgDN, validGotoUrlDomains);
        }
      }
    }
    if (validGotoUrlDomains == null || validGotoUrlDomains.isEmpty()) {
      return true;
    }

    URLPatternMatcher patternMatcher = new URLPatternMatcher();
    try {
      return patternMatcher.match(url, new ArrayList(validGotoUrlDomains), true);
    } catch (MalformedURLException me) {
      debug.error("AuthD.isGotoUrlValid():" + "Error in validating GotoUrl: " + url, me);
      return false;
    }
  }
}
Beispiel #21
0
  /**
   * Determine the listener list based on the diable list property and SMS DataStore notification
   * property in Realm mode
   */
  private static void getListenerList() {
    String list = SystemProperties.get(EVENT_LISTENER_DISABLE_LIST, "");
    if (debugger.messageEnabled()) {
      debugger.message(
          "EventService.getListenerList(): " + EVENT_LISTENER_DISABLE_LIST + ": " + list);
    }

    boolean enableDataStoreNotification =
        Boolean.parseBoolean(SystemProperties.get(Constants.SMS_ENABLE_DB_NOTIFICATION));
    if (debugger.messageEnabled()) {
      debugger.message(
          "EventService.getListenerList(): "
              + "com.sun.identity.sm.enableDataStoreNotification: "
              + enableDataStoreNotification);
    }

    boolean configTime =
        Boolean.parseBoolean(SystemProperties.get(Constants.SYS_PROPERTY_INSTALL_TIME));
    if (debugger.messageEnabled()) {
      debugger.message(
          "EventService.getListenerList(): "
              + Constants.SYS_PROPERTY_INSTALL_TIME
              + ": "
              + configTime);
    }

    // Copy the default listeners
    String[] tmpListeners = new String[ALL_LISTENERS.length];
    System.arraycopy(ALL_LISTENERS, 0, tmpListeners, 0, ALL_LISTENERS.length);

    // Process the configured disabled list first
    boolean disableACI = false, disableUM = false, disableSM = false;
    if (list.length() != 0) {
      StringTokenizer st = new StringTokenizer(list, ",");
      String listener = "";
      while (st.hasMoreTokens()) {
        listener = st.nextToken().trim();
        if (listener.equalsIgnoreCase("aci")) {
          disableACI = true;
        } else if (listener.equalsIgnoreCase("um")) {
          disableUM = true;
        } else if (listener.equalsIgnoreCase("sm")) {
          disableSM = true;
        } else {
          debugger.error(
              "EventService.getListenerList() - " + "Invalid listener name: " + listener);
        }
      }
    }

    if (!disableUM || !disableACI) {
      // Check if AMSDK is configured
      boolean disableAMSDK = true;
      if (!configTime) {
        try {
          ServiceSchemaManager scm =
              new ServiceSchemaManager(getSSOToken(), IdConstants.REPO_SERVICE, "1.0");
          ServiceSchema idRepoSubSchema = scm.getOrganizationSchema();
          Set idRepoPlugins = idRepoSubSchema.getSubSchemaNames();
          if (idRepoPlugins.contains("amSDK")) {
            disableAMSDK = false;
          }
        } catch (SMSException ex) {
          if (debugger.warningEnabled()) {
            debugger.warning(
                "EventService.getListenerList() - " + "Unable to obtain idrepo service", ex);
          }
        } catch (SSOException ex) {
          // Should not happen, ignore the exception
        }
      }
      if (disableAMSDK) {
        disableUM = true;
        disableACI = true;
        if (debugger.messageEnabled()) {
          debugger.message(
              "EventService.getListener"
                  + "List(): AMSDK is not configured or config time. "
                  + "Disabling UM and ACI event listeners");
        }
      }
    }

    // Verify if SMSnotification should be enabled
    if (configTime || ServiceManager.isRealmEnabled()) {
      disableSM = !enableDataStoreNotification;
      if (debugger.messageEnabled()) {
        debugger.message(
            "EventService.getListenerList(): In realm "
                + "mode or config time, SMS listener is set to datastore "
                + "notification flag: "
                + enableDataStoreNotification);
      }
    }

    // Disable the selected listeners
    if (disableACI) {
      tmpListeners[0] = null;
    }
    if (disableUM) {
      tmpListeners[1] = null;
    }
    if (disableSM) {
      tmpListeners[2] = null;
    }
    listeners = tmpListeners;

    // if all disabled, signal to not start the thread
    if (disableACI && disableUM && disableSM) {
      if (debugger.messageEnabled()) {
        debugger.message(
            "EventService.getListenerList() - "
                + "all listeners are disabled, EventService won't start");
      }
      _allDisabled = true;
    } else {
      _allDisabled = false;
    }
  }
Beispiel #22
0
  /**
   * Redirects the HTTP request to the Authentication module. It gets the authentication url from
   * <code>SystemProperties</code>.
   *
   * @param request an HttpServletRequest object that contains the request the client has made of
   *     the servlet.
   * @param response an HttpServletResponse object that contains the response the servlet sends to
   *     the client.
   * @exception IOException If an input or output exception occurs
   */
  private void redirectForAuthentication(HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    if (debug.messageEnabled()) {
      debug.message(
          "CDCClientServlet.redirectForAuthentication: " + "requestURL=" + request.getRequestURL());
    }
    StringBuffer redirectURL = new StringBuffer(100);
    StringBuffer gotoURL = new StringBuffer(100);

    // Check if user has authenticated to another OpenSSO
    // instance
    String authURL = null;
    Cookie authCookie = CookieUtils.getCookieFromReq(request, authURLCookieName);
    if (authCookie != null) {
      authURL = CookieUtils.getCookieValue(authCookie);
      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.redirectForAuthentication: "
                + "got an authenticated URL= "
                + authURL);
      }
    }
    try {
      if (authURL == null
          || authURL.length() == 0
          || !authURL.toLowerCase().startsWith("http")
          || policyAdviceList != null) {
        String finalURL = request.getParameter(GOTO_PARAMETER);

        if (finalURL == null || finalURL.equals("")) {
          finalURL = request.getParameter(TARGET_PARAMETER);
        }

        if (finalURL == null || finalURL.equals("")) {
          showError(response, "GOTO or TARGET parameter is missing" + " in the request");
          return;
        }

        gotoURL
            .append(deployDescriptor)
            .append(CDCURI)
            .append(QUESTION_MARK)
            .append(TARGET_PARAMETER)
            .append(EQUAL_TO)
            .append(URLEncDec.encode(finalURL))
            .append(AMPERSAND)
            .append(requestParams);

        // Construct the login URL
        String cdcurl = SystemProperties.get(Constants.CDCSERVLET_LOGIN_URL);
        if (cdcurl != null && cdcurl.length() > 0) {
          if (cdcurl.indexOf("?") == -1) {
            redirectURLStr = cdcurl + QUESTION_MARK;
          } else {
            redirectURLStr = cdcurl + AMPERSAND;
          }
        } else {
          redirectURLStr = AUTHURI + QUESTION_MARK;
        }
        if (debug.messageEnabled()) {
          debug.message("CDCClientServlet init redirect URL is" + "set to= " + redirectURLStr);
        }

        redirectURL.append(redirectURLStr);
        if (policyAdviceList != null) {
          redirectURL.append(policyAdviceList).append(AMPERSAND);
        }
        redirectURL
            .append(GOTO_PARAMETER)
            .append(EQUAL_TO)
            .append(URLEncDec.encode(gotoURL.toString()));

        // Check for policy advices
        if (policyAdviceList != null) {
          redirectURL.append(AMPERSAND).append(policyAdviceList);
        }
        if (debug.messageEnabled()) {
          debug.message(
              "CDCClientServlet.redirectForAuthentication"
                  + ":redirectURL before dispatching is="
                  + redirectURL);
        }
        RequestDispatcher dispatcher = request.getRequestDispatcher(redirectURL.toString());
        dispatcher.forward(request, response);
      } else {
        // Redirect the user to the authenticated URL
        redirectURL
            .append(authURL)
            .append(deployDescriptor)
            .append(CDCURI)
            .append(QUESTION_MARK)
            .append(request.getQueryString());
        // Reset the cookie value to null, to avoid continous loop
        // when a load balancer is used
        if (authCookie != null) {
          authCookie.setValue("");
          response.addCookie(authCookie);
        }
        response.sendRedirect(redirectURL.toString());
      }

      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.redirectForAuthentication:"
                + "Forwarding for authentication to= "
                + redirectURL);
      }
    } catch (IOException ex) {
      debug.error(
          "CDCClientServlet.redirectForAuthentication: Failed "
              + "in forwarding to Authentication service. IOException",
          ex);
      showError(response, "Could for forward to authentication service:" + ex.getMessage());
    } catch (ServletException se) {
      debug.error(
          "CDCClientServlet.redirectForAuthentication : Failed "
              + "in forwarding to Authentication service. ServletException",
          se);
      showError(response, "Could for forward to authentication service:" + se.getMessage());
    } catch (IllegalStateException ie) {
      debug.error(
          "CDCClientServlet.redirectForAuthentication : Failed "
              + "in forwarding to Authentication service. Illegal state",
          ie);
      showError(response, "Could for forward to authentication service:" + ie.getMessage());
    }
  }
Beispiel #23
0
 static {
   debug = com.sun.identity.shared.debug.Debug.getInstance("amXMLHandler");
   messageEnabled = debug.messageEnabled();
   serviceURI = SystemProperties.get(Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR) + "/authservice";
 }
Beispiel #24
0
/**
 * This class Implements utility methods for handling HTTP Session.
 *
 * <p>
 */
public class SessionUtils {

  /** The QUERY encoding scheme */
  public static final short QUERY = 0;

  /** The SLASH encoding scheme */
  public static final short SLASH = 1;

  /** The SEMICOLON encoding scheme */
  public static final short SEMICOLON = 2;

  static Debug debug = Debug.getInstance("amSessionUtils");

  /** Set of trusted Inetaddresses */
  private static Set trustedSources = null;

  /** The HTTPClient IPHeader */
  private static final String httpClientIPHeader =
      SystemProperties.get(Constants.HTTP_CLIENT_IP_HEADER, "proxy-ip");

  /** The SESSION_ENCRYPTION to check if this is encrypted session */
  private static final boolean SESSION_ENCRYPTION =
      Boolean.valueOf(SystemProperties.get(Constants.SESSION_REPOSITORY_ENCRYPTION, "false"))
          .booleanValue();

  /**
   * Returns a SessionID string based on a HttpServletRequest object or null if session id is not
   * present or there was an error.
   *
   * <p>
   *
   * @param request The HttpServletRequest object which contains the session string.
   * @return an encodeURL with sessionID or the url if session was not present or there was an
   *     error.
   */
  public static String getSessionId(HttpServletRequest request) {
    String sidString = (new SessionID(request)).toString();
    if (sidString.length() == 0) {
      sidString = null;
    }
    return sidString;
  }

  /**
   * Returns URL encoded with the cookie Value (SSOToken ID) if cookies are not support. Throws an
   * SSOException in case of an error.
   *
   * <p>The cookie Value is written in the URL based on the encodingScheme specified. The Cookie
   * Value could be written as path info separated by either a "/" OR ";" or as a query string.
   *
   * <p>If the encoding scheme is SLASH then the cookie value would be written in the URL as extra
   * path info in the following format:
   *
   * <pre>
   * protocol://server:port/servletpath/&lt;cookieName>=&lt;cookieValue>?
   *     queryString
   * </pre>
   *
   * <p>Note that this format works only if the path is a servlet, if a a jsp file is specified then
   * webcontainers return with "File Not found" error. To rewrite links which are JSP files with
   * cookie value use the SEMICOLON OR QUERY encoding scheme.
   *
   * <p>If the encoding scheme is SEMICOLON then the cookie value would be written in the URL as
   * extra path info in the following format:
   *
   * <pre>
   * protocol://server:port/path;&lt;cookieName=cookieValue>?queryString
   * </pre>
   *
   * Note that this is not supported in the servlet specification and some web containers do not
   * support this.
   *
   * <p>If the encoding scheme is QUERY then the cookie value would be written in the URL in the
   * following format:
   *
   * <pre>
   * protocol://server:port/path?&lt;cookieName>=&lt;cookieValue>
   * protocol://server:port/path?queryString&amp;
   *       &lt;cookieName>=&lt;cookieValue>
   * </pre>
   *
   * <p>This is the default and OpenSSO always encodes in this format unless otherwise specified. If
   * the URL passed in has query parameter then entity escaping of ampersand will be done before
   * appending the cookie if the escape is true.Only the ampersand before appending cookie parameter
   * will be entity escaped.
   *
   * <p>
   *
   * @param ssoToken Single Sign Token which contains the session string.
   * @param url the URL to be encoded
   * @param encodingScheme possible values are <code>QUERY</code>, <code>SLASH</code>, <code>
   *     SEMICOLON</code>.
   * @param escape <code>true</code> to escape ampersand when appending the Single Sign On Token ID
   *     to request query string.
   * @return encoded URL with cookie value (session ID) based on the encoding scheme.
   * @exception SSOException if URL cannot be encoded.
   */
  public static String encodeURL(
      SSOToken ssoToken, String url, short encodingScheme, boolean escape) throws SSOException {
    String encodedURL = url;
    try {
      SSOTokenID ssoTokenId = ssoToken.getTokenID();
      SessionID sessionID = new SessionID(ssoTokenId.toString());
      Session session = Session.getSession(sessionID);
      encodedURL = session.encodeURL(url, encodingScheme, escape);
    } catch (Exception e) {
      debug.message("Exception encoding URL ", e);
      throw new SSOException(e);
    }
    return encodedURL;
  }

  /**
   * Returns URL encoded with the cookie Value (SSOToken ID) if cookies are not supported.
   *
   * <p>This method assumes default encoding scheme which is QUERY. The cookie value would be
   * written in the URL in the following format:
   *
   * <pre>
   * protocol://server:port/path?&lt;cookieName>=&lt;cookieValue>
   * protocol://server:port/path?queryString&amp;
   *        &lt;cookieName>=&lt;cookieValue>
   * </pre>
   *
   * <p>This is the default and OpenSSO always encodes in this format unless otherwise specified. If
   * the URL passed in has query parameter then entity escaping of ampersand will be done before
   * appending the cookie if the escape is true.Only the ampersand before appending cookie parameter
   * will be entity escaped.
   *
   * <p>
   *
   * @param ssoToken Single Sign Token which contains the session string.
   * @param url the URL to be encoded.
   * @param escape <code>true</code> to escape ampersand when appending the Single Sign On Token ID
   *     to request query string.
   * @return URL encoded with cookie Value in the query string.
   * @exception SSOException if URL cannot be encoded.
   */
  public static String encodeURL(SSOToken ssoToken, String url, boolean escape)
      throws SSOException {
    String encodedURL = url;
    try {
      encodedURL = encodeURL(ssoToken, url, QUERY, escape);
    } catch (Exception e) {
      debug.message("Exception encoding url", e);
      throw new SSOException(e);
    }
    return encodedURL;
  }

  /**
   * Returns the remote IP address of the client
   *
   * @param servletRequest The HttpServletRequest object which contains the session string.
   * @return InetAddress the client address
   * @exception Exception
   */
  public static InetAddress getClientAddress(HttpServletRequest servletRequest) throws Exception {

    InetAddress remoteClient = InetAddress.getByName(servletRequest.getRemoteAddr());

    if (isTrustedSource(remoteClient)) {
      String proxyHeader = servletRequest.getHeader(httpClientIPHeader);
      if (proxyHeader != null) {
        remoteClient = InetAddress.getByName(proxyHeader);
      }
    }
    return remoteClient;
  }

  /* build the trust source set*/
  private static Set getTrustedSourceList() throws SessionException {
    Set result = new HashSet();
    try {
      String rawList = SystemProperties.get(Constants.TRUSTED_SOURCE_LIST);
      if (rawList != null) {
        StringTokenizer stk = new StringTokenizer(rawList, ",");
        while (stk.hasMoreTokens()) {
          result.add(InetAddress.getByName(stk.nextToken()));
        }
      } else {
        // use platform server list as a default fallback
        Vector psl = WebtopNaming.getPlatformServerList();
        if (psl == null) {
          throw new SessionException(SessionBundle.rbName, "emptyTrustedSourceList", null);
        }
        for (Enumeration e = psl.elements(); e.hasMoreElements(); ) {
          try {
            URL url = new URL((String) e.nextElement());
            result.add(InetAddress.getByName(url.getHost()));
          } catch (Exception ex) {
            debug.error("SessionUtils.getTrustedSourceList : " + "Validating Host exception", ex);
          }
        }
      }
    } catch (Exception e) {
      throw new SessionException(e);
    }
    return result;
  }

  /**
   * Returns the remote IP address of the client is a trusted source
   *
   * @param source the InetAddress of the remote client
   * @return a <code>true </code> if is a trusted source.<code>false> otherwise
   * @exception Exception
   */
  public static boolean isTrustedSource(InetAddress source) throws SessionException {
    if (trustedSources == null) {
      trustedSources = getTrustedSourceList();
    }
    return trustedSources.contains(source);
  }

  /**
   * Helper method to serialize and encrypt objects saved in the repository
   *
   * @param obj object to be serialized and encrypted
   * @return encrypted byte array containing serialized objects
   * @throws Exception if anything goes wrong
   */
  public static byte[] encode(Object obj) throws Exception {
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
    ObjectOutputStream objOutStream = new ObjectOutputStream(byteOut);

    // convert object to byte using streams
    objOutStream.writeObject(obj);
    objOutStream.close();

    final byte[] blob = byteOut.toByteArray();

    if (SESSION_ENCRYPTION) {
      return (byte[])
          AccessController.doPrivileged(
              new PrivilegedExceptionAction() {
                public Object run() throws Exception {
                  return Crypt.getEncryptor().encrypt(blob);
                }
              });
    }
    return blob;
  }

  /**
   * Deserializes and decrypts objects retrieved from the repository.
   *
   * @param blob Byte array containing serialized and encrypted object value.
   * @return retrieved object.
   * @throws Exception if anything goes wrong.
   */
  public static Object decode(final byte blob[]) throws Exception {
    byte[] decryptedBlob;
    if (SESSION_ENCRYPTION) {
      decryptedBlob =
          (byte[])
              AccessController.doPrivileged(
                  new PrivilegedExceptionAction() {
                    public Object run() throws Exception {
                      return Crypt.getEncryptor().decrypt(blob);
                    }
                  });
    } else {
      decryptedBlob = blob;
    }
    ByteArrayInputStream byteIn = new ByteArrayInputStream(decryptedBlob);
    ObjectInputStream objInStream = new ObjectInputStream(byteIn);
    return objInStream.readObject();
  }

  /**
   * Helper method to get the encrypted session storage key
   *
   * @param sessionID SessionID
   * @return encrypted session storage key
   * @throws Exception if anything goes wrong
   */
  public static String getEncryptedStorageKey(SessionID sessionID) throws Exception {

    String sKey = sessionID.getExtension(SessionID.STORAGE_KEY);
    if (SESSION_ENCRYPTION) {
      String strEncrypted =
          (String)
              AccessController.doPrivileged(
                  new EncodeAction(sKey, Crypt.getHardcodedKeyEncryptor()));
      return strEncrypted;
    }
    return sKey;
  }

  /**
   * Helper method to get admin token. This is not amadmin user but the user configured in
   * serverconfig.xml as super user.
   *
   * @return SSOToken of super admin.
   */
  public static SSOToken getAdminToken() throws SSOException {
    SSOToken adminToken = (SSOToken) AccessController.doPrivileged(AdminTokenAction.getInstance());
    if (adminToken == null) {
      I18n i18n = I18n.getInstance(IUMSConstants.UMS_PKG);
      String rbName = i18n.getResBundleName();
      throw new SSOException(rbName, IUMSConstants.NULL_TOKEN, null);
    }
    return (adminToken);
  }

  /**
   * Helper method to compare if the user token passed is same as admin token. It does not check if
   * user token or admin token is valid.
   *
   * @param admToken Admin Single Sign-On token.
   * @param usrToken User Single Sign-On token to compare against admin Single Sign-On token.
   * @return <code>true</code> if they both are same.
   */
  public static boolean isAdmin(SSOToken admToken, SSOToken usrToken) {
    if (usrToken == null) {
      debug.error("SessionUtils.isAdmin(): user token is null");
      return false;
    }

    if (admToken == null) {
      debug.error("SessionUtils.isAdmin(): admin token is null");
      return false;
    }

    boolean result = false;

    String usrName = null;
    String admName = null;

    try {
      usrName = usrToken.getPrincipal().getName();
    } catch (SSOException ssoEx) {
      debug.error("SessionUtils.isAdmin(): user token fails" + "to get principal");
      return false;
    }

    try {
      admName = admToken.getPrincipal().getName();
    } catch (SSOException ssoEx) {
      debug.error("SessionUtils.isAdmin(): admin token fails " + "to get principal");
      return false;
    }

    if (usrName.equalsIgnoreCase(admName)) {
      result = true;
    }

    if (debug.messageEnabled()) {
      debug.message(
          "SessionUtils.isAdmin(): returns "
              + result
              + " for user principal: "
              + usrName
              + " against admin principal: "
              + admName);
    }

    return result;
  }

  /**
   * Helper method to check if client has taken permission to set value to it. If
   *
   * @param clientToken Token of the client setting protected property.
   * @param key Property key
   * @param value Property value.
   * @throws SessionException if the key is protected property.
   */
  public static void checkPermissionToSetProperty(SSOToken clientToken, String key, String value)
      throws SessionException {
    if (InternalSession.isProtectedProperty(key)) {
      if (clientToken == null) {
        // Throw Ex. Client should identify itself.
        if (SessionService.sessionDebug.warningEnabled()) {
          SessionService.sessionDebug.warning(
              "SessionUtils.checkPermissionToSetProperty(): "
                  + "Attempt to set protected property without client "
                  + "token ["
                  + key
                  + "="
                  + value
                  + "]");
        }
        throw new SessionException(
            SessionBundle.getString("protectedPropertyNoClientToken") + " " + key);
      }

      SSOTokenManager ssoTokenManager = null;
      try {
        ssoTokenManager = SSOTokenManager.getInstance();
      } catch (SSOException ssoEx) {
        // Throw Ex. Not able to get SSOTokenManager instance.
        SessionService.sessionDebug.error(
            "SessionUtils.checkPermissionToSetProperty(): "
                + "Cannot get instance of SSOTokenManager.");
        throw new SessionException(
            SessionBundle.getString("protectedPropertyNoSSOTokenMgrInstance") + " " + key);
      }

      if (!ssoTokenManager.isValidToken(clientToken)) {
        // Throw Ex. Client should identify itself.
        if (SessionService.sessionDebug.warningEnabled()) {
          SessionService.sessionDebug.warning(
              "SessionUtils.checkPermissionToSetProperty(): "
                  + "Attempt to set protected property with invalid client"
                  + " token ["
                  + key
                  + "="
                  + value
                  + "]");
        }
        throw new SessionException(
            SessionBundle.getString("protectedPropertyInvalidClientToken") + " " + key);
      }

      SSOToken admToken = null;
      try {
        admToken = SessionUtils.getAdminToken();
      } catch (SSOException ssoEx) {
        // Throw Ex. Server not able to get Admin Token.
        SessionService.sessionDebug.error(
            "SessionUtils.checkPermissionToSetProperty(): "
                + "Cannot get Admin Token for validation to set protected "
                + "property ["
                + key
                + "="
                + value
                + "]");
        throw new SessionException(
            SessionBundle.getString("protectedPropertyNoAdminToken") + " " + key);
      }
      if (!SessionUtils.isAdmin(admToken, clientToken)) {
        // Throw Ex. Client not authorized to set this property.
        SessionService.sessionDebug.error(
            "SessionUtils.checkPermissionToSetProperty(): "
                + "Client does not have permission to set protected "
                + "property"
                + key
                + "="
                + value
                + "]");
        throw new SessionException(
            SessionBundle.getString("protectedPropertyNoPermission") + " " + key);
      }
    }
  }
}
Beispiel #25
0
/**
 * The <code>CDCClientServlet</code> is the heart of the Cross Domain Single Signon mechanism of
 * OpenAM in the DMZ along with the distributed auth. <br>
 * The following is the algorithm used by the program:
 *
 * <ol>
 *   <li>If request does not contain SSO related cookie or policy has generated some advices then
 *       redirect request to the distributed auth service.
 *   <li>If request contains SSO related cookie and no advices.
 *       <ul>
 *         <li>Tunnel the Request to OpenAM.
 *         <li>Send the received AuthNResponse as Form POST to the original request requested using
 *             the goto parameter in the query string.
 *       </ul>
 * </ol>
 */
public class CDCClientServlet extends HttpServlet {
  private static final ArrayList adviceParams = new ArrayList();
  private static final Set<String> INVALID_SET = new HashSet<String>();
  private static final Set<String> VALID_LOGIN_URIS = new HashSet<String>();
  private static final String LEFT_ANGLE = "<";
  private static final String RIGHT_ANGLE = ">";
  private static final String URLENC_RIGHT_ANGLE = "%3e";
  private static final String URLENC_LEFT_ANGLE = "%3c";
  private static final String URLENC_JAVASCRIPT = "javascript%3a";
  private static final String JAVASCRIPT = "javascript:";
  private static final String DELIM = ",";
  private static final String DEBUG_FILE_NAME = "amCDC";
  private static final char QUESTION_MARK = '?';
  private static final char AMPERSAND = '&';
  private static final char EQUAL_TO = '=';
  private static final char SEMI_COLON = ';';
  private static final char SPACE = ' ';
  private static final String GOTO_PARAMETER = "goto";
  private static final String TARGET_PARAMETER = "TARGET";
  private static final String CDCURI = "/cdcservlet";
  private static final String LOGIN_URI = "loginURI";
  private static String cdcAuthURI;
  private static final String AUTHURI = "/UI/Login";
  private static final String RESPONSE_HEADER_ALERT = "X-DSAME-Assertion-Form";
  private static final String RESPONSE_HEADER_ALERT_VALUE = "true";
  private static final String FORBIDDEN_STR_MATCH = "#403x";
  private static final String SERVER_ERROR_STR_MATCH = "#500x";
  static Debug debug = Debug.getInstance(DEBUG_FILE_NAME);

  static {
    initConfig();
  }

  private static SSOTokenManager tokenManager;
  private static String sessionServiceName = "iPlanetAMSessionService";
  private static String authURLCookieName;
  private static String authURLCookieDomain;
  private static String deployDescriptor;
  boolean serverMode =
      Boolean.valueOf(
              System.getProperty(
                  Constants.SERVER_MODE, SystemProperties.get(Constants.SERVER_MODE, "false")))
          .booleanValue();
  private static boolean cookieEncoding = SystemProperties.getAsBoolean(Constants.AM_COOKIE_ENCODE);

  /**
   * @param config the ServletConfig object that contains configutation information for this
   *     servlet.
   * @exception ServletException if an exception occurs that interrupts the servlet's normal
   *     operation.
   */
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    if (debug.messageEnabled()) {
      debug.message("CDCClientServlet.init:CDCClientServlet " + "Initializing...");
    }
    try {
      tokenManager = SSOTokenManager.getInstance();
    } catch (SSOException ssoe) {
      debug.error("CDCClientServlet.init:unable to get SSOTokenManager", ssoe);
    }
    authURLCookieName =
        SystemProperties.get(Constants.AUTH_UNIQUE_COOKIE_NAME, "sunIdentityServerAuthNServer");
    authURLCookieDomain = SystemProperties.get(Constants.AUTH_UNIQUE_COOKIE_DOMAIN, "");
    deployDescriptor =
        SystemProperties.get(Constants.AM_DISTAUTH_DEPLOYMENT_DESCRIPTOR, "/distauth");
  }

  /**
   * Handles the HTTP GET request.
   *
   * @param request an HttpServletRequest object that contains the request the client has made of
   *     the servlet.
   * @param response an HttpServletResponse object that contains the response the servlet sends to
   *     the client.
   * @exception ServletException if an input or output error is detected when the servlet handles
   *     the GET request
   * @exception IOException if the request for the GET could not be handled
   */
  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGetPost(request, response);
  }

  /**
   * Handles the HTTP POST request.
   *
   * @param request an HttpServletRequest object that contains the request the client has made of
   *     the servlet.
   * @param response an HttpServletResponse object that contains the response the servlet sends to
   *     the client.
   * @exception ServletException if an input or output error is detected when the servlet handles
   *     the GET request
   * @exception IOException if the request for the GET could not be handled
   */
  @Override
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGetPost(request, response);
  }

  /**
   * The method redirects the user to the authentication module if he is not authenticated; else
   * redirects him back to the original referrer.
   *
   * @param request an HttpServletRequest object that contains the request the client has made of
   *     the servlet.
   * @param response an HttpServletResponse object that contains the response the servlet sends to
   *     the client.
   * @exception ServletException if an input or output error is detected when the servlet handles
   *     the GET request
   * @exception IOException if the request for the GET could not be handled
   */
  private void doGetPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    if (debug.messageEnabled()) {
      debug.message(
          "CDCClientServlet.doGetPost:Query String received= " + request.getQueryString());
    }
    String gotoParameter = request.getParameter(GOTO_PARAMETER);
    String targetParameter = request.getParameter(TARGET_PARAMETER);
    if (targetParameter == null) {
      targetParameter = request.getParameter(TARGET_PARAMETER.toLowerCase());
    }
    // if check if goto ot target have invalid strings, to avoid
    // accepting invalid injected javascript.

    if ((gotoParameter != null) || (targetParameter != null)) {
      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet:doGetPost():validating goto: "
                + gotoParameter
                + " and target: "
                + targetParameter);
      }
      for (String invalidStr : INVALID_SET) {
        if (gotoParameter != null && gotoParameter.toLowerCase().contains(invalidStr)) {
          showError(response, SERVER_ERROR_STR_MATCH + "GOTO parameter has invalid characters");
          return;
        }
        if (targetParameter != null && targetParameter.toLowerCase().contains(invalidStr)) {
          showError(response, SERVER_ERROR_STR_MATCH + "TARGET parameter has invalid characters");
          return;
        }
      }
    }

    /* Steps to be done
     * 1. If no SSOToken or policy advice present , forward to
     *    authentication.
     * 2. If SSOToken is valid tunnel request to the backend AM's
     *    CDCServlet and Form POST the received response to the agent.
     */
    // Check for a valid SSOToken in the request. If SSOToken is not found
    // or if the token is invalid, redirect the user for authentication.
    // Also re-direct if there are policy advices in the query string
    SSOToken token = getSSOToken(request, response);
    // collect advices in parsedRequestParams[0] String and rest of params
    // other than original goto url in parsedRequestParams[1] String.
    String[] parsedRequestParams = parseRequestParams(request);

    if ((token == null) || (parsedRequestParams[0] != null)) {
      // Redirect to authentication
      redirectForAuthentication(request, response, parsedRequestParams[0], parsedRequestParams[1]);
    } else {

      // tunnel request to AM
      // send the request to the CDCServlet of AM where the session
      // was created.
      sendAuthnRequest(request, response, token);
    }
  }

  /**
   * This the main method of this servlet which takes in the request opens a URLConnection to the
   * CDCServlet endpoint in the OpenAM, and tunnels the request content to it. It parses the
   * Response received and if the HTTP_STATUS is "HTTP_OK" or "HTTP_MOVED_TEMP" POSTs the received
   * Liberty Authn Response to the goto URL specified in the original request.
   */
  private void sendAuthnRequest(
      HttpServletRequest request, HttpServletResponse response, SSOToken token)
      throws ServletException, IOException {
    SessionID sessid = new SessionID(request);
    URL CDCServletURL = null;
    URL sessionServiceURL = null;
    try {
      sessionServiceURL = Session.getSessionServiceURL(sessid);
    } catch (SessionException se) {
      debug.error(
          "CDCClientServlet.sendAuthnRequest: Cannot locate" + " OpenAM instance to forward to.",
          se);
      showError(response, "Cannot locate OpenAM instance to forward to");
    }
    if (sessionServiceURL == null) {
      showError(response, "Cannot locate OpenAM instance to forward to");
    }
    // replace "sessionservice" by cdcservlet in obtained URL
    // we use naming so that we get the URL of the exact server
    // where the session is located and get the right deployment
    // descriptor.
    String sessionServiceURLString = sessionServiceURL.toString();
    int serviceNameIndex =
        sessionServiceURLString.lastIndexOf(
            "/", sessionServiceURLString.length() - 2); // avoiding trailing "/"
    // if any
    StringBuilder buffer = new StringBuilder(150);
    buffer
        .append(sessionServiceURLString.substring(0, serviceNameIndex))
        .append(CDCURI)
        .append(QUESTION_MARK)
        .append(request.getQueryString()); // add query string to
    // CDCServletURL

    CDCServletURL = new URL(buffer.toString());

    // save the go to URL of the agent side to ultimately
    // POST to.
    try {
      HttpURLConnection connection = HttpURLConnectionManager.getConnection(CDCServletURL);
      connection.setRequestMethod("GET");
      connection.setRequestProperty("Content-Type", "text/html;charset=UTF-8");
      connection.setDoOutput(true);
      connection.setUseCaches(false);
      // replay cookies
      String strCookies = getCookiesFromRequest(request);
      if (strCookies != null) {
        if (debug.messageEnabled()) {
          debug.message("CDCClientServlet.sendAuthnRequest:Setting " + "cookies = " + strCookies);
        }
        connection.setRequestProperty("Cookie", strCookies);
      }
      // dont wish to follow redirect to agent, since
      // the response needs to go via the CDCClientServlet.
      HttpURLConnection.setFollowRedirects(false);

      // Receiving input from CDCServlet on the AM server instance
      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.sendAuthnRequest:Getting " + "response back from  " + CDCServletURL);
        debug.message(
            "CDCClientServlet.sendAuthnRequest:Response " + "Code " + connection.getResponseCode());
        debug.message(
            "CDCClientServlet.sendAuthnRequest:Response "
                + "Message= "
                + connection.getResponseMessage());
      }

      // Check response code
      if ((connection.getResponseCode() == HttpURLConnection.HTTP_OK)
          || (connection.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP)) {
        /**
         * Read the response back from CDCServlet, got a redirect since this response contains the
         * "LARES" ( Liberty authn response, which needs to be posted back to the dest url (agent).
         */
        StringBuilder inBuf = new StringBuilder();
        BufferedReader in =
            new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
        int len;
        char[] buf = new char[1024];
        while ((len = in.read(buf, 0, buf.length)) != -1) {
          inBuf.append(buf, 0, len);
        }
        String inString = inBuf.toString();
        if (debug.messageEnabled()) {
          debug.message(
              "CDCClientServlet.sendAuthnRequest:" + "Received response data = " + inString);
        }
        // put the received Liberty Auth Response
        // in the servlet's response.
        sendAuthnResponse(request, response, inString);
      } else {
        debug.error("CDCClientServlet.sendAuthnRequest: Response " + "code NOT OK/MOVED_TEMP ");
        showError(
            response,
            "ERROR: Received HTTP error code "
                + connection.getResponseCode()
                + " from "
                + CDCServletURL);
      }
    } catch (ConnectException ce) {
      // Debug the exception
      if (debug.warningEnabled()) {
        debug.warning(
            "CDCClientServlet.sendAuthnRequest: " + "Connection Exception to " + CDCServletURL, ce);
      }
      showError(
          response, "Could not connect to CDCServlet at " + CDCServletURL + ":" + ce.getMessage());
    }
  }

  // Get cookies string from HTTP request object
  private String getCookiesFromRequest(HttpServletRequest request) {
    Cookie cookies[] = CookieUtils.getCookieArrayFromReq(request);
    // above call would return pure sid in iPlanetDirectoryPro cookie
    // independent of container encoding
    StringBuilder cookieStr = null;
    String strCookies = null;
    if (cookies != null) {
      for (int nCookie = 0; nCookie < cookies.length; nCookie++) {
        String cookieName = cookies[nCookie].getName();
        String cookieVal = cookies[nCookie].getValue();
        if (cookieName.equals(CookieUtils.getAmCookieName()) && cookieEncoding) {
          cookieVal = URLEncDec.encode(cookieVal);
        }
        if (debug.messageEnabled()) {
          debug.message("CDCClientServlet.getCookiesFromRequest:" + "Cookie name = " + cookieName);
          debug.message("CDCClientServlet.getCookiesFromRequest:" + "Cookie val= " + cookieVal);
        }
        if (cookieStr == null) {
          cookieStr = new StringBuilder();
        } else {
          cookieStr.append(SEMI_COLON).append(SPACE);
        }
        cookieStr.append(cookieName).append(EQUAL_TO).append(cookieVal);
      }
    }
    if (cookieStr != null) {
      strCookies = cookieStr.toString();
    }
    return strCookies;
  }

  /**
   * Gathers the parameters in the request as a HTTP URL string. to form request parameters and
   * policy advice String array. It collects all the parameters from the original request except the
   * original goto url and any advice parameters. Note: All the paramters will be url decoded by
   * default., we should make sure that these values are encoded again
   *
   * @param request an HttpServletRequest object that contains the request the client has made of
   *     the servlet.
   * @return An String array, index 0 is policy advice, index 1 is rest of the request parameters
   */
  private String[] parseRequestParams(HttpServletRequest request) {
    StringBuilder adviceList = null;
    StringBuilder parameterString = new StringBuilder(100);
    for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
      String paramName = (String) e.nextElement();
      if (adviceParams.contains(paramName.toLowerCase())) {
        if (adviceList == null) {
          adviceList = new StringBuilder();
        } else {
          adviceList.append(AMPERSAND);
        }
        String[] values = request.getParameterValues(paramName);
        for (int i = 0; values != null && i < values.length; i++) {
          adviceList.append(paramName).append(EQUAL_TO).append(values[i]);
        }
      } else {
        if (!paramName.equals(GOTO_PARAMETER)) {
          String[] values = request.getParameterValues(paramName);
          for (int i = 0; values != null && i < values.length; i++) {
            parameterString
                .append(AMPERSAND)
                .append(paramName)
                .append(EQUAL_TO)
                .append(URLEncDec.encode(values[i]));
          }
        }
      }
    }
    if (debug.messageEnabled()) {
      debug.message("CDCClientServlet.parseRequestParams:" + "Advice List is = " + adviceList);
      debug.message(
          "CDCClientServlet.parseRequestParams:"
              + "Parameter String is = "
              + parameterString.toString());
    }

    String policyAdviceList;
    String requestParams;

    if (adviceList == null) {
      policyAdviceList = null;
    } else {
      policyAdviceList = adviceList.toString();
    }

    if (parameterString.length() > 0) {
      requestParams = (parameterString.deleteCharAt(0).toString());
    } else {
      requestParams = parameterString.toString();
    }

    return new String[] {policyAdviceList, requestParams};
  }

  /**
   * Redirects the HTTP request to the Authentication module. It gets the authentication url from
   * <code>SystemProperties</code>.
   *
   * @param request an HttpServletRequest object that contains the request the client has made of
   *     the servlet.
   * @param response an HttpServletResponse object that contains the response the servlet sends to
   *     the client.
   * @exception IOException If an input or output exception occurs
   */
  private void redirectForAuthentication(
      HttpServletRequest request,
      HttpServletResponse response,
      String policyAdviceList,
      String requestParams)
      throws IOException {
    if (debug.messageEnabled()) {
      debug.message(
          "CDCClientServlet.redirectForAuthentication: " + "requestURL=" + request.getRequestURL());
    }
    StringBuilder redirectURL = new StringBuilder(100);
    StringBuilder gotoURL = new StringBuilder(100);

    // Check if user has authenticated to another OpenAM
    // instance
    String authURL = null;
    Cookie authCookie = CookieUtils.getCookieFromReq(request, authURLCookieName);
    if (authCookie != null) {
      authURL = CookieUtils.getCookieValue(authCookie);
      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.redirectForAuthentication: "
                + "got an authenticated URL= "
                + authURL);
      }
    }
    try {
      if (authURL == null
          || authURL.length() == 0
          || !authURL.toLowerCase().startsWith("http")
          || policyAdviceList != null) {
        String finalURL = request.getParameter(GOTO_PARAMETER);

        if (finalURL == null || finalURL.equals("")) {
          finalURL = request.getParameter(TARGET_PARAMETER);
        }

        if (finalURL == null || finalURL.equals("")) {
          if (debug.messageEnabled()) {
            debug.message(
                "CDCClientServlet.redirectForAuthentication: "
                    + "goto or target parameter is missing in the request.");
          }

          showError(response, SERVER_ERROR_STR_MATCH);
          return;
        }

        gotoURL
            .append(deployDescriptor)
            .append(CDCURI)
            .append(QUESTION_MARK)
            .append(TARGET_PARAMETER)
            .append(EQUAL_TO)
            .append(URLEncDec.encode(finalURL))
            .append(AMPERSAND)
            .append(requestParams);

        // Construct the login URL
        String loginURI = request.getParameter(LOGIN_URI);
        String cdcUri;

        if (loginURI != null && !loginURI.isEmpty() && isValidCDCURI(loginURI)) {
          if (debug.messageEnabled()) {
            debug.message(
                "CDCClientServlet.redirectForAuthentication:found " + LOGIN_URI + "=" + loginURI);
          }

          cdcUri = loginURI;
        } else {
          cdcUri = cdcAuthURI;
        }

        if (debug.messageEnabled()) {
          debug.message(
              "CDCClientServlet.redirectForAuthentication: Login URI is set to = " + cdcUri);
        }

        if (cdcUri.indexOf(QUESTION_MARK) == -1) {
          redirectURL.append(cdcUri).append(QUESTION_MARK);
        } else {
          redirectURL.append(cdcUri).append(AMPERSAND);
        }

        if (policyAdviceList != null) {
          redirectURL.append(policyAdviceList).append(AMPERSAND);
        }
        redirectURL
            .append(GOTO_PARAMETER)
            .append(EQUAL_TO)
            .append(URLEncDec.encode(gotoURL.toString()));

        if (debug.messageEnabled()) {
          debug.message(
              "CDCClientServlet.redirectForAuthentication"
                  + ":redirectURL before dispatching is="
                  + redirectURL);
        }
        RequestDispatcher dispatcher = request.getRequestDispatcher(redirectURL.toString());
        dispatcher.forward(request, response);
      } else {
        // Redirect the user to the authenticated URL
        redirectURL
            .append(authURL)
            .append(deployDescriptor)
            .append(CDCURI)
            .append(QUESTION_MARK)
            .append(request.getQueryString());
        // Reset the cookie value to null, to avoid continuous loop
        // when a load balancer is used
        if (authCookie != null) {
          authCookie.setValue("");
          response.addCookie(authCookie);
        }
        response.sendRedirect(redirectURL.toString());
      }

      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.redirectForAuthentication:"
                + "Forwarding for authentication to= "
                + redirectURL);
      }
    } catch (IOException ex) {
      debug.error(
          "CDCClientServlet.redirectForAuthentication: Failed "
              + "in forwarding to Authentication service. IOException",
          ex);
      showError(response, "Could for forward to authentication service:" + ex.getMessage());
    } catch (ServletException se) {
      debug.error(
          "CDCClientServlet.redirectForAuthentication : Failed "
              + "in forwarding to Authentication service. ServletException",
          se);
      showError(response, "Could for forward to authentication service:" + se.getMessage());
    } catch (IllegalStateException ie) {
      debug.error(
          "CDCClientServlet.redirectForAuthentication : Failed "
              + "in forwarding to Authentication service. Illegal state",
          ie);
      showError(response, "Could for forward to authentication service:" + ie.getMessage());
    }
  }

  /**
   * Shows Application Error message to the user.
   *
   * @param response an HttpServletResponse object that contains the response the servlet sends to
   *     the client.
   * @param msg Message to be displayed.
   */
  private void showError(HttpServletResponse response, String msg) throws IOException {
    ServletOutputStream out = null;
    if (msg == null || msg.equals("") || msg.contains(SERVER_ERROR_STR_MATCH)) {
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

      return;
    }

    try {
      out = response.getOutputStream();
      out.println(msg);
      out.flush();
    } catch (IOException e) {
      debug.error("CDCClientServlet.showError::Could not show error " + "message to the user " + e);
    } finally {
      try {
        out.close();
      } catch (IOException ignore) {
      }
    }
  }

  /**
   * Returns the SSOToken of the user. If user has not authenticated re-directs the user to login
   * page
   */
  private SSOToken getSSOToken(HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    SSOToken token = null;
    try {
      /* SSOTokenManager.createSSOToken() throws an SSOException if the
       * token is not valid, so for a invalid token manager.isValidToken()
       * will never get executed for an invalid token.
       */
      if (((token = tokenManager.createSSOToken(request)) == null)
          || !tokenManager.isValidToken(token)) {
        if (debug.messageEnabled()) {
          debug.message(
              "CDCClientServlet.getSSOToken:SSOToken is "
                  + "either null or not valid: "
                  + token
                  + "\nRedirecting for authentication");
        }
        token = null;
      }
    } catch (com.iplanet.sso.SSOException e) {
      if (debug.messageEnabled()) {
        debug.message("CDCClientServlet.getSSOToken:SSOException " + "caught= " + e);
      }
      token = null;
    }
    return (token);
  }

  private void sendAuthnResponse(
      HttpServletRequest request, HttpServletResponse response, String authnResponse) {
    if (debug.messageEnabled()) {
      debug.message("CDCClientServlet.sendAuthnResponse: Called");
    }
    try {
      if (debug.messageEnabled()) {
        debug.message("CDCClientServlet.sendAuthnResponse: " + "AuthnResponse= " + authnResponse);
      }
      response.setContentType("text/html");
      response.setHeader("Pragma", "no-cache");
      response.setHeader(RESPONSE_HEADER_ALERT, RESPONSE_HEADER_ALERT_VALUE);

      if (authnResponse.contains(FORBIDDEN_STR_MATCH)) {
        if (debug.messageEnabled()) {
          debug.message(
              "CDCClientServlet.sendAuthnResponse: " + "AuthnResponse showing 403 error page");
        }

        response.sendError(HttpServletResponse.SC_FORBIDDEN);
        return;
      }

      if (authnResponse.contains(SERVER_ERROR_STR_MATCH)) {
        if (debug.messageEnabled()) {
          debug.error(
              "CDCClientServlet.sendAuthnResponse: " + "ERROR: An application error has occured.");
        }

        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        return;
      }

      PrintWriter out = response.getWriter();
      out.println(authnResponse);
      out.close();
      if (debug.messageEnabled()) {
        debug.message("CDCClientServlet.sendAuthnResponse: " + "AuthnResponse sent successfully");
      }
      return;
    } catch (IOException ioe) {
      debug.error("CDCClientServlet.sendAuthnResponse:" + ioe.getMessage());
    }
  }

  /**
   * Return <code>true</code> if the passed URI is valid compared to the valid set loaded during
   * initialization.
   *
   * @param cdcUri The URI to test.
   * @return <code>true</code> if the URI is considered valid, <code>false</code> otherwise.
   */
  private boolean isValidCDCURI(String cdcUri) {
    int questionMark = cdcUri.indexOf(QUESTION_MARK);

    // We are only interested in the URI part up to any parameters that may be included.
    if (questionMark != -1) {
      cdcUri = cdcUri.substring(0, questionMark);
    }

    // If there is not an exact match for the passed value then it cannot be considered valid
    boolean result = VALID_LOGIN_URIS.contains(cdcUri);

    if (debug.messageEnabled()) {
      debug.message(
          "CDCClientServlet.isValidCDCURI: checking if "
              + cdcUri
              + " is in validLoginURISet: "
              + VALID_LOGIN_URIS
              + " result:"
              + result);
    }

    return result;
  }

  private static void initConfig() {
    adviceParams.add("module");
    adviceParams.add("authlevel");
    adviceParams.add("role");
    adviceParams.add("service");
    adviceParams.add("user");
    adviceParams.add("realm");
    adviceParams.add("org");
    adviceParams.add("resource");
    adviceParams.add("sunamcompositeadvice");
    String invalidStrings = SystemPropertiesManager.get(Constants.INVALID_GOTO_STRINGS);
    if (INVALID_SET.isEmpty()) {
      debug.message("CDCClientServlet.initConfig: creating invalidSet");
      if (invalidStrings == null) {
        debug.message("CDCClientServlet.initConfig: invalidStrings is null");
        INVALID_SET.add(LEFT_ANGLE);
        INVALID_SET.add(RIGHT_ANGLE);
        INVALID_SET.add(URLENC_LEFT_ANGLE);
        INVALID_SET.add(URLENC_RIGHT_ANGLE);
        INVALID_SET.add(JAVASCRIPT);
        INVALID_SET.add(URLENC_JAVASCRIPT);
      } else {
        if (debug.messageEnabled()) {
          debug.message("CDCClientServlet.initConfig: invalidStrings is: " + invalidStrings);
        }
        StringTokenizer st = new StringTokenizer(invalidStrings, DELIM);
        while (st.hasMoreTokens()) {
          INVALID_SET.add(st.nextToken());
        }
      }
      debug.message("CDCClientServlet.initConfig: created invalidSet " + INVALID_SET);
    }

    String urlFromProps = SystemProperties.get(Constants.CDCSERVLET_LOGIN_URL);
    cdcAuthURI = (urlFromProps != null) ? urlFromProps : AUTHURI;

    String validLoginURIStrings = SystemPropertiesManager.get(Constants.VALID_LOGIN_URIS);
    debug.message("CDCClientServlet.initConfig: creating validLoginURISet");
    if (validLoginURIStrings == null) {
      debug.message(
          "CDCClientServlet.initConfig: validLoginURIStrings is null, creating default set");
      VALID_LOGIN_URIS.add(cdcAuthURI);
    } else {
      if (debug.messageEnabled()) {
        debug.message(
            "CDCClientServlet.initConfig: validLoginURIStrings is: " + validLoginURIStrings);
      }
      StringTokenizer st = new StringTokenizer(validLoginURIStrings, DELIM);
      while (st.hasMoreTokens()) {
        VALID_LOGIN_URIS.add(st.nextToken());
      }
    }
    debug.message("CDCClientServlet.initConfig: created validLoginURISet " + VALID_LOGIN_URIS);
  }
}
/**
 * A <code>ClusterStateService </code> class implements monitoring the state of server instances
 * that are participating in the cluster environment. It is used in making routing decisions in
 * "internal request routing" mode
 */
public class ClusterStateService extends GeneralTaskRunnable {

  // Inner Class definition of ServerInfo Object.
  // Contains information about each Server.
  private class ServerInfo implements Comparable {
    String id;

    String protocol;

    URL url;

    InetSocketAddress address;

    boolean isUp;

    boolean isLocal;

    public int compareTo(Object o) {
      return id.compareTo(((ServerInfo) o).id);
    }

    /**
     * toString Override.
     *
     * @return String representation of this Inner Object Class.
     */
    public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append("ServerInfo ID:[").append(this.id).append("], ");
      sb.append("Protocol:[").append(this.protocol).append("], ");
      sb.append("URL:[").append(((this.url == null) ? "null" : this.url.toString()));
      sb.append("], ");
      sb.append("Address:[");
      if (this.address == null) {
        sb.append("null], ");
      } else {
        sb.append(this.address.toString()).append("], Unresolved:[");
        sb.append(this.address.isUnresolved()).append("], ");
      }
      sb.append("Local:[").append(this.isLocal).append("], ");
      sb.append("Up:[").append(this.isUp).append("].\n");
      return sb.toString();
    }
  } // . End of Inner Class Definition.

  /** Service Globals */
  public static Debug sessionDebug = null;

  /** Servers in the cluster environment */
  private static Map<String, ServerInfo> servers = new HashMap<String, ServerInfo>();

  /** Servers are down in the cluster environment */
  private static Set<String> downServers = new HashSet<String>();

  /** Server Information */
  private static ServerInfo[] serverSelectionList = new ServerInfo[0];

  /** Last selected Server */
  private static int lastSelected = -1;

  /** individual server wait default time out 10 milliseconds */
  public static final int DEFAULT_TIMEOUT = 1000;

  private static String GET_REQUEST = "";
  private static final String EMPTY_STRING = "";
  private static final String SUCCESS_200 = "200";
  private static final String HTTP = "http";

  private static String hcPath = SystemProperties.get(Constants.URLCHECKER_TARGET_URL, null);

  private static boolean doRequest = true;
  private static final String doRequestFlag =
      SystemProperties.get(Constants.URLCHECKER_DOREQUEST, "false");

  private int timeout = DEFAULT_TIMEOUT; // in milliseconds

  /** default ServerInfo check time 10 milliseconds */
  public static final long DEFAULT_PERIOD = 1000;

  private static long period = DEFAULT_PERIOD; // in milliseconds

  // server instance id
  private static String localServerId = null;

  // SessionService
  private static volatile SessionService sessionService = null;

  // Static Initialization Stanza.
  static {
    sessionDebug = Debug.getInstance("amSession");

    if (doRequestFlag != null) {
      if (doRequestFlag.equals("false")) doRequest = false;
    }
    if (hcPath == null) {
      String deployuri =
          SystemProperties.get(Constants.AM_SERVICES_DEPLOYMENT_DESCRIPTOR, "/openam");
      hcPath = deployuri + "/namingservice";
      if (!hcPath.startsWith("/")) {
        hcPath += "/" + hcPath;
      }

      GET_REQUEST = "GET " + hcPath + " HTTP/1.0";
    }
  } // End of Static Initialization Stanza

  /**
   * Get Servers within Cluster
   *
   * @return Map<String, ServerInfo>
   */
  protected Map<String, ServerInfo> getServers() {
    return servers;
  }

  /**
   * Get Server IDs which are in a Down State.
   *
   * @return Set<String>
   */
  protected Set<String> getDownServers() {
    return downServers;
  }
  /**
   * Get the Server Selection List, common to all Servers in Cluster.
   *
   * @return ServerInfo[] Array of Servers in Selection list in proper order.
   */
  protected ServerInfo[] getServerSelectionList() {
    return serverSelectionList;
  }

  /**
   * Get our Local Server Id
   *
   * @return String of Local Server Id.
   */
  protected String getLocalServerId() {
    return localServerId;
  }

  /**
   * Is Specified ServerId our Local Server Id?
   *
   * @param serverId
   * @return boolean indicating true if specified server id is our local Server Id or false ir not.
   */
  protected boolean isLocalServerId(String serverId) {
    return ((serverId == null) || (!serverId.equalsIgnoreCase(this.localServerId))) ? false : true;
  }

  /**
   * Constructs an instance for the cluster service
   *
   * @param localServerId id of the server instance in which this ClusterStateService instance is
   *     running
   * @param timeout timeout for waiting on an individual server (millisec)
   * @param period checking cycle period (millisecs)
   * @param members map if server id - > url for all cluster members
   * @throws Exception
   */
  protected ClusterStateService(
      SessionService sessionService,
      String localServerId,
      int timeout,
      long period,
      Map<String, String> members)
      throws Exception {
    if ((localServerId == null) || (localServerId.isEmpty())) {
      String message =
          "ClusterStateService: Local Server Id argument is null, unable to instantiate Cluster State Service!";
      sessionDebug.error(message);
      throw new IllegalArgumentException(message);
    }
    // Ensure we Synchronize this Instantiation.
    synchronized (this) {
      this.sessionService = sessionService;
      this.localServerId = localServerId;
      this.timeout = timeout;
      this.period = period;
      serverSelectionList = new ServerInfo[members.size()];

      for (Map.Entry<String, String> entry : members.entrySet()) {
        ServerInfo info = new ServerInfo();
        info.id = entry.getKey();
        URL url = new URL(entry.getValue() + "/namingservice");
        info.url = url;
        info.protocol = url.getProtocol();
        info.address = new InetSocketAddress(url.getHost(), url.getPort());
        // Fix for Deadlock. If this is our server, set to true, else false.
        info.isUp = isLocalServerId(info.id);
        info.isLocal = info.isUp; // Set our Local Server Indicator, per above interrogation.

        // Check for Down Servers.
        if (!info.isUp) {
          downServers.add(info.id);
        }

        // Add Server to Server List.
        servers.put(info.id, info);
        // Associate to a Server Selection Bucket.
        serverSelectionList[getNextSelected()] = info;
        if (sessionDebug.messageEnabled()) {
          sessionDebug.error("Added Server to ClusterStateService: " + info.toString());
        }
      } // End of For Loop.

      // to ensure that ordering in different server instances is identical
      Arrays.sort(serverSelectionList);
      SystemTimer.getTimer().schedule(this, new Date((System.currentTimeMillis() / 1000) * 1000));
    } // End of Synchronized Block.
  }

  /**
   * Implements "wrap-around" lastSelected index advancement
   *
   * @return updated lastSelected index value
   */
  private int getNextSelected() {
    return lastSelected = (lastSelected + 1) % serverSelectionList.length;
  }

  /**
   * Returns currently known status of the server instance identified by serverId
   *
   * @param serverId server instance id
   * @return true if server is up, false otherwise
   */
  boolean isUp(String serverId) {
    if ((serverId == null) || (serverId.isEmpty())) {
      return false;
    }
    if (serverId.equalsIgnoreCase(this.localServerId)) {
      return true;
    }
    if ((servers == null) || servers.isEmpty()) {
      return false;
    }
    return (servers.get(serverId) != null) ? servers.get(serverId).isUp : false;
  }

  /**
   * Actively checks and updates the status of the server instance identified by serverId
   *
   * @param serverId server instance id
   * @return true if server is up, false otherwise
   */
  boolean checkServerUp(String serverId) {
    if ((serverId == null) || (serverId.isEmpty())) {
      return false;
    }
    if (serverId.equalsIgnoreCase(this.localServerId)) {
      return true;
    }
    if ((servers == null) || servers.isEmpty()) {
      return false;
    }
    ServerInfo info = servers.get(serverId);
    info.isUp = checkServerUp(info);
    return info.isUp;
  }

  /**
   * Returns size of the server list
   *
   * @return size of the server list
   */
  int getServerSelectionListSize() {
    return (serverSelectionList == null) ? 0 : serverSelectionList.length;
  }

  /**
   * Returns server id for a given index inside the server list or null if out of bounds.
   *
   * @param index index in the server list, relative to Zero.
   * @return server id
   */
  String getServerSelection(int index) {
    if ((getServerSelectionListSize() <= 0)
        || (index < 0)
        || (index >= getServerSelectionListSize())) {
      return null;
    }
    return serverSelectionList[index].id;
  }

  /**
   * Implements for GeneralTaskRunnable
   *
   * @return The run period of the task.
   */
  public long getRunPeriod() {
    return period;
  }

  /**
   * Implements for GeneralTaskRunnable.
   *
   * @return false since this class will not be used as container.
   */
  public boolean addElement(Object obj) {
    return false;
  }

  /**
   * Implements for GeneralTaskRunnable.
   *
   * @return false since this class will not be used as container.
   */
  public boolean removeElement(Object obj) {
    return false;
  }

  /**
   * Implements for GeneralTaskRunnable.
   *
   * @return true since this class will not be used as container.
   */
  public boolean isEmpty() {
    return true;
  }

  /** Monitoring logic used by background thread */
  public void run() {
    try {
      boolean cleanRemoteSessions = false;
      synchronized (servers) {
        for (Map.Entry<String, ServerInfo> server : servers.entrySet()) {
          ServerInfo info = server.getValue();
          info.isUp = checkServerUp(info);

          if (!info.isUp) {
            downServers.add(info.id);
          } else {
            if (!downServers.isEmpty() && downServers.remove(info.id)) {
              cleanRemoteSessions = true;
            }
          }
        }
      }
      if (cleanRemoteSessions) {
        sessionService.cleanUpRemoteSessions();
      }
    } catch (Exception ex) {
      sessionDebug.error(
          "cleanRemoteSessions Background thread has encountered an Exception: " + ex.getMessage(),
          ex);
    }
  }

  /**
   * Internal method for checking health status using sock.connect()
   *
   * <p>TODO -- Use a better mechanism for alive status. 10.1+.
   *
   * @param info server info instance
   * @return true if server is up, false otherwise
   */
  private boolean checkServerUp(ServerInfo info) {
    if (info == null) {
      return false;
    }
    if (localServerId.equals(info.id)) {
      return true;
    }

    boolean result = false;
    Socket sock = new Socket();
    PrintWriter out = null;
    BufferedReader in = null;

    try {
      sock.connect(info.address, timeout);
      /*
       * If we need to check for a front end proxy, we need
       * to send a request.
       */
      if (doRequest) {
        if (info.protocol.equals(HTTP)) {
          out = new PrintWriter(sock.getOutputStream());
          in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
          out.println(GET_REQUEST);
          out.println(EMPTY_STRING);
          out.flush();

          String response = in.readLine();

          if (response.contains(SUCCESS_200)) {
            result = true;
          } else {
            result = false;
          }
        } else {
          HttpsURLConnection connection = null;
          int responseCode = 0;
          InputStream is = null;

          try {
            connection = (HttpsURLConnection) info.url.openConnection();

            connection.setHostnameVerifier(
                new HostnameVerifier() {
                  public boolean verify(String hostname, SSLSession session) {
                    return true;
                  }
                });

            responseCode = connection.getResponseCode();
            is = connection.getInputStream();
            int ret = 0;
            byte[] buf = new byte[512];

            // clear the stream
            while ((ret = is.read(buf)) > 0) {
              // do nothing
            }

            // close the inputstream
            is.close();
          } catch (IOException ioe) {
            InputStream es = null;

            try {
              es = ((HttpsURLConnection) connection).getErrorStream();
              int ret = 0;
              byte[] buf = new byte[512];

              // read the response body to clear
              while ((ret = es.read(buf)) > 0) {
                // do nothing
              }

              // close the errorstream
              es.close();
            } catch (IOException ex) {
              // deal with the exception
            }
          }

          if (responseCode == HttpURLConnection.HTTP_OK) {
            result = true;
          } else {
            result = false;
          }
        }
      } else {
        result = true;
      }
    } catch (Exception ex) {
      result = false;
    } finally {
      try {
        sock.close();
      } catch (Exception ex) {
      }
    }
    return result;
  }

  // TODO -- Develop Method to write our Server State to the Session Persistence Store.

  /**
   * Override toString
   *
   * @return
   */
  @Override
  public String toString() {
    final StringBuffer sb = new StringBuffer();
    sb.append("ClusterStateService: ");
    sb.append("{ lastSelected=").append(lastSelected);
    sb.append(", timeout=").append(timeout).append("\n");
    sb.append(" Current Server Selection List:").append("\n");
    for (ServerInfo serverInfo : getServerSelectionList()) {
      sb.append(serverInfo.toString());
    }
    sb.append('}');
    return sb.toString();
  }
}