@Override
    public User loadUser(String username) throws UserNotFoundException {
        if(username.contains("@")) {
            if (!XMPPServer.getInstance().isLocal(new JID(username))) {
                throw new UserNotFoundException("Cannot load user of remote server: " + username);
            }
            username = username.substring(0,username.lastIndexOf("@"));
        }
        // Un-escape username.
        username = JID.unescapeNode(username);
        DirContext ctx = null;
        try {
            Rdn[] userRDN = manager.findUserRDN(username);
            // Load record.
            final List<String> attributes = new ArrayList<>();
            attributes.add( manager.getUsernameField() );
            attributes.addAll( manager.getNameField().getFields() );
            attributes.add( manager.getEmailField() );
            attributes.add( "createTimestamp" );
            attributes.add( "modifyTimestamp" );

            ctx = manager.getContext(manager.getUsersBaseDN(username));
            Attributes attrs = ctx.getAttributes(LdapManager.escapeForJNDI(userRDN), attributes.toArray(new String[0]));
            String name = LdapUserTester.getPropertyValue(manager.getNameField(), attrs);
            String email = null;
            Attribute emailField = attrs.get(manager.getEmailField());
            if (emailField != null) {
                email = (String)emailField.get();
            }
            Date creationDate = null;
            Attribute creationDateField = attrs.get("createTimestamp");
            if (creationDateField != null && ((String) creationDateField.get()).trim().isEmpty()) {
                creationDate = parseLDAPDate((String) creationDateField.get());
            }
            Date modificationDate = null;
            Attribute modificationDateField = attrs.get("modifyTimestamp");
            if (modificationDateField != null && ((String) modificationDateField.get()).trim().isEmpty()) {
                modificationDate = parseLDAPDate((String)modificationDateField.get());
            }
            // Escape the username so that it can be used as a JID.
            username = JID.escapeNode(username);
            
            // As defined by RFC5803.
            Attribute authPassword = attrs.get("authPassword");
            User user = new User(username, name, email, creationDate, modificationDate);
            if (manager.isFindUsersFromGroupsEnabled() && GroupManager.getInstance().getGroups(user).isEmpty()) {
                throw new UserNotFoundException("User exists in LDAP but is not a member of any Openfire groups");
            }
            if (authPassword != null) {
                // The authPassword attribute can be multivalued.
                // Not sure if this is the right API to loop through them.
                NamingEnumeration<?> values = authPassword.getAll();
                while (values.hasMore()) {
                    Attribute authPasswordValue = (Attribute) values.next();
                    String[] parts = ((String) authPasswordValue.get()).split("\\$");
                    String[] authInfo = parts[1].split(":");
                    String[] authValue = parts[2].split(":");
    
                    String scheme = parts[0].trim();
    
                    // We only support SCRAM-SHA-1 at the moment.
                    if ("SCRAM-SHA-1".equals(scheme)) {
                        int iterations = Integer.parseInt(authInfo[0].trim());
                        String salt = authInfo[1].trim();
                        String storedKey = authValue[0].trim();
                        String serverKey = authValue[1].trim();
                        
                        user.setSalt(salt);
                        user.setStoredKey(storedKey);
                        user.setServerKey(serverKey);
                        user.setIterations(iterations);
                        
                        break;
                    }
                }
            }
            return user;
        }
        catch (Exception e) {
            throw new UserNotFoundException(e);
        }
        finally {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            }
            catch (Exception ex) {
                Log.debug( "An exception occurred while closing the LDAP context after attempting to load user {}", username, ex);
            }
        }
    }
LDAP implementation of the UserProvider interface. All data in the directory is
treated as read-only so any set operations will result in an exception.

@author Matt Tucker
xmppserver/src/main/java/org/jivesoftware/openfire/ldap/LdapUserProvider.java