All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.security.ldap.DefaultSpringSecurityContextSource Maven / Gradle / Ivy

There is a newer version: 6.3.4
Show newest version
/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.
 */

package org.springframework.security.ldap;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.log.LogMessage;
import org.springframework.ldap.core.support.DirContextAuthenticationStrategy;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy;
import org.springframework.util.Assert;

/**
 * ContextSource implementation which uses Spring LDAP's LdapContextSource as a
 * base class. Used internally by the Spring Security LDAP namespace configuration.
 * 

* From Spring Security 3.0, Spring LDAP 1.3 is used and the ContextSource * interface provides support for binding with a username and password. As a result, * Spring LDAP ContextSource implementations such as LdapContextSource * may be used directly with Spring Security. *

* Spring LDAP 1.3 doesn't have JVM-level LDAP connection pooling enabled by default. This * class sets the pooled property to true, but customizes the * {@link DirContextAuthenticationStrategy} used to disable pooling when the DN * doesn't match the userDn property. This prevents pooling for calls to * {@link #getContext(String, String)} to authenticate as specific users. * * @author Luke Taylor * @since 2.0 */ public class DefaultSpringSecurityContextSource extends LdapContextSource { protected final Log logger = LogFactory.getLog(getClass()); /** * Create and initialize an instance which will connect to the supplied LDAP URL. If * you want to use more than one server for fail-over, rather use the * {@link #DefaultSpringSecurityContextSource(List, String)} constructor. * @param providerUrl an LDAP URL of the form * ldap://localhost:389/base_dn */ public DefaultSpringSecurityContextSource(String providerUrl) { Assert.hasLength(providerUrl, "An LDAP connection URL must be supplied."); StringTokenizer tokenizer = new StringTokenizer(providerUrl); ArrayList urls = new ArrayList<>(); // Work out rootDn from the first URL and check that the other URLs (if any) match String rootDn = null; while (tokenizer.hasMoreTokens()) { String url = tokenizer.nextToken(); String urlRootDn = LdapUtils.parseRootDnFromUrl(url); urls.add(url.substring(0, url.lastIndexOf(urlRootDn))); this.logger.info(LogMessage.format("Configure with URL %s and root DN %s", url, urlRootDn)); Assert.isTrue(rootDn == null || rootDn.equals(urlRootDn), "Root DNs must be the same when using multiple URLs"); rootDn = (rootDn != null) ? rootDn : urlRootDn; } setUrls(urls.toArray(new String[0])); setBase((rootDn != null) ? decodeUrl(rootDn) : null); setPooled(true); setAuthenticationStrategy(new SimpleDirContextAuthenticationStrategy() { @Override @SuppressWarnings("rawtypes") public void setupEnvironment(Hashtable env, String dn, String password) { super.setupEnvironment(env, dn, password); // Remove the pooling flag unless authenticating as the 'manager' user. if (!DefaultSpringSecurityContextSource.this.userDn.equals(dn) && env.containsKey(SUN_LDAP_POOLING_FLAG)) { DefaultSpringSecurityContextSource.this.logger.trace("Removing pooling flag for user " + dn); env.remove(SUN_LDAP_POOLING_FLAG); } } }); } /** * Create and initialize an instance which will connect of the LDAP Spring Security * Context Source. It will connect to any of the provided LDAP server URLs. * @param urls A list of string values which are LDAP server URLs. An example would be * ldap://ldap.company.com:389. LDAPS URLs (SSL-secured) may be used as * well, given that Spring Security is able to connect to the server. Note that these * URLs must not include the base DN! * @param baseDn The common Base DN for all provided servers, e.g. * *

	 * dc=company,dc=com
	 * 
* * . */ public DefaultSpringSecurityContextSource(List urls, String baseDn) { this(buildProviderUrl(urls, baseDn)); } /** * Builds a Spring LDAP-compliant Provider URL string, i.e. a space-separated list of * LDAP servers with their base DNs. As the base DN must be identical for all servers, * it needs to be supplied only once. * @param urls A list of string values which are LDAP server URLs. An example would be * *
	 * ldap://ldap.company.com:389
	 * 
* * . LDAPS URLs may be used as well, given that Spring Security is able to connect to * the server. * @param baseDn The common Base DN for all provided servers, e.g. * *
	 * dc=company,dc=com
	 * 
* * . * @return A Spring Security/Spring LDAP-compliant Provider URL string. */ private static String buildProviderUrl(List urls, String baseDn) { Assert.notNull(baseDn, "The Base DN for the LDAP server must not be null."); Assert.notEmpty(urls, "At least one LDAP server URL must be provided."); String encodedBaseDn = encodeUrl(baseDn.trim()); StringBuilder providerUrl = new StringBuilder(); for (String serverUrl : urls) { String trimmedUrl = serverUrl.trim(); if ("".equals(trimmedUrl)) { continue; } providerUrl.append(trimmedUrl); if (!trimmedUrl.endsWith("/")) { providerUrl.append("/"); } providerUrl.append(encodedBaseDn); providerUrl.append(" "); } return providerUrl.toString(); } private static String encodeUrl(String url) { try { return URLEncoder.encode(url, StandardCharsets.UTF_8.toString()); } catch (UnsupportedEncodingException ex) { throw new IllegalStateException(ex); } } private String decodeUrl(String url) { try { return URLDecoder.decode(url, StandardCharsets.UTF_8.toString()); } catch (UnsupportedEncodingException ex) { throw new IllegalStateException(ex); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy