Package org.fao.geonet.kernel.security.ldap

Source Code of org.fao.geonet.kernel.security.ldap.LDAPSynchronizerJob

//=============================================================================
//===  Copyright (C) 2001-2012 Food and Agriculture Organization of the
//===  United Nations (FAO-UN), United Nations World Food Programme (WFP)
//===  and United Nations Environment Programme (UNEP)
//===
//===  This program is free software; you can redistribute it and/or modify
//===  it under the terms of the GNU General Public License as published by
//===  the Free Software Foundation; either version 2 of the License, or (at
//===  your option) any later version.
//===
//===  This program is distributed in the hope that it will be useful, but
//===  WITHOUT ANY WARRANTY; without even the implied warranty of
//===  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//===  General Public License for more details.
//===
//===  You should have received a copy of the GNU General Public License
//===  along with this program; if not, write to the Free Software
//===  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
//===
//===  Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//===  Rome - Italy. email: geonetwork@osgeo.org
//==============================================================================
package org.fao.geonet.kernel.security.ldap;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import org.fao.geonet.domain.UserGroupId_;
import org.fao.geonet.utils.Log;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.Group;
import org.fao.geonet.domain.User;
import org.fao.geonet.repository.GroupRepository;
import org.fao.geonet.repository.UserGroupRepository;
import org.fao.geonet.repository.UserRepository;
import org.fao.geonet.repository.specification.UserSpecs;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.domain.Specifications;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchResult;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LDAPSynchronizerJob extends QuartzJobBean {
   
    private ApplicationContext applicationContext;
   
    private DefaultSpringSecurityContextSource contextSource;
   
    @Override
    protected void executeInternal(final JobExecutionContext jobExecContext)
            throws JobExecutionException {
        try {
            if (Log.isDebugEnabled(Geonet.LDAP)) {
                Log.debug(Geonet.LDAP, "LDAPSynchronizerJob starting ...");
            }
           
            // Retrieve application context. A defautl SpringBeanJobFactory
            // will not provide the application context to the job. Use
            // AutowiringSpringBeanJobFactory.
            applicationContext = (ApplicationContext) jobExecContext
                    .getJobDetail().getJobDataMap().get("applicationContext");
           
           
            if (applicationContext == null) {
                Log.error(
                        Geonet.LDAP,
                        "  Application context is null. Be sure to configure SchedulerFactoryBean job factory property with AutowiringSpringBeanJobFactory.");
            }

            // start transaction
            runInTransaction(jobExecContext);


        } catch (Exception e) {
            Log.error(
                    Geonet.LDAP,
                    "Unexpected error while synchronizing LDAP user in database",
                    e);
            e.printStackTrace();
        }
       
        if (Log.isDebugEnabled(Geonet.LDAP)) {
            Log.debug(Geonet.LDAP, "LDAPSynchronizerJob done.");
        }
    }

    private void runInTransaction(JobExecutionContext jobExecContext) {
        // Get LDAP information defining which users to sync
        final JobDataMap jdm = jobExecContext.getJobDetail().getJobDataMap();
        contextSource = (DefaultSpringSecurityContextSource) jdm.get("contextSource");

        final String ldapUserSearchFilter = (String) jdm.get("ldapUserSearchFilter");
        final String ldapUserSearchBase = (String) jdm.get("ldapUserSearchBase");
        final String ldapUserSearchAttribute = (String) jdm.get("ldapUserSearchAttribute");

        final DirContext dc = contextSource.getReadOnlyContext();
        try {
        // Users
        synchronizeUser(applicationContext, ldapUserSearchFilter, ldapUserSearchBase,
                ldapUserSearchAttribute, dc);

        // And optionaly groups
        String createNonExistingLdapGroup = (String) jdm
                .get("createNonExistingLdapGroup");

        if ("true".equals(createNonExistingLdapGroup)) {
            String ldapGroupSearchFilter = (String) jdm
                    .get("ldapGroupSearchFilter");
            String ldapGroupSearchBase = (String) jdm
                    .get("ldapGroupSearchBase");
            String ldapGroupSearchAttribute = (String) jdm
                    .get("ldapGroupSearchAttribute");
            String ldapGroupSearchPattern = (String) jdm
                    .get("ldapGroupSearchPattern");

            synchronizeGroup(applicationContext, ldapGroupSearchFilter,
                    ldapGroupSearchBase, ldapGroupSearchAttribute,
                    ldapGroupSearchPattern, dc);
        }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (NamingException e) {
            e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
        } finally {
            try {
                dc.close();
            } catch (NamingException e) {
                throw new RuntimeException(e);
            }
        }
    }


    private void synchronizeUser(ApplicationContext applicationContext, String ldapUserSearchFilter,
                                 String ldapUserSearchBase, String ldapUserSearchAttribute,
                                 DirContext dc) throws NamingException, SQLException {
        // Do something for LDAP users ? Currently user is updated on log
        // in only.
        NamingEnumeration<?> userList = dc.search(ldapUserSearchBase,
                ldapUserSearchFilter, null);
       
        // Build a list of LDAP users
        Set<String> usernames = new HashSet<String>();
        while (userList.hasMore()) {
            SearchResult sr = (SearchResult) userList.next();
            final String username = sr.getAttributes().get(ldapUserSearchAttribute)
                    .get().toString();
            usernames.add(username);
        }

        // Remove LDAP user available in db and not in LDAP if not linked to
        // metadata
        final UserRepository userRepository = applicationContext.getBean(UserRepository.class);
        final UserGroupRepository userGroupRepository = applicationContext.getBean(UserGroupRepository.class);
        final Specifications<User> spec = Specifications.where(
                UserSpecs.hasAuthType(LDAPConstants.LDAP_FLAG)
        ).and(
                Specifications.not(UserSpecs.userIsNameNotOneOf(usernames))
        );

        final List<User> usersFound = userRepository.findAll(spec);
        Collection<Integer> userIds = Collections2.transform(usersFound, new Function<User, Integer>() {
            @Nullable
            @Override
            public Integer apply(@Nonnull User input) {
                return input.getId();
            }
        });
        userGroupRepository.deleteAllByIdAttribute(UserGroupId_.userId, userIds);
        userRepository.deleteInBatch(usersFound);
    }
   
   
    private void synchronizeGroup(ApplicationContext applicationContext, String ldapGroupSearchFilter,
                                  String ldapGroupSearchBase, String ldapGroupSearchAttribute,
                                  String ldapGroupSearchPattern, DirContext dc) throws  NamingException, SQLException {
       
        NamingEnumeration<?> groupList = dc.search(ldapGroupSearchBase,
                ldapGroupSearchFilter, null);
        Pattern ldapGroupSearchPatternCompiled = null;
        if (ldapGroupSearchPattern != null && !"".equals(ldapGroupSearchPattern)) {
            ldapGroupSearchPatternCompiled = Pattern.compile(ldapGroupSearchPattern);
        }
       
        while (groupList.hasMore()) {
            SearchResult sr = (SearchResult) groupList.next();
           
            // TODO : should we retrieve LDAP group id and do an update of group
            // name
            // This will require to store in local db the remote id
            String groupName = (String) sr.getAttributes()
                    .get(ldapGroupSearchAttribute).get();
           
            if (ldapGroupSearchPatternCompiled != null && !"".equals(ldapGroupSearchPattern)) {
                Matcher m = ldapGroupSearchPatternCompiled.matcher(groupName);
                boolean b = m.matches();
                if (b) {
                    groupName = m.group(1);
                }
            }
           
            GroupRepository groupRepo = this.applicationContext.getBean(GroupRepository.class);
            Group group = groupRepo.findByName(groupName);
           
            if (group == null) {
                group = groupRepo.save(new Group().setName(groupName));
            } else {
                // Update something ?
                // Group description is only defined in catalog, not in LDAP for the time
                // being
            }
        }
    }
   
    public DefaultSpringSecurityContextSource getContextSource() {
        return contextSource;
    }
   
    public void setContextSource(
            DefaultSpringSecurityContextSource contextSource) {
        this.contextSource = contextSource;
    }
}
TOP

Related Classes of org.fao.geonet.kernel.security.ldap.LDAPSynchronizerJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.