KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > security > auth > realm > ldap > LDAPRealm


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.security.auth.realm.ldap;
25
26 import java.util.*;
27 import java.util.logging.Logger JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import javax.naming.Context JavaDoc;
30 import com.sun.logging.LogDomains;
31
32 import com.sun.enterprise.security.acl.RoleMapper;
33 import com.sun.enterprise.security.auth.realm.User;
34 import com.sun.enterprise.security.auth.realm.Realm;
35 import com.sun.enterprise.security.auth.realm.BadRealmException;
36 import com.sun.enterprise.security.auth.realm.NoSuchUserException;
37 import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
38 import com.sun.enterprise.security.auth.realm.AuthenticationHandler;
39 import com.sun.enterprise.security.auth.realm.InvalidOperationException;
40
41 import com.sun.enterprise.security.RealmConfig;
42 import com.sun.enterprise.security.auth.realm.IASRealm;
43
44
45 /**
46  * Realm wrapper for supporting LDAP authentication.
47  *
48  * <P>See LDAPLoginModule documentation for more details on the operation
49  * of the LDAP realm and login module.
50  *
51  * <P>The ldap realm needs the following properties in its configuration:
52  * <ul>
53  * <li>directory - URL of LDAP directory to use
54  * <li>base-dn - The base DN to use for user searches.
55  * <li>jaas-ctx - JAAS context name used to access LoginModule for
56  * authentication.
57  * </ul>
58  *
59  * <P>Besides JDK Context properties start with java.naming, javax.security,
60  * one can also set connection pool related properties starting with
61  * com.sun.jndi.ldap.connect.pool.
62  * See http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html
63  * for details.
64  * Also, the following optional attributes can also be specified:
65  * <ul>
66  * <li>search-filter - LDAP filter to use for searching for the user
67  * entry based on username given to iAS. The default value is
68  * <code>uid=%s</code> where %s is expanded to the username.
69  * <li>group-base-dn - The base DN to use for group searches. By default
70  * its value is the same as base-dn.
71  * <li>group-search-filter - The LDAP filter to use for searching group
72  * membership of a given user. The default value is <code>
73  * uniquemember=%d</code> where %d is expanded to the DN of the
74  * user found by the user search.
75  * <li>group-target - The attribute which value(s) are interpreted as
76  * group membership names of the user. Default value is <code>cn</code>.
77  * <li>search-bind-dn - The dn of ldap user. optional and no default value.
78  * <li>search-bind-password - The password of search-bind-dn.optional and
79  * no default value.
80  * <li>pool-size - The JNDI ldap connection pool size.
81  * </ul>
82  *
83  * @see com.sun.enterprise.security.auth.login.LDAPLoginModule
84  *
85  */

