Frames | No Frames |
1: /* Sasl.java -- 2: Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.security.sasl; 40: 41: import java.security.Provider; 42: import java.security.Security; 43: import java.util.Enumeration; 44: import java.util.HashSet; 45: import java.util.Iterator; 46: import java.util.Map; 47: import java.util.Vector; 48: 49: import javax.security.auth.callback.CallbackHandler; 50: 51: /** 52: * <p>A static class for creating SASL clients and servers.</p> 53: * 54: * <p>This class defines the policy of how to locate, load, and instantiate SASL 55: * clients and servers.</p> 56: * 57: * <p>For example, an application or library gets a SASL client instance by 58: * doing something like:</p> 59: * 60: * <pre> 61: *SaslClient sc = 62: * Sasl.createSaslClient(mechanisms, authorizationID, protocol, 63: * serverName, props, callbackHandler); 64: * </pre> 65: * 66: * <p>It can then proceed to use the instance to create an authenticated 67: * connection.</p> 68: * 69: * <p>Similarly, a server gets a SASL server instance by using code that looks 70: * as follows:</p> 71: * 72: * <pre> 73: *SaslServer ss = 74: * Sasl.createSaslServer(mechanism, protocol, serverName, props, 75: * callbackHandler); 76: * </pre> 77: * 78: * @since 1.5 79: */ 80: public class Sasl 81: { 82: 83: // Constants and variables 84: // ------------------------------------------------------------------------- 85: 86: /** 87: * <p>The name of a property that specifies the quality-of-protection to use. 88: * The property contains a comma-separated, ordered list of quality-of- 89: * protection values that the client or server is willing to support. A qop 90: * value is one of:</p> 91: * 92: * <ul> 93: * <li><code>"auth"</code> - authentication only,</li> 94: * <li><code>"auth-int"</code> - authentication plus integrity 95: * protection,</li> 96: * <li><code>"auth-conf"</code> - authentication plus integrity and 97: * confidentiality protection.</li> 98: * </ul> 99: * 100: * <p>The order of the list specifies the preference order of the client or 101: * server.</p> 102: * 103: * <p>If this property is absent, the default qop is <code>"auth"</code>.</p> 104: * 105: * <p>The value of this constant is <code>"javax.security.sasl.qop"</code>.</p> 106: */ 107: public static final String QOP = "javax.security.sasl.qop"; 108: 109: /** 110: * <p>The name of a property that specifies the cipher strength to use. The 111: * property contains a comma-separated, ordered list of cipher strength 112: * values that the client or server is willing to support. A strength value 113: * is one of:</p> 114: * 115: * <ul> 116: * <li><code>"low"</code>,</li> 117: * <li><code>"medium"</code>,</li> 118: * <li><code>"high"</code>.</li> 119: * </ul> 120: * 121: * <p>The order of the list specifies the preference order of the client or 122: * server. An implementation should allow configuration of the meaning of 123: * these values. An application may use the Java Cryptography Extension (JCE) 124: * with JCE-aware mechanisms to control the selection of cipher suites that 125: * match the strength values.</p> 126: * 127: * <p>If this property is absent, the default strength is 128: * <code>"high,medium,low"</code>.</p> 129: * 130: * <p>The value of this constant is <code>"javax.security.sasl.strength"</code>. 131: * </p> 132: */ 133: public static final String STRENGTH = "javax.security.sasl.strength"; 134: 135: /** 136: * <p>The name of a property that specifies whether the server must authenticate 137: * to the client. The property contains <code>"true"</code> if the server 138: * must authenticate the to client; <code>"false"</code> otherwise. The 139: * default is <code>"false"</code>.</p> 140: * 141: * <p>The value of this constant is 142: * <code>"javax.security.sasl.server.authentication"</code>.</p> 143: */ 144: public static final String SERVER_AUTH = "javax.security.sasl.server.authentication"; 145: 146: /** 147: * <p>The name of a property that specifies the maximum size of the receive 148: * buffer in bytes of {@link SaslClient}/{@link SaslServer}. The property 149: * contains the string representation of an integer.</p> 150: * 151: * <p>If this property is absent, the default size is defined by the 152: * mechanism.</p> 153: * 154: * <p>The value of this constant is <code>"javax.security.sasl.maxbuffer"</code>. 155: * </p> 156: */ 157: public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer"; 158: 159: /** 160: * <p>The name of a property that specifies the maximum size of the raw send 161: * buffer in bytes of {@link SaslClient}/{@link SaslServer}. The property 162: * contains the string representation of an integer. The value of this 163: * property is negotiated between the client and server during the 164: * authentication exchange.</p> 165: * 166: * <p>The value of this constant is <code>"javax.security.sasl.rawsendsize"</code>. 167: * </p> 168: */ 169: public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize"; 170: 171: /** 172: * <p>The name of a property that specifies whether mechanisms susceptible 173: * to simple plain passive attacks (e.g., "PLAIN") are not permitted. The 174: * property contains <code>"true"</code> if such mechanisms are not 175: * permitted; <code>"false"</code> if such mechanisms are permitted. The 176: * default is <code>"false"</code>.</p> 177: * 178: * <p>The value of this constant is <code>"javax.security.sasl.policy.noplaintext"</code>. 179: * </p> 180: */ 181: public static final String POLICY_NOPLAINTEXT = "javax.security.sasl.policy.noplaintext"; 182: 183: /** 184: * <p>The name of a property that specifies whether mechanisms susceptible to 185: * active (non-dictionary) attacks are not permitted. The property contains 186: * <code>"true"</code> if mechanisms susceptible to active attacks are not 187: * permitted; <code>"false"</code> if such mechanisms are permitted. The 188: * default is <code>"false"</code>.</p> 189: * 190: * <p>The value of this constant is <code>"javax.security.sasl.policy.noactive"</code>. 191: * </p> 192: */ 193: public static final String POLICY_NOACTIVE = "javax.security.sasl.policy.noactive"; 194: 195: /** 196: * <p>The name of a property that specifies whether mechanisms susceptible to 197: * passive dictionary attacks are not permitted. The property contains 198: * <code>"true"</code> if mechanisms susceptible to dictionary attacks are 199: * not permitted; <code>"false"</code> if such mechanisms are permitted. The 200: * default is <code>"false"</code>.</p> 201: * 202: * <p>The value of this constant is <code>"javax.security.sasl.policy.nodictionary"</code>. 203: * </p> 204: */ 205: public static final String POLICY_NODICTIONARY = "javax.security.sasl.policy.nodictionary"; 206: 207: /** 208: * <p>The name of a property that specifies whether mechanisms that accept 209: * anonymous login are not permitted. The property contains <code>"true"</code> 210: * if mechanisms that accept anonymous login are not permitted; <code>"false" 211: * </code> if such mechanisms are permitted. The default is <code>"false"</code>. 212: * </p> 213: * 214: * <p>The value of this constant is <code>"javax.security.sasl.policy.noanonymous"</code>. 215: * </p> 216: */ 217: public static final String POLICY_NOANONYMOUS = "javax.security.sasl.policy.noanonymous"; 218: 219: /** 220: * The name of a property that specifies whether mechanisms that implement 221: * forward secrecy between sessions are required. Forward secrecy means that 222: * breaking into one session will not automatically provide information for 223: * breaking into future sessions. The property contains <code>"true"</code> 224: * if mechanisms that implement forward secrecy between sessions are 225: * required; <code>"false"</code> if such mechanisms are not required. The 226: * default is <code>"false"</code>. 227: * 228: * <p>The value of this constant is <code>"javax.security.sasl.policy.forward"</code>. 229: * </p> 230: */ 231: public static final String POLICY_FORWARD_SECRECY = "javax.security.sasl.policy.forward"; 232: 233: /** 234: * The name of a property that specifies whether mechanisms that pass client 235: * credentials are required. The property contains <code>"true"</code> if 236: * mechanisms that pass client credentials are required; <code>"false"</code> 237: * if such mechanisms are not required. The default is <code>"false"</code>. 238: * 239: * <p>The value of this constant is <code>"javax.security.sasl.policy.credentials"</code>. 240: * </p> 241: */ 242: public static final String POLICY_PASS_CREDENTIALS = "javax.security.sasl.policy.credentials"; 243: 244: /** 245: * <p>The name of a property that specifies whether to reuse previously 246: * authenticated session information. The property contains <code>"true"</code> 247: * if the mechanism implementation may attempt to reuse previously 248: * authenticated session information; it contains <code>"false"</code> if the 249: * implementation must not reuse previously authenticated session information. 250: * A setting of <code>"true"</code> serves only as a hint; it does not 251: * necessarily entail actual reuse because reuse might not be possible due to 252: * a number of reasons, including, but not limited to, lack of mechanism 253: * support for reuse, expiration of reusable information, and the peer's 254: * refusal to support reuse. The property's default value is <code>"false"</code>. 255: * </p> 256: * 257: * <p>The value of this constant is <code>"javax.security.sasl.reuse"</code>. 258: * Note that all other parameters and properties required to create a SASL 259: * client/server instance must be provided regardless of whether this 260: * property has been supplied. That is, you cannot supply any less 261: * information in anticipation of reuse. Mechanism implementations that 262: * support reuse might allow customization of its implementation for factors 263: * such as cache size, timeouts, and criteria for reuseability. Such 264: * customizations are implementation-dependent.</p> 265: */ 266: public static final String REUSE = "javax.security.sasl.reuse"; 267: 268: /** 269: * <p>The name of a property which specifies the credentials to use. 270: * The value of the property is a mechanism-specific object which can 271: * be used to supply credentials to a mechanism which provides delegated 272: * authentication.</p> 273: * 274: * <p>The value of this constant is <code>"javax.security.sasl.credentials"</code>.</p> 275: */ 276: public static final String CREDENTIALS = "javax.security.sasl.credentials"; 277: 278: private static final String CLIENT_FACTORY_SVC = "SaslClientFactory."; 279: private static final String SERVER_FACTORY_SVC = "SaslServerFactory."; 280: private static final String ALIAS = "Alg.Alias."; 281: 282: // Constructor(s) 283: // ------------------------------------------------------------------------- 284: 285: private Sasl() 286: { 287: super(); 288: } 289: 290: // Class methods 291: // ------------------------------------------------------------------------- 292: 293: /** 294: * Creates a {@link SaslClient} for the specified mechanism. 295: * 296: * <p>This method uses the JCA Security Provider Framework, described in the 297: * "Java Cryptography Architecture API Specification & Reference", for 298: * locating and selecting a {@link SaslClient} implementation.</p> 299: * 300: * <p>First, it obtains an ordered list of {@link SaslClientFactory} 301: * instances from the registered security providers for the 302: * <code>"SaslClientFactory"</code> service and the specified mechanism. It 303: * then invokes <code>createSaslClient()</code> on each factory instance on 304: * the list until one produces a non-null {@link SaslClient} instance. It 305: * returns the non-null {@link SaslClient} instance, or <code>null</code> if 306: * the search fails to produce a non-null {@link SaslClient} instance.</p> 307: * 308: * <p>A security provider for <code>SaslClientFactory</code> registers with 309: * the JCA Security Provider Framework keys of the form:</p> 310: * 311: * <pre> 312: * SaslClientFactory.mechanism_name 313: * </pre> 314: * 315: * <p>and values that are class names of implementations of {@link 316: * SaslClientFactory}.</p> 317: * 318: * <p>For example, a provider that contains a factory class, 319: * <code>com.wiz.sasl.digest.ClientFactory</code>, that supports the 320: * <code>"DIGEST-MD5"</code> mechanism would register the following entry 321: * with the JCA:</p> 322: * 323: * <pre> 324: * SaslClientFactory.DIGEST-MD5 com.wiz.sasl.digest.ClientFactory 325: * </pre> 326: * 327: * <p>See the "Java Cryptography Architecture API Specification & 328: * Reference" for information about how to install and configure security 329: * service providers.</p> 330: * 331: * @param mechanisms the non-null list of mechanism names to try. Each is the 332: * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5"). 333: * @param authorizationID the possibly <code>null</code> protocol-dependent 334: * identification to be used for authorization. If <code>null</code> or 335: * empty, the server derives an authorization ID from the client's 336: * authentication credentials. When the SASL authentication completes 337: * successfully, the specified entity is granted access. 338: * @param protocol the non-null string name of the protocol for which the 339: * authentication is being performed (e.g. "ldap"). 340: * @param serverName the non-null fully-qualified host name of the server to 341: * authenticate to. 342: * @param props the possibly null set of properties used to select the SASL 343: * mechanism and to configure the authentication exchange of the selected 344: * mechanism. For example, if props contains the {@link Sasl#POLICY_NOPLAINTEXT} 345: * property with the value <code>"true"</code>, then the selected SASL 346: * mechanism must not be susceptible to simple plain passive attacks. In 347: * addition to the standard properties declared in this class, other, 348: * possibly mechanism-specific, properties can be included. Properties not 349: * relevant to the selected mechanism are ignored. 350: * @param cbh the possibly <code>null</code> callback handler to used by the 351: * SASL mechanisms to get further information from the application/library to 352: * complete the authentication. For example, a SASL mechanism might require 353: * the authentication ID, password and realm from the caller. The 354: * authentication ID is requested by using a 355: * {@link javax.security.auth.callback.NameCallback}. The password is 356: * requested by using a {@link javax.security.auth.callback.PasswordCallback}. 357: * The realm is requested by using a {@link RealmChoiceCallback} if there is 358: * a list of realms to choose from, and by using a {@link RealmCallback} if 359: * the realm must be entered. 360: * @return a possibly <code>null</code> {@link SaslClient} created using the 361: * parameters supplied. If <code>null</code>, the method could not find a 362: * {@link SaslClientFactory} that will produce one. 363: * @throws SaslException if a {@link SaslClient} cannot be created because 364: * of an error. 365: */ 366: public static SaslClient createSaslClient(String[] mechanisms, 367: String authorizationID, 368: String protocol, 369: String serverName, 370: Map<String, ?> props, 371: CallbackHandler cbh) 372: throws SaslException 373: { 374: if (mechanisms == null) 375: { 376: return null; 377: } 378: Provider[] providers = Security.getProviders(); 379: if (providers == null || providers.length == 0) 380: { 381: return null; 382: } 383: 384: SaslClient result = null; 385: SaslClientFactory factory = null; 386: String m, clazz = null, upper, alias; 387: int j; 388: Provider p; 389: for (int i = 0; i < mechanisms.length; i++) 390: { 391: m = mechanisms[i]; 392: if (m == null) 393: continue; 394: for (j = 0; j < providers.length; j++) 395: { 396: p = providers[j]; 397: if (p != null) 398: { 399: // try the name as is 400: clazz = p.getProperty(CLIENT_FACTORY_SVC + m); 401: if (clazz == null) // try all uppercase 402: { 403: upper = m.toUpperCase(); 404: clazz = p.getProperty(CLIENT_FACTORY_SVC + upper); 405: if (clazz == null) // try if it's an alias 406: { 407: alias = p.getProperty(ALIAS + CLIENT_FACTORY_SVC + m); 408: if (alias == null) // try all-uppercase alias name 409: { 410: alias = p.getProperty(ALIAS + CLIENT_FACTORY_SVC + upper); 411: if (alias == null) // spit the dummy 412: continue; 413: } 414: clazz = p.getProperty(CLIENT_FACTORY_SVC + alias); 415: } 416: } 417: if (clazz == null) 418: continue; 419: else 420: clazz = clazz.trim(); 421: } 422: 423: try 424: { 425: result = null; 426: factory = (SaslClientFactory) Class.forName(clazz).newInstance(); 427: result = factory.createSaslClient(mechanisms, authorizationID, 428: protocol, serverName, props, cbh); 429: } 430: catch (ClassCastException ignored) // ignore instantiation exceptions 431: { 432: } 433: catch (ClassNotFoundException ignored) 434: { 435: } 436: catch (InstantiationException ignored) 437: { 438: } 439: catch (IllegalAccessException ignored) 440: { 441: } 442: if (result != null) 443: return result; 444: } 445: } 446: return null; 447: } 448: 449: /** 450: * Gets an enumeration of known factories for producing a {@link SaslClient} 451: * instance. This method uses the same sources for locating factories as 452: * <code>createSaslClient()</code>. 453: * 454: * @return a non-null {@link Enumeration} of known factories for producing a 455: * {@link SaslClient} instance. 456: * @see #createSaslClient(String[],String,String,String,Map,CallbackHandler) 457: */ 458: public static Enumeration<SaslClientFactory> getSaslClientFactories() 459: { 460: Vector result = new Vector(); 461: HashSet names = new HashSet(); 462: Provider[] providers = Security.getProviders(); 463: Iterator it; 464: if (providers != null) 465: { 466: Provider p; 467: String key; 468: for (int i = 0; i < providers.length; i++) 469: { 470: p = providers[i]; 471: for (it = p.keySet().iterator(); it.hasNext(); ) 472: { 473: key = (String) it.next(); 474: // add key's binding (a) it is a class of a client factory, 475: // and (b) the key does not include blanks 476: if (key.startsWith(CLIENT_FACTORY_SVC) && key.indexOf(" ") == -1) 477: { 478: names.add(p.getProperty(key)); 479: break; 480: } 481: } 482: } 483: } 484: // we have the factory class names in names; instantiate and enumerate 485: String c; 486: for (it = names.iterator(); it.hasNext(); ) 487: { 488: c = (String) it.next(); 489: try 490: { 491: SaslClientFactory f = (SaslClientFactory) Class.forName(c).newInstance(); 492: if (f != null) 493: result.add(f); 494: } catch (ClassCastException ignored) { // ignore instantiation exceptions 495: } catch (ClassNotFoundException ignored) { 496: } catch (InstantiationException ignored) { 497: } catch (IllegalAccessException ignored) { 498: } 499: } 500: 501: return result.elements(); 502: } 503: 504: /** 505: * Creates a {@link SaslServer} for the specified mechanism. 506: * 507: * <p>This method uses the JCA Security Provider Framework, described in the 508: * "Java Cryptography Architecture API Specification & Reference", for 509: * locating and selecting a SaslServer implementation.</p> 510: * 511: * <p>First, it obtains an ordered list of {@link SaslServerFactory} 512: * instances from the registered security providers for the 513: * <code>"SaslServerFactory"</code> service and the specified mechanism. It 514: * then invokes <code>createSaslServer()</code> on each factory instance on 515: * the list until one produces a non-null {@link SaslServer} instance. It 516: * returns the non-null {@link SaslServer} instance, or <code>null</code> if 517: * the search fails to produce a non-null {@link SaslServer} instance.</p> 518: * 519: * <p>A security provider for {@link SaslServerFactory} registers with the 520: * JCA Security Provider Framework keys of the form:</p> 521: * 522: * <pre> 523: * SaslServerFactory.mechanism_name 524: * </pre> 525: * 526: * <p>and values that are class names of implementations of {@link 527: * SaslServerFactory}.</p> 528: * 529: * <p>For example, a provider that contains a factory class, 530: * <code>com.wiz.sasl.digest.ServerFactory</code>, that supports the 531: * <code>"DIGEST-MD5"</code> mechanism would register the following entry 532: * with the JCA:</p> 533: * 534: * <pre> 535: * SaslServerFactory.DIGEST-MD5 com.wiz.sasl.digest.ServerFactory 536: * </pre> 537: * 538: * <p>See the "Java Cryptography Architecture API Specification & 539: * Reference" for information about how to install and configure security 540: * service providers.</p> 541: * 542: * @param mechanism the non-null mechanism name. It must be an 543: * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5"). 544: * @param protocol the non-null string name of the protocol for which the 545: * authentication is being performed (e.g. "ldap"). 546: * @param serverName the non-null fully qualified host name of the server. 547: * @param props the possibly <code>null</code> set of properties used to 548: * select the SASL mechanism and to configure the authentication exchange of 549: * the selected mechanism. For example, if props contains the {@link 550: * Sasl#POLICY_NOPLAINTEXT} property with the value <code>"true"</code>, then 551: * the selected SASL mechanism must not be susceptible to simple plain 552: * passive attacks. In addition to the standard properties declared in this 553: * class, other, possibly mechanism-specific, properties can be included. 554: * Properties not relevant to the selected mechanism are ignored. 555: * @param cbh the possibly <code>null</code> callback handler to used by the 556: * SASL mechanisms to get further information from the application/library to 557: * complete the authentication. For example, a SASL mechanism might require 558: * the authentication ID, password and realm from the caller. The 559: * authentication ID is requested by using a 560: * {@link javax.security.auth.callback.NameCallback}. The password is 561: * requested by using a {@link javax.security.auth.callback.PasswordCallback}. 562: * The realm is requested by using a {@link RealmChoiceCallback} if there is 563: * a list of realms to choose from, and by using a {@link RealmCallback} if 564: * the realm must be entered. 565: * @return a possibly <code>null</code> {@link SaslServer} created using the 566: * parameters supplied. If <code>null</code>, the method cannot find a 567: * {@link SaslServerFactory} instance that will produce one. 568: * @throws SaslException if a {@link SaslServer} instance cannot be created 569: * because of an error. 570: */ 571: public static SaslServer createSaslServer(String mechanism, String protocol, 572: String serverName, 573: Map<String, ?> props, 574: CallbackHandler cbh) 575: throws SaslException 576: { 577: if (mechanism == null) 578: return null; 579: Provider[] providers = Security.getProviders(); 580: if (providers == null || providers.length == 0) 581: return null; 582: 583: SaslServer result = null; 584: SaslServerFactory factory = null; 585: String clazz = null, upper, alias = null; 586: int j; 587: Provider p; 588: for (j = 0; j < providers.length; j++) 589: { 590: p = providers[j]; 591: if (p != null) 592: { 593: // try the name as is 594: clazz = p.getProperty(SERVER_FACTORY_SVC + mechanism); 595: if (clazz == null) // try all uppercase 596: { 597: upper = mechanism.toUpperCase(); 598: clazz = p.getProperty(SERVER_FACTORY_SVC + upper); 599: if (clazz == null) // try if it's an alias 600: { 601: alias = p.getProperty(ALIAS + SERVER_FACTORY_SVC + mechanism); 602: if (alias == null) // try all-uppercase alias name 603: { 604: alias = p.getProperty(ALIAS + SERVER_FACTORY_SVC + upper); 605: if (alias == null) // spit the dummy 606: continue; 607: } 608: } 609: clazz = p.getProperty(SERVER_FACTORY_SVC + alias); 610: } 611: } 612: if (clazz == null) 613: continue; 614: else 615: clazz = clazz.trim(); 616: 617: try 618: { 619: result = null; 620: factory = (SaslServerFactory) Class.forName(clazz).newInstance(); 621: result = 622: factory.createSaslServer(mechanism, protocol, serverName, props, cbh); 623: } 624: catch (ClassCastException ignored) // ignore instantiation exceptions 625: { 626: } 627: catch (ClassNotFoundException ignored) 628: { 629: } 630: catch (InstantiationException ignored) 631: { 632: } 633: catch (IllegalAccessException ignored) 634: { 635: } 636: if (result != null) 637: return result; 638: } 639: return null; 640: } 641: 642: /** 643: * Gets an enumeration of known factories for producing a {@link SaslServer} 644: * instance. This method uses the same sources for locating factories as 645: * <code>createSaslServer()</code>. 646: * 647: * @return a non-null {@link Enumeration} of known factories for producing a 648: * {@link SaslServer} instance. 649: * @see #createSaslServer(String,String,String,Map,CallbackHandler) 650: */ 651: public static Enumeration<SaslServerFactory> getSaslServerFactories() 652: { 653: Vector result = new Vector(); 654: HashSet names = new HashSet(); 655: Provider[] providers = Security.getProviders(); 656: Iterator it; 657: if (providers != null) 658: { 659: Provider p; 660: String key; 661: for (int i = 0; i < providers.length; i++) 662: { 663: p = providers[i]; 664: for (it = p.keySet().iterator(); it.hasNext(); ) 665: { 666: key = (String) it.next(); 667: // add key's binding (a) it is a class of a server factory, 668: // and (b) the key does not include blanks 669: if (key.startsWith(SERVER_FACTORY_SVC) && key.indexOf(" ") == -1) 670: { 671: names.add(p.getProperty(key)); 672: break; 673: } 674: } 675: } 676: } 677: // we have the factory class names in names; instantiate and enumerate 678: String c; 679: for (it = names.iterator(); it.hasNext(); ) 680: { 681: c = (String) it.next(); 682: try 683: { 684: SaslServerFactory f = (SaslServerFactory) Class.forName(c).newInstance(); 685: if (f != null) 686: result.add(f); 687: } 688: catch (ClassCastException ignored) // ignore instantiation exceptions 689: { 690: } 691: catch (ClassNotFoundException ignored) 692: { 693: } 694: catch (InstantiationException ignored) 695: { 696: } 697: catch (IllegalAccessException ignored) 698: { 699: } 700: } 701: 702: return result.elements(); 703: } 704: }