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