86 public final class LDAPRealm extends IASRealm
87 {
88     // Descriptive string of the authentication type of this realm.
89
public static final String JavaDoc AUTH_TYPE = "ldap";
90
91     // These are property names which should be in auth-realm in server.xml
92
public static final String JavaDoc PARAM_DIRURL="directory";
93     public static final String JavaDoc PARAM_USERDN="base-dn";
94    
95     // These are optional, defaults are provided
96
// %s = subject name
97
// %d = DN of user search result
98
public static final String JavaDoc PARAM_SEARCH_FILTER="search-filter";
99     public static final String JavaDoc PARAM_GRPDN="group-base-dn";
100     public static final String JavaDoc PARAM_GRP_SEARCH_FILTER="group-search-filter";
101     public static final String JavaDoc PARAM_GRP_TARGET="group-target";
102     public static final String JavaDoc PARAM_MODE="mode";
103     public static final String JavaDoc PARAM_JNDICF="jndiCtxFactory";
104     public static final String JavaDoc PARAM_POOLSIZE="pool-size";
105     
106     // These are optional, no default values are provided
107
public static final String JavaDoc PARAM_BINDDN="search-bind-dn";
108     public static final String JavaDoc PARAM_BINDPWD="search-bind-password";
109
110     // Only find-bind mode is supported so mode attribute is not exposed yet
111
public static final String JavaDoc MODE_FIND_BIND="find-bind";
112
113     // Expansion strings
114
public static final String JavaDoc SUBST_SUBJECT_NAME="%s";
115     public static final String JavaDoc SUBST_SUBJECT_DN="%d";
116
117     // Defaults
118
private static final String JavaDoc SEARCH_FILTER_DEFAULT=
119                                      "uid="+SUBST_SUBJECT_NAME;
120     private static final String JavaDoc GRP_SEARCH_FILTER_DEFAULT=
121                                      "uniquemember="+SUBST_SUBJECT_DN;
122     private static final String JavaDoc GRP_TARGET_DEFAULT="cn";
123     private static final String JavaDoc MODE_DEFAULT=MODE_FIND_BIND;
124     private static final String JavaDoc JNDICF_DEFAULT=
125                                      "com.sun.jndi.ldap.LdapCtxFactory";
126     private static final int POOLSIZE_DEFAULT=5;
127     
128     private static final String JavaDoc SUN_JNDI_POOL = "com.sun.jndi.ldap.connect.pool";
129     private static final String JavaDoc SUN_JNDI_POOL_ = "com.sun.jndi.ldap.connect.pool.";
130     private static final String JavaDoc SUN_JNDI_POOL_MAXSIZE = "com.sun.jndi.ldap.connect.pool.maxsize";
131     // dynamic group related properties.
132
private static final String JavaDoc DYNAMIC_GROUP_OBJECT_FACTORY =
133                                         "com.sun.jndi.ldap.obj.LdapGroupFactory";
134     public static final String JavaDoc DYNAMIC_GROUP_FACTORY_OBJECT_PROPERTY =
135                                         "java.naming.factory.object";
136     private static final String JavaDoc DYNAMIC_GROUP_STATE_FACTORY =
137                                         "com.sun.jndi.ldap.obj.LdapGroupFactory";
138     public static final String JavaDoc DYNAMIC_GROUP_STATE_FACTORY_PROPERTY =
139                                         "java.naming.factory.state";
140     
141     public static final String JavaDoc DYNAMIC_GROUP_FILTER =
142                 "(&(objectclass=groupofuniquenames)(objectclass=*groupofurls*))";
143     
144     private HashMap groupCache;
145     private Vector emptyVector;
146     private Properties ldapBindProps = new Properties();
147
148     /**
149      * Initialize a realm with some properties. This can be used
150      * when instantiating realms from their descriptions. This
151      * method may only be called a single time.
152      *
153      * @param props Initialization parameters used by this realm.
154      * @exception BadRealmException If the configuration parameters
155      * identify a corrupt realm.
156      * @exception NoSuchRealmException If the configuration parameters
157      * specify a realm which doesn't exist.
158      *
159      */

160     public synchronized void init(Properties props)
161         throws BadRealmException, NoSuchRealmException
162     {
163         String JavaDoc url = props.getProperty(PARAM_DIRURL);
164         this.setProperty(PARAM_DIRURL, url);
165         ldapBindProps.setProperty(Context.PROVIDER_URL, url);
166         
167         String JavaDoc dn = props.getProperty(PARAM_USERDN);
168         this.setProperty(PARAM_USERDN, dn);
169
170         String JavaDoc jaasCtx = props.getProperty(IASRealm.JAAS_CONTEXT_PARAM);
171         this.setProperty(IASRealm.JAAS_CONTEXT_PARAM, jaasCtx);
172         
173         if (url==null || dn==null || jaasCtx==null) {
174             String JavaDoc msg = sm.getString("ldaprealm.badconfig", url, dn, jaasCtx);
175             throw new BadRealmException(msg);
176         }
177
178         String JavaDoc mode = props.getProperty(PARAM_MODE, MODE_DEFAULT);
179         if (!MODE_DEFAULT.equals(mode)) {
180             String JavaDoc msg = sm.getString("ldaprealm.badmode", mode);
181             throw new BadRealmException(msg);
182         }
183         this.setProperty(PARAM_MODE, mode);
184
185         String JavaDoc ctxF = props.getProperty(PARAM_JNDICF, JNDICF_DEFAULT);
186         this.setProperty(PARAM_JNDICF, ctxF);
187         ldapBindProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, ctxF);
188
189         String JavaDoc searchFilter = props.getProperty(
190                 PARAM_SEARCH_FILTER, SEARCH_FILTER_DEFAULT);
191         this.setProperty(PARAM_SEARCH_FILTER,searchFilter);
192
193         String JavaDoc grpDN = props.getProperty(PARAM_GRPDN, dn);
194         this.setProperty(PARAM_GRPDN, grpDN);
195
196         String JavaDoc grpSearchFilter = props.getProperty(
197                 PARAM_GRP_SEARCH_FILTER, GRP_SEARCH_FILTER_DEFAULT);
198         this.setProperty(PARAM_GRP_SEARCH_FILTER, grpSearchFilter);
199
200         String JavaDoc grpTarget = props.getProperty(
201                 PARAM_GRP_TARGET, GRP_TARGET_DEFAULT);
202         this.setProperty(PARAM_GRP_TARGET, grpTarget);
203
204         String JavaDoc objectFactory = props.getProperty(
205                 DYNAMIC_GROUP_FACTORY_OBJECT_PROPERTY, DYNAMIC_GROUP_OBJECT_FACTORY);
206         this.setProperty(DYNAMIC_GROUP_FACTORY_OBJECT_PROPERTY, objectFactory);
207         ldapBindProps.setProperty(DYNAMIC_GROUP_FACTORY_OBJECT_PROPERTY, objectFactory);
208
209         String JavaDoc stateFactory = props.getProperty(
210                 DYNAMIC_GROUP_STATE_FACTORY_PROPERTY, DYNAMIC_GROUP_STATE_FACTORY);
211         this.setProperty(DYNAMIC_GROUP_STATE_FACTORY_PROPERTY, stateFactory);
212         ldapBindProps.setProperty(DYNAMIC_GROUP_STATE_FACTORY_PROPERTY, stateFactory);
213
214         String JavaDoc bindDN = props.getProperty(PARAM_BINDDN);
215         if (bindDN != null) {
216             this.setProperty(PARAM_BINDDN, bindDN);
217             ldapBindProps.setProperty(Context.SECURITY_PRINCIPAL, bindDN);
218         }
219         String JavaDoc bindPWD = props.getProperty(PARAM_BINDPWD);
220         if (bindPWD != null) {
221             this.setProperty(PARAM_BINDPWD, bindPWD);
222             ldapBindProps.setProperty(Context.SECURITY_CREDENTIALS, bindPWD);
223         }
224
225         Enumeration penum = props.propertyNames();
226         while (penum.hasMoreElements()) {
227             String JavaDoc propName = (String JavaDoc)penum.nextElement();
228             if (propName.startsWith("java.naming.") ||
229                     propName.startsWith("javax.security.")) {
230                 ldapBindProps.setProperty(propName, props.getProperty(propName));
231             } else if (propName.startsWith(SUN_JNDI_POOL_) &&
232                     !SUN_JNDI_POOL_MAXSIZE.equals(propName)) {
233                 if (System.getProperty(propName) == null) {
234                     System.setProperty(propName, props.getProperty(propName));
235                 }
236             }
237         }
238
239         String JavaDoc poolSize =
240             Integer.getInteger(PARAM_POOLSIZE,POOLSIZE_DEFAULT).toString();
241         String JavaDoc sunPoolSizeStr = props.getProperty(SUN_JNDI_POOL_MAXSIZE,
242             poolSize);
243         //Precedence rule: SUN_JNDI_POOL_MAXSIZE > PARAM_POOLSIZE > POOLSIZE_DEFAULT
244
try {
245             sunPoolSizeStr = Integer.valueOf(sunPoolSizeStr).toString();
246         } catch(Exception JavaDoc ex) {
247             sunPoolSizeStr = poolSize;
248         }
249         if (System.getProperty(SUN_JNDI_POOL_MAXSIZE) == null) {
250             System.setProperty(SUN_JNDI_POOL_MAXSIZE, sunPoolSizeStr);
251         }
252         this.setProperty(PARAM_POOLSIZE, sunPoolSizeStr);
253
254         String JavaDoc usePool = props.getProperty(SUN_JNDI_POOL, "true");
255         ldapBindProps.setProperty(SUN_JNDI_POOL, usePool);
256
257         if (_logger.isLoggable(Level.FINE)) {
258             Properties tempProps = (Properties)ldapBindProps.clone();
259             tempProps.remove(Context.SECURITY_CREDENTIALS);
260             _logger.log(Level.FINE, "LDAPRealm : " + tempProps);
261         }
262
263         groupCache = new HashMap();
264         emptyVector = new Vector();
265     }
266
267
268     /**
269      * Returns a short (preferably less than fifteen characters) description
270      * of the kind of authentication which is supported by this realm.
271      *
272      * @return Description of the kind of authentication that is directly
273      * supported by this realm.
274      */

