/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.ldap;
import java.io.IOException;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geoserver.config.util.XStreamPersister;
import org.geoserver.security.GeoServerAuthenticationProvider;
import org.geoserver.security.GeoServerRoleService;
import org.geoserver.security.GeoServerSecurityManager;
import org.geoserver.security.GeoServerSecurityProvider;
import org.geoserver.security.GeoServerUserGroupService;
import org.geoserver.security.config.SecurityNamedServiceConfig;
import org.geotools.util.logging.Logging;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.UserDetailsServiceLdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
/**
* LDAP security provider.
*
* @author Justin Deoliveira, OpenGeo
*/
public class LDAPSecurityProvider extends GeoServerSecurityProvider {
static final Logger LOGGER = Logging.getLogger("org.geoserver.security.ldap");
GeoServerSecurityManager securityManager;
public LDAPSecurityProvider(GeoServerSecurityManager securityManager) {
this.securityManager = securityManager;
}
@Override
public void configure(XStreamPersister xp) {
xp.getXStream().alias("ldap", LDAPSecurityServiceConfig.class);
}
@Override
public Class<LDAPAuthenticationProvider> getAuthenticationProviderClass() {
return LDAPAuthenticationProvider.class;
}
@Override
public Class<? extends GeoServerUserGroupService> getUserGroupServiceClass() {
return LDAPUserGroupService.class;
}
@Override
public GeoServerAuthenticationProvider createAuthenticationProvider(SecurityNamedServiceConfig config) {
LDAPSecurityServiceConfig ldapConfig = (LDAPSecurityServiceConfig) config;
LdapContextSource ldapContext = LDAPUtils.createLdapContext(ldapConfig);
GeoserverLdapBindAuthenticator authenticator = new GeoserverLdapBindAuthenticator(
ldapContext);
// authenticate and extract user using a filter and an optional username
// format
authenticator.setUserFilter(ldapConfig.getUserFilter());
authenticator.setUserFormat(ldapConfig.getUserFormat());
// authenticate and extract user using a distinguished name
if (ldapConfig.getUserDnPattern() != null) {
authenticator.setUserDnPatterns(new String[] { ldapConfig
.getUserDnPattern() });
}
LdapAuthoritiesPopulator authPopulator = null;
LdapAuthenticationProvider provider = null;
String ugServiceName = ldapConfig.getUserGroupServiceName();
if (ugServiceName != null) {
// use local user group service for loading authorities
GeoServerUserGroupService ugService;
try {
ugService = securityManager.loadUserGroupService(ugServiceName);
authPopulator = new UserDetailsServiceLdapAuthoritiesPopulator(
ugService);
provider = new LdapAuthenticationProvider(authenticator,
authPopulator);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, String.format(
"Unable to load user group service '%s', "
+ "will use LDAP server for calculating roles",
ugServiceName), e);
}
}
if (authPopulator == null) {
// fall back to looking up roles via LDAP server, choosing
// between default and binding populator
if (ldapConfig.isBindBeforeGroupSearch()) {
authPopulator = new BindingLdapAuthoritiesPopulator(
ldapContext, ldapConfig.getGroupSearchBase());
if (ldapConfig.getGroupSearchFilter() != null) {
((BindingLdapAuthoritiesPopulator) authPopulator)
.setGroupSearchFilter(ldapConfig
.getGroupSearchFilter());
}
provider = new LdapAuthenticationProvider(authenticator,
authPopulator) {
/**
* We need to give authoritiesPopulator both username and
* password, so it can bind to the LDAP server.
*/
@Override
protected Collection<? extends GrantedAuthority> loadUserAuthorities(
DirContextOperations userData, String username,
String password) {
return ((BindingLdapAuthoritiesPopulator) getAuthoritiesPopulator())
.getGrantedAuthorities(userData, username, password);
}
};
} else {
ldapContext.setAnonymousReadOnly(true);
authPopulator = new DefaultLdapAuthoritiesPopulator(
ldapContext, ldapConfig.getGroupSearchBase());
if (ldapConfig.getGroupSearchFilter() != null) {
((DefaultLdapAuthoritiesPopulator) authPopulator)
.setGroupSearchFilter(ldapConfig
.getGroupSearchFilter());
}
provider = new LdapAuthenticationProvider(authenticator,
authPopulator);
}
}
return new LDAPAuthenticationProvider(provider,
ldapConfig.getAdminGroup(), ldapConfig.getGroupAdminGroup());
}
@Override
public Class<? extends GeoServerRoleService> getRoleServiceClass() {
return LDAPRoleService.class;
}
@Override
public GeoServerRoleService createRoleService(SecurityNamedServiceConfig config)
throws IOException {
return new LDAPRoleService();
}
@Override
public GeoServerUserGroupService createUserGroupService(SecurityNamedServiceConfig config)
throws IOException {
return new LDAPUserGroupService(config);
}
}