View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.realm.ldap;
20  
21  import java.util.Hashtable;
22  import java.util.Map;
23  import javax.naming.Context;
24  import javax.naming.NamingException;
25  import javax.naming.ldap.InitialLdapContext;
26  import javax.naming.ldap.LdapContext;
27  
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  /**
32   * <p>Default implementation of {@link LdapContextFactory} that can be configured or extended to
33   * customize the way {@link javax.naming.ldap.LdapContext} objects are retrieved.</p>
34   * <p/>
35   * <p>This implementation of {@link LdapContextFactory} is used by the {@link AbstractLdapRealm} if a
36   * factory is not explictly configured.</p>
37   * <p/>
38   * <p>Connection pooling is enabled by default on this factory, but can be disabled using the
39   * {@link #usePooling} property.</p>
40   *
41   * @since 0.2
42   * @deprecated replaced by the {@link JndiLdapContextFactory} implementation.  This implementation will be removed
43   * prior to Shiro 2.0
44   */
45  @Deprecated
46  public class DefaultLdapContextFactory implements LdapContextFactory {
47  
48      //TODO - complete JavaDoc
49  
50      /*--------------------------------------------
51      |             C O N S T A N T S             |
52      ============================================*/
53      /**
54       * The Sun LDAP property used to enable connection pooling.  This is used in the default implementation
55       * to enable LDAP connection pooling.
56       */
57      protected static final String SUN_CONNECTION_POOLING_PROPERTY = "com.sun.jndi.ldap.connect.pool";
58  
59      /*--------------------------------------------
60      |    I N S T A N C E   V A R I A B L E S    |
61      ============================================*/
62  
63      private static final Logger log = LoggerFactory.getLogger(DefaultLdapContextFactory.class);
64  
65      protected String authentication = "simple";
66  
67      protected String principalSuffix = null;
68  
69      protected String searchBase = null;
70  
71      protected String contextFactoryClassName = "com.sun.jndi.ldap.LdapCtxFactory";
72  
73      protected String url = null;
74  
75      protected String referral = "follow";
76  
77      protected String systemUsername = null;
78  
79      protected String systemPassword = null;
80  
81      private boolean usePooling = true;
82  
83      private Map<String, String> additionalEnvironment;
84  
85      /*--------------------------------------------
86      |         C O N S T R U C T O R S           |
87      ============================================*/
88  
89      /*--------------------------------------------
90      |  A C C E S S O R S / M O D I F I E R S    |
91      ============================================*/
92  
93      /**
94       * Sets the type of LDAP authentication to perform when connecting to the LDAP server.  Defaults to "simple"
95       *
96       * @param authentication the type of LDAP authentication to perform.
97       */
98      public void setAuthentication(String authentication) {
99          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 }