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 }