275     public String JavaDoc getAuthType()
276     {
277         return AUTH_TYPE;
278     }
279     
280
281
282     /**
283      * Get binding properties defined in server.xml for LDAP server.
284      *
285      */

286     public Properties getLdapBindProps()
287     {
288         return (Properties)ldapBindProps.clone();
289     }
290
291
292     /**
293      * Returns the name of all the groups that this user belongs to.
294      * Note that this information is only known after the user has
295      * logged in. This is called from web path role verification, though
296      * it should not be.
297      *
298      * @param username Name of the user in this realm whose group listing
299      * is needed.
300      * @return Enumeration of group names (strings).
301      * @exception InvalidOperationException thrown if the realm does not
302      * support this operation - e.g. Certificate realm does not support
303      * this operation.
304      */

305     public Enumeration getGroupNames (String JavaDoc username)
306         throws InvalidOperationException, NoSuchUserException
307     {
308         Vector v = (Vector)groupCache.get(username);
309         if (v == null) {
310             if (_logger.isLoggable(Level.FINE)) {
311                 _logger.log(Level.FINE, "No groups available for: "+username);
312             }
313             return emptyVector.elements();
314         } else {
315             return v.elements();
316         }
317     }
318
319
320     /**
321      * Set group membership info for a user.
322      *
323      * <P>See bugs 4646133,4646270 on why this is here.
324      *
325      */

326     public void setGroupNames(String JavaDoc username, String JavaDoc[] groups)
327     {
328         Vector v = new Vector(groups.length);
329         for (int i=0; i<groups.length; i++) {
330             v.add(groups[i]);
331         }
332         groupCache.put(username, v);
333     }
334
335
336     
337 }
338
Popular Tags