docs: @Override
      @FFDCIgnore({ RegistryException.class, CertificateMapFailedException.class, WSLoginFailedException.class, LoginException.class })
      public boolean login() throws LoginException {
          if (isAlreadyProcessed()) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "Already processed by other login module, abstaining.");
              }
              return false;
          }
  
          X509Certificate certChain[] = null;
          try {
              Callback[] callbacks = getRequiredCallbacks(callbackHandler);
              certChain = ((WSX509CertificateChainCallback) callbacks[0]).getX509CertificateChain();
  
              // If we have insufficient data, abstain.
              if (certChain == null || certChain.length == 0) {
                  return false;
              }
  
              setAlreadyProcessed();
  
              // Check if the certificate subject is a collective certificate chain.
              // If it is a collective certificate chain, handle the collective login
              // otherwise, do a user login.
              CollectiveAuthenticationPlugin plugin = getCollectiveAuthenticationPlugin();
              collectiveCert = plugin.isCollectiveCertificateChain(certChain);
              if (collectiveCert || plugin.isCollectiveCACertificate(certChain)) {
                  handleCollectiveLogin(certChain, plugin, collectiveCert);
              } else {
                  CertificateAuthenticator certAuthen = getCertificateAuthenticator(certChain);
                  if (certAuthen != null) {
                      handleCertificateAuthenticator(certChain, certAuthen);
                  } else {
                      handleUserLogin(certChain);
                  }
              }
  
              updateSharedState();
              return true;
  
          } catch (CertificateMapFailedException e) {
              String dn = certChain[0].getSubjectX500Principal().getName();
              String msg = TraceNLS.getFormattedMessage(
                                                        this.getClass(),
                                                        TraceConstants.MESSAGE_BUNDLE,
                                                        "JAAS_AUTHENTICATION_FAILED_CERTNOMAP",
                                                        new Object[] { dn },
                                                        "CWWKS1101I: CLIENT-CERT Authentication failed for the client certificate with dn {0}. The dn did not map to a user in the registry.");
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "CLIENT-CERT Authentication failed for the client certificate with dn " + dn + ". The dn did not map to a user in the registry.");
              }
              throw new AuthenticationException(msg, e);
          } catch (RegistryException e) {
              String dn = certChain[0].getSubjectX500Principal().getName();
              String msg = TraceNLS.getFormattedMessage(
                                                        this.getClass(),
                                                        TraceConstants.MESSAGE_BUNDLE,
                                                        "JAAS_AUTHENTICATION_FAILED_CERTNOMAP",
                                                        new Object[] { dn },
                                                        "CWWKS1101I: CLIENT-CERT Authentication failed for the client certificate with dn {0}. The dn did not map to a user in the registry.");
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "CLIENT-CERT Authentication failed for the client certificate with dn " + dn + ". The dn did not map to a user in the registry.");
              }
              throw new AuthenticationException(msg, e);
          } catch (WSLoginFailedException e) {
              throw new AuthenticationException(e.getLocalizedMessage());
          } catch (LoginException e) {
              // Need to re-throw LoginException
              throw e;
          } catch (Exception e) {
              if (tc.isDebugEnabled()) {
                  Tr.debug(tc, "Exception while processing CertificateLoginModule.login.", e);
              }
              // This is not normal: FFDC will be instrumented
              String dn;
              if (certChain != null)
                  dn = certChain[0].getSubjectX500Principal().getName();
              else
                  dn = "certChain=null";
              String msg = TraceNLS.getFormattedMessage(this.getClass(),
                                                        TraceConstants.MESSAGE_BUNDLE,
                                                        "JAAS_AUTHENTICATION_FAILED_CERT_INTERNAL_ERROR",
                                                        new Object[] { dn, e },
                                                        "CWWKS1102E: CLIENT-CERT Authentication failed for the client certificate with dn " + dn + ". An internal error occurred: "
                                                                                + e.getLocalizedMessage());
              if (TraceComponent.isAnyTracingEnabled() && tc.isErrorEnabled()) {
                  Tr.error(tc, "JAAS_AUTHENTICATION_FAILED_CERT_INTERNAL_ERROR", dn, e.getLocalizedMessage());
              }
              throw new AuthenticationException(msg, e);
          }
      }