/**
  * @return a Collection of principals that contains the current user principal and all groups it
  *     is member of.
  */
 protected Set<Principal> getPrincipals() {
   // use linked HashSet instead of HashSet in order to maintain the order
   // of principals (as in the Subject).
   Set<Principal> principals = new LinkedHashSet<Principal>();
   principals.add(principal);
   PrincipalIterator groups = principalProvider.getGroupMembership(principal);
   while (groups.hasNext()) {
     principals.add(groups.nextPrincipal());
   }
   return principals;
 }
  /**
   * Initialize this LoginModule and sets the following fields for later usage:
   *
   * <ul>
   *   <li>{@link PrincipalProvider} for user-{@link Principal} resolution.
   *   <li>{@link LoginModuleConfig#PARAM_ADMIN_ID} option is evaluated
   *   <li>{@link LoginModuleConfig#PARAM_ANONYMOUS_ID} option is evaluated
   * </ul>
   *
   * Implementations are called via {@link #doInit(CallbackHandler, Session, Map)} to implement
   * additional initialization
   *
   * @param subject the <code>Subject</code> to be authenticated.
   *     <p>
   * @param callbackHandler a <code>CallbackHandler</code> for communicating with the end user
   *     (prompting for usernames and passwords, for example).
   *     <p>
   * @param sharedState state shared with other configured LoginModules.
   *     <p>
   * @param options options specified in the login <code>Configuration</code> for this particular
   *     <code>LoginModule</code>.
   * @see LoginModule#initialize(Subject, CallbackHandler, Map, Map)
   * @see #doInit(CallbackHandler, Session, Map)
   * @see #isInitialized()
   */
  public void initialize(
      Subject subject,
      CallbackHandler callbackHandler,
      Map<String, ?> sharedState,
      Map<String, ?> options) {
    // common jaas state variables
    this.callbackHandler = callbackHandler;
    this.subject = subject;
    this.sharedState = sharedState;

    // initialize the login module
    try {
      log.debug("Initialize LoginModule: ");
      RepositoryCallback repositoryCb = new RepositoryCallback();
      callbackHandler.handle(new Callback[] {repositoryCb});

      PrincipalProviderRegistry registry = repositoryCb.getPrincipalProviderRegistry();
      // check if the class name of a PrincipalProvider implementation
      // is present with the module configuration.
      if (options.containsKey(LoginModuleConfig.PARAM_PRINCIPAL_PROVIDER_CLASS)) {
        Object pcOption = options.get(LoginModuleConfig.PARAM_PRINCIPAL_PROVIDER_CLASS);
        if (pcOption != null) {
          principalProviderClassName = pcOption.toString();
        }
      }
      if (principalProviderClassName == null) {
        // try compatibility parameters
        if (options.containsKey(LoginModuleConfig.COMPAT_PRINCIPAL_PROVIDER_NAME)) {
          principalProviderClassName =
              options.get(LoginModuleConfig.COMPAT_PRINCIPAL_PROVIDER_NAME).toString();
        } else if (options.containsKey(LoginModuleConfig.COMPAT_PRINCIPAL_PROVIDER_CLASS)) {
          principalProviderClassName =
              options.get(LoginModuleConfig.COMPAT_PRINCIPAL_PROVIDER_CLASS).toString();
        }
      }
      if (principalProviderClassName != null) {
        principalProvider = registry.getProvider(principalProviderClassName);
      }
      if (principalProvider == null) {
        principalProvider = registry.getDefault();
        if (principalProvider == null) {
          return; // abort. not even a default principal provider
        }
      }
      log.debug("- PrincipalProvider -> '" + principalProvider.getClass().getName() + "'");

      // call implementation for additional setup
      doInit(callbackHandler, repositoryCb.getSession(), options);

      // adminId: if not present in options -> retrieve from callback
      if (options.containsKey(LoginModuleConfig.PARAM_ADMIN_ID)) {
        adminId = (String) options.get(LoginModuleConfig.PARAM_ADMIN_ID);
      }
      if (adminId == null) {
        adminId = repositoryCb.getAdminId();
      }
      // anonymousId: if not present in options -> retrieve from callback
      if (options.containsKey(LoginModuleConfig.PARAM_ANONYMOUS_ID)) {
        anonymousId = (String) options.get(LoginModuleConfig.PARAM_ANONYMOUS_ID);
      }
      if (anonymousId == null) {
        anonymousId = repositoryCb.getAnonymousId();
      }
      // trusted credentials attribute name (may be missing to not
      // support) (normalized to null aka missing aka unset if an empty
      // string)
      preAuthAttributeName = (String) options.get(PRE_AUTHENTICATED_ATTRIBUTE_OPTION);
      if (preAuthAttributeName != null && preAuthAttributeName.length() == 0) {
        preAuthAttributeName = null;
      }

      // log config values for debug
      if (log.isDebugEnabled()) {
        for (String option : options.keySet()) {
          log.debug("- Option: " + option + " -> '" + options.get(option) + "'");
        }
      }
      initialized = (this.subject != null);

    } catch (Exception e) {
      log.error("LoginModule failed to initialize.", e);
    }
  }