001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.console.ldapmanager;
019
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.Enumeration;
023 import java.util.HashMap;
024 import java.util.Hashtable;
025 import java.util.List;
026 import java.util.Map;
027
028 import javax.naming.Context;
029 import javax.naming.NameClassPair;
030 import javax.naming.NamingEnumeration;
031 import javax.naming.NamingException;
032 import javax.naming.directory.Attribute;
033 import javax.naming.directory.Attributes;
034 import javax.naming.directory.DirContext;
035 import javax.naming.directory.InitialDirContext;
036 import javax.naming.directory.SearchControls;
037 import javax.naming.directory.SearchResult;
038 import javax.servlet.http.HttpSession;
039
040 import uk.ltd.getahead.dwr.WebContext;
041 import uk.ltd.getahead.dwr.WebContextFactory;
042
043 /**
044 * The LDAP manager helper
045 */
046 public class LDAPManagerHelper {
047 private final static String LDAP_VERSION_KEY = "java.naming.ldap.version";
048
049 private final static String SSL_VALUE = "ssl";
050
051 private final static String NONE_VALUE = "none";
052
053 private final static String INITIAL_CONTEXT_FACTORY_DEFAULT = "com.sun.jndi.ldap.LdapCtxFactory";
054
055 private final static String HOST_DEFAULT = "localhost";
056
057 private final static String PORT_DEFAULT = "1389";
058
059 private final static String BASE_DN_DEFAULT = "ou=system";
060
061 // LDAP Version: "3", "2"
062 private final static String LDAP_VERSION_DEFAULT = "3";
063
064 // Security Protocol: "simple", "ssl", "sasl"
065 private final static String SECURITY_PROTOCOL_DEFAULT = "simple";
066
067 // Security Authentication: "simple", "none", "strong"
068 private final static String SECURITY_AUTHENTICATION_DEFAULT = "simple";
069
070 private final static String SECURITY_PRINCIPAL_DEFAULT = "uid=admin, ou=system";
071
072 private final static String SECURITY_CREDENTIALS_DEFAULT = "secret";
073
074 private final static String ONELEVEL_SCOPE = "onelevel";
075
076 private final static String SUBTREE_SCOPE = "subtree";
077
078 private final static String DIR_CONTEXT_KEY = "LDAPManagerHelper.dirContext";
079
080 private final static String DIR_ENV_KEY = "LDAPManagerHelper.dirEnv";
081
082 private final static String HOST_KEY = "LDAPManagerHelper.host";
083
084 private final static String PORT_KEY = "LDAPManagerHelper.port";
085
086 private final static String BASE_DN_KEY = "LDAPManagerHelper.baseDN";
087
088 private final static String SUCCESS_RESULT = "<SUCCESS>";
089
090 private DirContext dirContext;
091
092 private Hashtable dirEnv;
093
094 private String host;
095
096 private String port;
097
098 private String baseDN;
099
100 /**
101 * Construct an LDAP manager helper using config data (default)
102 */
103 public LDAPManagerHelper() throws Exception {
104 dirContext = (DirContext) getSessionAttribute(DIR_CONTEXT_KEY);
105 if (dirContext == null) {
106 // TODO: Get the default values from configuration / GBean
107 String result = connect(INITIAL_CONTEXT_FACTORY_DEFAULT,
108 HOST_DEFAULT, PORT_DEFAULT, BASE_DN_DEFAULT,
109 LDAP_VERSION_DEFAULT, SECURITY_PROTOCOL_DEFAULT,
110 SECURITY_AUTHENTICATION_DEFAULT,
111 SECURITY_PRINCIPAL_DEFAULT, SECURITY_CREDENTIALS_DEFAULT);
112 if (!SUCCESS_RESULT.equalsIgnoreCase(result)) {
113 throw new Exception(result);
114 }
115 } else {
116 dirEnv = (Hashtable) getSessionAttribute(DIR_ENV_KEY);
117 host = (String) getSessionAttribute(HOST_KEY);
118 port = (String) getSessionAttribute(PORT_KEY);
119 baseDN = (String) getSessionAttribute(BASE_DN_KEY);
120 }
121 }
122
123 /**
124 * Construct an LDAP manager helper using config data (partial)
125 */
126 public LDAPManagerHelper(String host, String port, String baseDN,
127 String securityAuthentication, String userDN, String userPwd)
128 throws Exception {
129 connect(INITIAL_CONTEXT_FACTORY_DEFAULT, host, port, baseDN,
130 LDAP_VERSION_DEFAULT, SECURITY_PROTOCOL_DEFAULT,
131 securityAuthentication, userDN, userPwd);
132 }
133
134 /**
135 * Construct an LDAP manager helper using config data (all)
136 */
137 public LDAPManagerHelper(String initialContextFactory, String host,
138 String port, String baseDN, String ldapVersion,
139 String securityProtocol, String securityAuthentication,
140 String securityPrincipal, String securityCredentials)
141 throws Exception {
142 connect(initialContextFactory, host, port, baseDN, ldapVersion,
143 securityProtocol, securityAuthentication, securityPrincipal,
144 securityCredentials);
145 }
146
147 /**
148 * Create a directory context using config data
149 */
150 public synchronized String connect(String initialContextFactory,
151 String host, String port, String baseDN, String ldapVersion,
152 String securityProtocol, String securityAuthentication,
153 String securityPrincipal, String securityCredentials)
154 throws Exception {
155 String result = SUCCESS_RESULT;
156
157 Hashtable dirEnv = new Hashtable();
158 dirEnv.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
159 String providerURL = createLDAPURL(host, port, ""); // Empty Base DN
160 dirEnv.put(Context.PROVIDER_URL, providerURL);
161 dirEnv.put(LDAP_VERSION_KEY, ldapVersion);
162 if (SSL_VALUE.equalsIgnoreCase(securityProtocol)) {
163 dirEnv.put(Context.SECURITY_PROTOCOL, SSL_VALUE);
164 }
165 dirEnv.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);
166 if (!(NONE_VALUE.equalsIgnoreCase(securityAuthentication))) {
167 // Either "simple" or "strong"
168 dirEnv.put(Context.SECURITY_PRINCIPAL, securityPrincipal); // User DN
169 dirEnv.put(Context.SECURITY_CREDENTIALS, securityCredentials); // Password
170 }
171
172 try {
173 DirContext newDirContext = new InitialDirContext(dirEnv);
174 // Close old context
175 if (dirContext != null) {
176 dirContext.close();
177 }
178 // Save directory data to class vars
179 this.dirContext = newDirContext;
180 this.dirEnv = dirEnv;
181 this.host = host;
182 this.port = port;
183 this.baseDN = baseDN;
184 // Save directory data to session
185 setSessionAttribute(DIR_CONTEXT_KEY, dirContext);
186 setSessionAttribute(DIR_ENV_KEY, dirEnv);
187 setSessionAttribute(HOST_KEY, host);
188 setSessionAttribute(PORT_KEY, port);
189 setSessionAttribute(BASE_DN_KEY, baseDN);
190 } catch (NamingException e) {
191 result = "Problem connecting to directory server: "
192 + e.getMessage();
193 }
194
195 return result;
196 }
197
198 /**
199 * Return directory context environment
200 */
201 public Map getEnvironment() {
202 Map env = new HashMap();
203 env.put("host", host);
204 env.put("port", port);
205 String ldapVersion = (String) dirEnv.get(LDAP_VERSION_KEY);
206 env.put("ldapVersion", ldapVersion);
207 env.put("baseDN", baseDN);
208 String securityProtocol = (String) dirEnv
209 .get(Context.SECURITY_PROTOCOL);
210 env.put("securityProtocol", securityProtocol);
211 String securityAuthentication = (String) dirEnv
212 .get(Context.SECURITY_AUTHENTICATION);
213 env.put("securityAuthentication", securityAuthentication);
214 String securityPrincipal = (String) dirEnv
215 .get(Context.SECURITY_PRINCIPAL);
216 env.put("securityPrincipal", securityPrincipal);
217
218 return env;
219 }
220
221 /**
222 * Returns the names bound in the named context
223 */
224 public Collection list(String name) throws Exception {
225 ArrayList result = new ArrayList();
226
227 try {
228 NamingEnumeration list = dirContext.list(name); // can't be ""
229
230 while (list.hasMore()) {
231 NameClassPair ncp = (NameClassPair) list.next();
232 String childName = ncp.getName();
233 String dn = childName + ", " + name;
234 String[] pair = { childName, dn };
235 result.add(pair);
236 }
237 } catch (NamingException e) {
238 throw new Exception("Problem getting directory list: "
239 + e.getMessage());
240 }
241
242 return result;
243 }
244
245 /**
246 * Returns the names bound in the base DN context
247 */
248 public Collection listBaseDN() throws Exception {
249 return list(baseDN);
250 }
251
252 /**
253 * Enumerates the names bound in the named context and return result as JSON
254 */
255 public String listJSON(String name) throws Exception {
256 return listJSON(name, null);
257 }
258
259 /**
260 * Enumerates the names bound in the named context and return result as JSON
261 */
262 public String listJSON(String name, String commonFields) throws Exception {
263 // JSON: [{title:"Title1",isFolder:true}, {title:"Title2"}]
264
265 StringBuffer json = new StringBuffer();
266 List list = (List) list(name);
267
268 json.append('[');
269 int size = list.size();
270 for (int i = 0; i < size; i++) {
271 String[] entry = (String[]) list.get(i);
272 json.append("{title:\"");
273 json.append(entry[0]);
274 json.append("\",widgetId:\"");
275 json.append(entry[1]);
276 json.append("\"");
277 if (commonFields != null) { // TODO: Do additional testing
278 json.append(commonFields);
279 }
280 json.append("}");
281 if ((i + 1) < size) {
282 json.append(',');
283 }
284 }
285 json.append("]");
286
287 return json.toString();
288 }
289
290 /**
291 * Return the attributes of an LDAP entry
292 */
293 public Collection getAttributes(String name) throws Exception {
294 ArrayList result = new ArrayList();
295 try {
296 Attributes attribs = dirContext.getAttributes(name);
297 NamingEnumeration attributes = attribs.getAll();
298 while (attributes.hasMore()) {
299 Attribute attribute = (Attribute) attributes.next();
300 String id = attribute.getID();
301 NamingEnumeration values = attribute.getAll();
302 while (values.hasMore()) {
303 String value = values.next().toString();
304 String[] pair = { id, value };
305 result.add(pair);
306 }
307 }
308 } catch (NamingException e) {
309 throw new Exception("Problem retrieving attributes: "
310 + e.getMessage());
311 }
312 return result;
313 }
314
315 /**
316 * Execute an LDAP search
317 */
318 public Collection search(String searchDN, String filter, String searchScope)
319 throws Exception {
320 ArrayList result = new ArrayList();
321 try {
322 String ldapURL = createLDAPURL(host, port, searchDN);
323 SearchControls sc = new SearchControls();
324 if (ONELEVEL_SCOPE.equalsIgnoreCase(searchScope)) {
325 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);
326 } else if (SUBTREE_SCOPE.equalsIgnoreCase(searchScope)) {
327 sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
328 } else {
329 // Default to one level scope
330 sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);
331 }
332 // Filter: "(objectclass=*)"
333 boolean isSearchDNAdded = false;
334 NamingEnumeration ne = dirContext.search(ldapURL, filter, sc);
335 while (ne.hasMore()) {
336 SearchResult sr = (SearchResult) ne.next();
337 String name = sr.getName();
338 String dn = null;
339 if (name.length() > 0) {
340 dn = name + "," + searchDN;
341 result.add(dn);
342 } else if ((name.length() == 0) && !isSearchDNAdded) {
343 dn = searchDN;
344 result.add(dn);
345 isSearchDNAdded = true;
346 }
347 }
348 } catch (NamingException e) {
349 throw new Exception("Problem performing directory search: "
350 + e.getMessage());
351 }
352 return result;
353 }
354
355 /**
356 * Close directory context
357 */
358 public void close() throws Exception {
359 try {
360 dirContext.close();
361 } catch (NamingException e) {
362 throw new Exception("Problem closing directory context: "
363 + e.getMessage());
364 }
365 }
366
367 /**
368 * Return base DN of this directory context
369 */
370 public String getBaseDN() {
371 return baseDN;
372 }
373
374 /**
375 * Create an LDAP url using host, port, and base DN
376 */
377 private String createLDAPURL(String host, String port, String baseDN) {
378 StringBuffer url = new StringBuffer();
379 url.append("ldap://");
380 url.append(host);
381 url.append(':');
382 url.append(port);
383 if ((baseDN != null) && (baseDN.length() >= 3)) {
384 if (!baseDN.startsWith("/")) {
385 url.append('/');
386 }
387 url.append(baseDN);
388 }
389 return url.toString();
390 }
391
392 /**
393 * Get the HTTP session
394 */
395 private HttpSession getSession() {
396 WebContext ctx = WebContextFactory.get();
397 HttpSession session = ctx.getSession();
398 return session;
399 }
400
401 /**
402 * Set an HTTP session attribute
403 */
404 private void setSessionAttribute(String name, Object value) {
405 getSession().setAttribute(name, value);
406 }
407
408 /**
409 * Get an HTTP session attribute
410 */
411 private Object getSessionAttribute(String name) {
412 return getSession().getAttribute(name);
413 }
414
415 /**
416 * Dump HTTP session attributes
417 */
418 private void dumpSession() {
419 System.out.println("--- dumpSession()");
420 WebContext ctx = WebContextFactory.get();
421 HttpSession session = ctx.getSession();
422 Enumeration attribNames = session.getAttributeNames();
423 while (attribNames.hasMoreElements()) {
424 String attribName = (String) attribNames.nextElement();
425 System.out.print("--- session: " + attribName + " = ");
426 Object attribValue = session.getAttribute(attribName);
427 System.out.println(attribValue);
428 }
429 }
430
431 /**
432 * Dump search enumeration
433 */
434 private void printSearchEnumeration(NamingEnumeration ne) {
435 try {
436 while (ne.hasMore()) {
437 SearchResult sr = (SearchResult) ne.next();
438 System.out.println("-->" + sr.getName());
439 System.out.println(sr.getAttributes());
440 }
441 } catch (NamingException e) {
442 e.printStackTrace();
443 }
444 }
445
446 }