001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.shiro.realm.ldap; 020 021import java.util.Hashtable; 022import java.util.Map; 023import javax.naming.Context; 024import javax.naming.NamingException; 025import javax.naming.ldap.InitialLdapContext; 026import javax.naming.ldap.LdapContext; 027 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * <p>Default implementation of {@link LdapContextFactory} that can be configured or extended to 033 * customize the way {@link javax.naming.ldap.LdapContext} objects are retrieved.</p> 034 * <p/> 035 * <p>This implementation of {@link LdapContextFactory} is used by the {@link AbstractLdapRealm} if a 036 * factory is not explictly configured.</p> 037 * <p/> 038 * <p>Connection pooling is enabled by default on this factory, but can be disabled using the 039 * {@link #usePooling} property.</p> 040 * 041 * @since 0.2 042 * @deprecated replaced by the {@link JndiLdapContextFactory} implementation. This implementation will be removed 043 * prior to Shiro 2.0 044 */ 045@Deprecated 046public class DefaultLdapContextFactory implements LdapContextFactory { 047 048 //TODO - complete JavaDoc 049 050 /*-------------------------------------------- 051 | C O N S T A N T S | 052 ============================================*/ 053 /** 054 * The Sun LDAP property used to enable connection pooling. This is used in the default implementation 055 * to enable LDAP connection pooling. 056 */ 057 protected static final String SUN_CONNECTION_POOLING_PROPERTY = "com.sun.jndi.ldap.connect.pool"; 058 059 /*-------------------------------------------- 060 | I N S T A N C E V A R I A B L E S | 061 ============================================*/ 062 063 private static final Logger log = LoggerFactory.getLogger(DefaultLdapContextFactory.class); 064 065 protected String authentication = "simple"; 066 067 protected String principalSuffix = null; 068 069 protected String searchBase = null; 070 071 protected String contextFactoryClassName = "com.sun.jndi.ldap.LdapCtxFactory"; 072 073 protected String url = null; 074 075 protected String referral = "follow"; 076 077 protected String systemUsername = null; 078 079 protected String systemPassword = null; 080 081 private boolean usePooling = true; 082 083 private Map<String, String> additionalEnvironment; 084 085 /*-------------------------------------------- 086 | C O N S T R U C T O R S | 087 ============================================*/ 088 089 /*-------------------------------------------- 090 | A C C E S S O R S / M O D I F I E R S | 091 ============================================*/ 092 093 /** 094 * Sets the type of LDAP authentication to perform when connecting to the LDAP server. Defaults to "simple" 095 * 096 * @param authentication the type of LDAP authentication to perform. 097 */ 098 public void setAuthentication(String authentication) { 099 this.authentication = authentication; 100 } 101 102 /** 103 * A suffix appended to the username. This is typically for 104 * domain names. (e.g. "@MyDomain.local") 105 * 106 * @param principalSuffix the suffix. 107 */ 108 public void setPrincipalSuffix(String principalSuffix) { 109 this.principalSuffix = principalSuffix; 110 } 111 112 /** 113 * The search base for the search to perform in the LDAP server. 114 * (e.g. OU=OrganizationName,DC=MyDomain,DC=local ) 115 * 116 * @param searchBase the search base. 117 * @deprecated this attribute existed, but was never used in Shiro 1.x. It will be removed prior to Shiro 2.0. 118 */ 119 @Deprecated 120 public void setSearchBase(String searchBase) { 121 this.searchBase = searchBase; 122 } 123 124 /** 125 * The context factory to use. This defaults to the SUN LDAP JNDI implementation 126 * but can be overridden to use custom LDAP factories. 127 * 128 * @param contextFactoryClassName the context factory that should be used. 129 */ 130 public void setContextFactoryClassName(String contextFactoryClassName) { 131 this.contextFactoryClassName = contextFactoryClassName; 132 } 133 134 /** 135 * The LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>) 136 * 137 * @param url the LDAP url. 138 */ 139 public void setUrl(String url) { 140 this.url = url; 141 } 142 143 /** 144 * Sets the LDAP referral property. Defaults to "follow" 145 * 146 * @param referral the referral property. 147 */ 148 public void setReferral(String referral) { 149 this.referral = referral; 150 } 151 152 /** 153 * The system username that will be used when connecting to the LDAP server to retrieve authorization 154 * information about a user. This must be specified for LDAP authorization to work, but is not required for 155 * only authentication. 156 * 157 * @param systemUsername the username to use when logging into the LDAP server for authorization. 158 */ 159 public void setSystemUsername(String systemUsername) { 160 this.systemUsername = systemUsername; 161 } 162 163 164 /** 165 * The system password that will be used when connecting to the LDAP server to retrieve authorization 166 * information about a user. This must be specified for LDAP authorization to work, but is not required for 167 * only authentication. 168 * 169 * @param systemPassword the password to use when logging into the LDAP server for authorization. 170 */ 171 public void setSystemPassword(String systemPassword) { 172 this.systemPassword = systemPassword; 173 } 174 175 /** 176 * Determines whether or not LdapContext pooling is enabled for connections made using the system 177 * user account. In the default implementation, this simply 178 * sets the <tt>com.sun.jndi.ldap.connect.pool</tt> property in the LDAP context environment. If you use an 179 * LDAP Context Factory that is not Sun's default implementation, you will need to override the 180 * default behavior to use this setting in whatever way your underlying LDAP ContextFactory 181 * supports. By default, pooling is enabled. 182 * 183 * @param usePooling true to enable pooling, or false to disable it. 184 */ 185 public void setUsePooling(boolean usePooling) { 186 this.usePooling = usePooling; 187 } 188 189 /** 190 * These entries are added to the environment map before initializing the LDAP context. 191 * 192 * @param additionalEnvironment additional environment entries to be configured on the LDAP context. 193 */ 194 public void setAdditionalEnvironment(Map<String, String> additionalEnvironment) { 195 this.additionalEnvironment = additionalEnvironment; 196 } 197 198 /*-------------------------------------------- 199 | M E T H O D S | 200 ============================================*/ 201 public LdapContext getSystemLdapContext() throws NamingException { 202 return getLdapContext(systemUsername, systemPassword); 203 } 204 205 /** 206 * Deprecated - use {@link #getLdapContext(Object, Object)} instead. This will be removed before Apache Shiro 2.0. 207 * 208 * @param username the username to use when creating the connection. 209 * @param password the password to use when creating the connection. 210 * @return a {@code LdapContext} bound using the given username and password. 211 * @throws javax.naming.NamingException if there is an error creating the context. 212 * @deprecated the {@link #getLdapContext(Object, Object)} method should be used in all cases to ensure more than 213 * String principals and credentials can be used. Shiro no longer calls this method - it will be 214 * removed before the 2.0 release. 215 */ 216 @Deprecated 217 public LdapContext getLdapContext(String username, String password) throws NamingException { 218 if (username != null && principalSuffix != null) { 219 username += principalSuffix; 220 } 221 return getLdapContext((Object) username, password); 222 } 223 224 public LdapContext getLdapContext(Object principal, Object credentials) throws NamingException { 225 if (url == null) { 226 throw new IllegalStateException("An LDAP URL must be specified of the form ldap://<hostname>:<port>"); 227 } 228 229 Hashtable<String, Object> env = new Hashtable<String, Object>(); 230 231 env.put(Context.SECURITY_AUTHENTICATION, authentication); 232 if (principal != null) { 233 env.put(Context.SECURITY_PRINCIPAL, principal); 234 } 235 if (credentials!= null) { 236 env.put(Context.SECURITY_CREDENTIALS, credentials); 237 } 238 env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactoryClassName); 239 env.put(Context.PROVIDER_URL, url); 240 env.put(Context.REFERRAL, referral); 241 242 // Only pool connections for system contexts 243 if (usePooling && principal != null && principal.equals(systemUsername)) { 244 // Enable connection pooling 245 env.put(SUN_CONNECTION_POOLING_PROPERTY, "true"); 246 } 247 248 if (additionalEnvironment != null) { 249 env.putAll(additionalEnvironment); 250 } 251 252 if (log.isDebugEnabled()) { 253 log.debug("Initializing LDAP context using URL [" + url + "] and username [" + systemUsername + "] " + 254 "with pooling [" + (usePooling ? "enabled" : "disabled") + "]"); 255 } 256 257 return new InitialLdapContext(env, null); 258 } 259}