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 }