org.apache.archiva.redback.users.ldap.ctl.DefaultLdapController.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.archiva.redback.users.ldap.ctl.DefaultLdapController.java

Source

package org.apache.archiva.redback.users.ldap.ctl;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import org.apache.archiva.redback.common.ldap.user.LdapUser;
import org.apache.archiva.redback.common.ldap.user.LdapUserMapper;
import org.apache.archiva.redback.common.ldap.user.UserMapper;
import org.apache.archiva.redback.configuration.UserConfiguration;
import org.apache.archiva.redback.configuration.UserConfigurationKeys;
import org.apache.archiva.redback.policy.PasswordEncoder;
import org.apache.archiva.redback.policy.encoders.SHA1PasswordEncoder;
import org.apache.archiva.redback.users.User;
import org.apache.archiva.redback.users.UserManager;
import org.apache.archiva.redback.common.ldap.MappingException;
import org.apache.archiva.redback.users.ldap.LdapUserQuery;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * @author <a href="jesse@codehaus.org"> jesse
 */
@Service
public class DefaultLdapController implements LdapController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @Inject
    @Named(value = "userMapper#ldap")
    private UserMapper mapper;

    @Inject
    @Named(value = "userConfiguration#default")
    private UserConfiguration userConf;

    private boolean writableLdap = false;

    private PasswordEncoder passwordEncoder;

    private String baseDn;

    private String groupsDn;

    private String ldapGroupClass = "groupOfUniqueNames";

    @PostConstruct
    public void initialize() {
        this.writableLdap = userConf.getBoolean(UserConfigurationKeys.LDAP_WRITABLE, this.writableLdap);
        this.baseDn = userConf.getConcatenatedList(UserConfigurationKeys.LDAP_BASEDN, null);
        this.passwordEncoder = new SHA1PasswordEncoder();
        this.groupsDn = userConf.getConcatenatedList(UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn);
        this.ldapGroupClass = userConf.getString(UserConfigurationKeys.LDAP_GROUPS_CLASS, this.ldapGroupClass);
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#removeUser(String, javax.naming.directory.DirContext)
     */
    public void removeUser(String principal, DirContext context) throws LdapControllerException {
        // no op
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#updateUser(org.apache.archiva.redback.users.User, javax.naming.directory.DirContext)
     */
    public void updateUser(User user, DirContext context) throws LdapControllerException, MappingException {
        // no op
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#userExists(String, javax.naming.directory.DirContext)
     */
    public boolean userExists(String key, DirContext context) throws LdapControllerException {
        NamingEnumeration<SearchResult> results = null;
        try {
            results = searchUsers(key, context);
            return results.hasMoreElements();
        } catch (NamingException e) {
            throw new LdapControllerException("Error searching for the existence of user: " + key, e);
        } finally {
            if (results != null) {
                try {
                    results.close();
                } catch (NamingException e) {
                    log.warn("Error closing search results", e);
                }
            }
        }
    }

    protected NamingEnumeration<SearchResult> searchUsers(String key, DirContext context) throws NamingException {
        LdapUserQuery query = new LdapUserQuery();
        query.setUsername(key);
        return searchUsers(context, null, query);
    }

    protected NamingEnumeration<SearchResult> searchUsers(DirContext context) throws NamingException {
        return searchUsers(context, null, null);
    }

    protected NamingEnumeration<SearchResult> searchUsers(DirContext context, String[] returnAttributes)
            throws NamingException {
        return searchUsers(context, returnAttributes, null);
    }

    protected NamingEnumeration<SearchResult> searchUsers(DirContext context, String[] returnAttributes,
            LdapUserQuery query) throws NamingException {
        if (query == null) {
            query = new LdapUserQuery();
        }
        SearchControls ctls = new SearchControls();

        ctls.setDerefLinkFlag(true);
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        ctls.setReturningAttributes(mapper.getReturningAttributes());
        ctls.setCountLimit(((LdapUserMapper) mapper).getMaxResultCount());

        String finalFilter = new StringBuilder("(&(objectClass=" + mapper.getUserObjectClass() + ")")
                .append((mapper.getUserFilter() != null ? mapper.getUserFilter() : ""))
                .append(query.getLdapFilter(mapper) + ")").toString();

        log.debug("Searching for users with filter: '{}' from base dn: {}", finalFilter, mapper.getUserBaseDn());

        return context.search(mapper.getUserBaseDn(), finalFilter, ctls);
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#getUsers(javax.naming.directory.DirContext)
     */
    public Collection<User> getUsers(DirContext context) throws LdapControllerException, MappingException {
        NamingEnumeration<SearchResult> results = null;
        try {
            results = searchUsers(context, null, null);
            Set<User> users = new LinkedHashSet<User>();

            while (results.hasMoreElements()) {
                SearchResult result = results.nextElement();

                users.add(mapper.getUser(result.getAttributes()));
            }

            return users;
        } catch (NamingException e) {
            String message = "Failed to retrieve ldap information for users.";

            throw new LdapControllerException(message, e);
        } finally {
            if (results != null) {
                try {
                    results.close();
                } catch (NamingException e) {
                    log.warn("failed to close search results", e);
                }
            }
        }
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#getUsersByQuery(org.apache.archiva.redback.users.ldap.LdapUserQuery, javax.naming.directory.DirContext)
     */
    public List<User> getUsersByQuery(LdapUserQuery query, DirContext context)
            throws LdapControllerException, MappingException {
        NamingEnumeration<SearchResult> results = null;
        try {
            results = searchUsers(context, null, query);
            List<User> users = new LinkedList<User>();

            while (results.hasMoreElements()) {
                SearchResult result = results.nextElement();

                users.add(mapper.getUser(result.getAttributes()));
            }

            return users;
        } catch (NamingException e) {
            String message = "Failed to retrieve ldap information for users.";

            throw new LdapControllerException(message, e);
        } finally {
            if (results != null) {
                try {
                    results.close();
                } catch (NamingException e) {
                    log.warn("failed to close search results", e);
                }
            }
        }
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#createUser(org.apache.archiva.redback.users.User, javax.naming.directory.DirContext, boolean)
     */
    public void createUser(User user, DirContext context, boolean encodePasswordIfChanged)
            throws LdapControllerException, MappingException {
        if (user == null) {
            return;
        }
        if (user.getUsername().equals(UserManager.GUEST_USERNAME)) {
            log.warn("skip user '{}' creation");
            //We don't store guest
            return;
        }
        boolean userExists = userExists(user.getUsername(), context);
        if (userExists) {
            log.debug("user '{}' exists skip creation", user.getUsername());
            return;
        }
        if (writableLdap) {
            try {
                bindUserObject(context, user);
                log.info("user {} created in ldap", user.getUsername());
            } catch (NamingException e) {
                throw new LdapControllerException(e.getMessage(), e);
            }
        }
    }

    private void bindUserObject(DirContext context, User user) throws NamingException {
        Attributes attributes = new BasicAttributes(true);
        BasicAttribute objectClass = new BasicAttribute("objectClass");
        objectClass.add("top");
        objectClass.add("inetOrgPerson");
        objectClass.add("person");
        objectClass.add("organizationalperson");
        attributes.put(objectClass);
        attributes.put("cn", user.getUsername());
        attributes.put("sn", "foo");
        if (StringUtils.isNotEmpty(user.getEmail())) {
            attributes.put("mail", user.getEmail());
        }

        if (userConf.getBoolean(UserConfigurationKeys.LDAP_BIND_AUTHENTICATOR_ALLOW_EMPTY_PASSWORDS, false)
                && StringUtils.isNotEmpty(user.getPassword())) {
            attributes.put("userPassword", passwordEncoder.encodePassword(user.getPassword()));
        }
        attributes.put("givenName", "foo");
        context.createSubcontext("cn=" + user.getUsername() + "," + this.getBaseDn(), attributes);
    }

    /**
     * @see org.apache.archiva.redback.users.ldap.ctl.LdapController#getUser(String, javax.naming.directory.DirContext)
     */
    public LdapUser getUser(String username, DirContext context) throws LdapControllerException, MappingException {

        log.debug("Searching for user: {}", username);

        LdapUserQuery query = new LdapUserQuery();
        query.setUsername(username);

        NamingEnumeration<SearchResult> result = null;
        try {
            result = searchUsers(context, null, query);

            if (result.hasMoreElements()) {
                SearchResult next = result.nextElement();

                log.info("Found user: {}", username);

                return mapper.getUser(next.getAttributes());
            } else {
                return null;
            }
        } catch (NamingException e) {
            String message = "Failed to retrieve information for user: " + username;

            throw new LdapControllerException(message, e);
        } finally {
            if (result != null) {
                try {
                    result.close();
                } catch (NamingException e) {
                    log.warn("failed to close search results", e);
                }
            }
        }
    }

    public Map<String, Collection<String>> findUsersWithRoles(DirContext dirContext)
            throws LdapControllerException {
        Map<String, Collection<String>> usersWithRoles = new HashMap<String, Collection<String>>();

        NamingEnumeration<SearchResult> namingEnumeration = null;
        try {

            SearchControls searchControls = new SearchControls();

            searchControls.setDerefLinkFlag(true);
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            String filter = "objectClass=" + getLdapGroupClass();

            namingEnumeration = dirContext.search(getGroupsDn(), filter, searchControls);

            while (namingEnumeration.hasMore()) {
                SearchResult searchResult = namingEnumeration.next();

                String groupName = searchResult.getName();
                // cn=blabla we only want bla bla
                groupName = StringUtils.substringAfter(groupName, "=");

                Attribute uniqueMemberAttr = searchResult.getAttributes().get("uniquemember");

                if (uniqueMemberAttr != null) {
                    NamingEnumeration<String> allMembersEnum = (NamingEnumeration<String>) uniqueMemberAttr
                            .getAll();
                    while (allMembersEnum.hasMore()) {
                        String userName = allMembersEnum.next();
                        // uid=blabla we only want bla bla
                        userName = StringUtils.substringAfter(userName, "=");
                        userName = StringUtils.substringBefore(userName, ",");
                        Collection<String> roles = usersWithRoles.get(userName);
                        if (roles == null) {
                            roles = new HashSet<String>();
                        }

                        roles.add(groupName);

                        usersWithRoles.put(userName, roles);

                    }
                }

                log.debug("found groupName: '{}' with users: {}", groupName);

            }

            return usersWithRoles;
        } catch (NamingException e) {
            throw new LdapControllerException(e.getMessage(), e);
        }

        finally {

            if (namingEnumeration != null) {
                try {
                    namingEnumeration.close();
                } catch (NamingException e) {
                    log.warn("failed to close search results", e);
                }
            }
        }
    }

    //-----------------------------
    // setters/getters
    //-----------------------------
    public UserMapper getMapper() {
        return mapper;
    }

    public void setMapper(UserMapper mapper) {
        this.mapper = mapper;
    }

    public UserConfiguration getUserConf() {
        return userConf;
    }

    public void setUserConf(UserConfiguration userConf) {
        this.userConf = userConf;
    }

    public boolean isWritableLdap() {
        return writableLdap;
    }

    public void setWritableLdap(boolean writableLdap) {
        this.writableLdap = writableLdap;
    }

    public PasswordEncoder getPasswordEncoder() {
        return passwordEncoder;
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    public String getBaseDn() {
        return baseDn;
    }

    public void setBaseDn(String baseDn) {
        this.baseDn = baseDn;
    }

    public String getGroupsDn() {
        return groupsDn;
    }

    public void setGroupsDn(String groupsDn) {
        this.groupsDn = groupsDn;
    }

    public String getLdapGroupClass() {
        return ldapGroupClass;
    }

    public void setLdapGroupClass(String ldapGroupClass) {
        this.ldapGroupClass = ldapGroupClass;
    }
}