docs: @Override
      @FFDCIgnore({ EntityNotFoundException.class, InvalidNameException.class, NamingException.class })
      public Root login(Root root) throws WIMException {
          List<Entity> entities = root.getEntities();
          LoginAccount inAccount = (LoginAccount) entities.get(0);
          String qName = inAccount.getTypeName();
          Map<String, Control> ctrlMap = ControlsHelper.getControlMap(root);
          LoginControl loginCtrl = (LoginControl) ctrlMap.get(SchemaConstants.DO_LOGIN_CONTROL);
          if (loginCtrl == null) {
              loginCtrl = new LoginControl();
          }
          LdapSearchControl srchCtrl = null;
  
          String principalName = inAccount.getPrincipalName();
  
          if (principalName != null)
              principalName = principalName.replace("*", "\\*");
  
          byte[] pwd = inAccount.getPassword();
          List<byte[]> certList = inAccount.getCertificate();
          int certListSize = certList.size();
  
          LdapEntry acctEntry = null;
  
          Root outRoot = new Root();
          if (certListSize > 0) {
              X509Certificate[] certs = new X509Certificate[certListSize];
              try {
                  for (int i = 0; i < certs.length; i++) {
                      ByteArrayInputStream bais = new ByteArrayInputStream(certList.get(i));
                      CertificateFactory cf = CertificateFactory.getInstance("X.509");
                      certs[i] = (X509Certificate) cf.generateCertificate(bais);
                      bais.close();
                  }
              } catch (IOException e) {
                  String msg = Tr.formatMessage(tc, WIMMessageKey.CERTIFICATE_MAP_FAILED, (Object) null);
                  throw new CertificateMapFailedException(WIMMessageKey.CERTIFICATE_MAP_FAILED, msg);
              } catch (CertificateException e) {
                  String msg = Tr.formatMessage(tc, WIMMessageKey.CERTIFICATE_MAP_FAILED, (Object) null);
                  throw new CertificateMapFailedException(WIMMessageKey.CERTIFICATE_MAP_FAILED, msg);
              }
              srchCtrl = getLdapSearchControl(loginCtrl, false, false);
              acctEntry = mapCertificate(certs, srchCtrl);
              if (acctEntry == null)
                  return outRoot;
          } else {
              if (principalName == null || principalName.trim().isEmpty()) {
                  String msg = Tr.formatMessage(tc, WIMMessageKey.MISSING_OR_EMPTY_PRINCIPAL_NAME, (Object) null);
                  throw new PasswordCheckFailedException(WIMMessageKey.MISSING_OR_EMPTY_PRINCIPAL_NAME, msg);
              }
              if (pwd == null || pwd.length == 0) {
                  String msg = Tr.formatMessage(tc, WIMMessageKey.MISSING_OR_EMPTY_PASSWORD, (Object) null);
                  throw new PasswordCheckFailedException(WIMMessageKey.MISSING_OR_EMPTY_PASSWORD, msg);
              }
  
              String quote = "'";
              if (principalName.indexOf("'") != -1) {
                  quote = "\"";
              }
  
              String searchExpr = "@xsi:type=" + quote + qName + quote + " and "
                                  + SchemaConstants.PROP_PRINCIPAL_NAME + "=" + quote + principalName + quote;
  
              loginCtrl.setExpression(searchExpr);
              srchCtrl = getLdapSearchControl(loginCtrl, false, false);
              String[] searchBases = srchCtrl.getBases();
              String sFilter = srchCtrl.getFilter();
  
              if (iLdapConfigMgr.getUseEncodingInSearchExpression() != null)
                  sFilter = LdapHelper.encodeAttribute(sFilter, iLdapConfigMgr.getUseEncodingInSearchExpression());
  
              //Check is input principalName is DN, if it is DN use the same for login otherwise use userFilter
              String principalNameDN = null;
              try {
                  principalNameDN = new LdapName(principalName).toString();
              } catch (InvalidNameException e) {
                  e.getMessage();
              }
              Filter userFilter = iLdapConfigMgr.getUserFilter();
              if (principalNameDN == null && userFilter != null) {
                  sFilter = userFilter.prepare(principalName);
                  sFilter = setAttributeNamesInFilter(sFilter, SchemaConstants.DO_PERSON_ACCOUNT);
              }
  
              int countLimit = srchCtrl.getCountLimit();
              int timeLimit = srchCtrl.getTimeLimit();
              List<String> entityTypes = srchCtrl.getEntityTypes();
              List<String> propNames = srchCtrl.getPropertyNames();
              // Add login properties to search
              propNames.addAll(iLdapConfigMgr.getLoginProperties());
              int scope = srchCtrl.getScope();
  
              int count = 0;
              for (int i = 0; i < searchBases.length; i++) {
                  try {
                      Set<LdapEntry> ldapEntries = iLdapConn.searchEntities(searchBases[i], sFilter, null, scope, entityTypes,
                                                                            propNames, false, false, countLimit, timeLimit);
                      if (ldapEntries.size() > 1) {
                          // TODO : Add MULTIPLE_PRINCIPALS_FOUND to LdapUtilMesssages.nlsprops and uncomment below if loop
                          /*
                           * if(tc.isErrorEnabled()){
                           * Tr.error(tc, WIMMessageKey.MULTIPLE_PRINCIPALS_FOUND, WIMMessageHelper.generateMsgParms(principalName));
                           * }
                           */
                          throw new PasswordCheckFailedException(WIMMessageKey.MULTIPLE_PRINCIPALS_FOUND, Tr.formatMessage(
                                                                                                                           tc,
                                                                                                                           WIMMessageKey.MULTIPLE_PRINCIPALS_FOUND,
                                                                                                                           WIMMessageHelper.generateMsgParms(principalName)));
                      } else if (ldapEntries.size() == 1) {
                          if (count == 0) {
                              acctEntry = ldapEntries.iterator().next();
                          }
                          count++;
                          if (count > 1) {
                              //Uncomment this when MULTIPLE_PRINCIPALS_FOUND is added to LdapUtilMesssages.nlsprops
                              /*
                               * if(tc.isErrorEnabled()){
                               * Tr.error(tc, WIMMessageKey.MULTIPLE_PRINCIPALS_FOUND, WIMMessageHelper.generateMsgParms(principalName));
                               * }
                               */
                              throw new PasswordCheckFailedException(WIMMessageKey.MULTIPLE_PRINCIPALS_FOUND, Tr.formatMessage(
                                                                                                                               tc,
                                                                                                                               WIMMessageKey.MULTIPLE_PRINCIPALS_FOUND,
                                                                                                                               WIMMessageHelper.generateMsgParms(principalName)));
                          }
                      }
                  } catch (EntityNotFoundException e) {
                      continue;
                  }
              }
              if (acctEntry == null) {
                  return outRoot;
              }
              String dn = acctEntry.getDN();
  
              if (!iLdapConn.isIgnoreCase()) {
                  boolean foundMatch = false;
                  Attributes attrs = acctEntry.getAttributes();
                  List<String> loginProperties = iLdapConfigMgr.getLoginAttributes();
  
                  for (String loginProp : loginProperties) {
                      try {
                          Attribute loginAttr = attrs.get(loginProp);
                          if (loginAttr != null) {
                              String attributeValue = String.valueOf(loginAttr.get());
                              if (principalName.equals(attributeValue)) {
                                  foundMatch = true;
                                  break;
                              }
                          } else {
                              foundMatch = true;
                              break;
                          }
                      } catch (NamingException e) {
                          continue;
                      }
                  }
  
                  if (!foundMatch)
                      return outRoot;
              }
  
              authenticateWithPassword(dn, pwd, principalName);
          }
  
          createEntityFromLdapEntry(outRoot, SchemaConstants.DO_ENTITIES, acctEntry, loginCtrl.getProperties());
  
          return outRoot;
      }