1 /* 2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.security.sasl; 27 28 import javax.security.auth.callback.CallbackHandler; 29 30 import java.util.Enumeration; 31 import java.util.Iterator; 32 import java.util.Map; 33 import java.util.Set; 34 import java.util.HashSet; 35 import java.util.Collections; 36 import java.security.InvalidParameterException; 37 import java.security.NoSuchAlgorithmException; 38 import java.security.Provider; 39 import java.security.Provider.Service; 40 import java.security.Security; 41 42 /** 43 * A static class for creating SASL clients and servers. 44 *<p> 45 * This class defines the policy of how to locate, load, and instantiate 46 * SASL clients and servers. 47 *<p> 48 * For example, an application or library gets a SASL client by doing 49 * something like: 50 *<blockquote><pre> 51 * SaslClient sc = Sasl.createSaslClient(mechanisms, 52 * authorizationId, protocol, serverName, props, callbackHandler); 53 *</pre></blockquote> 54 * It can then proceed to use the instance to create an authentication connection. 55 *<p> 56 * Similarly, a server gets a SASL server by using code that looks as follows: 57 *<blockquote><pre> 58 * SaslServer ss = Sasl.createSaslServer(mechanism, 59 * protocol, serverName, props, callbackHandler); 60 *</pre></blockquote> 61 * 62 * @since 1.5 63 * 64 * @author Rosanna Lee 65 * @author Rob Weltman 66 */ 67 public class Sasl { 68 // Cannot create one of these 69 private Sasl() { 70 } 71 72 /** 73 * The name of a property that specifies the quality-of-protection to use. 74 * The property contains a comma-separated, ordered list 75 * of quality-of-protection values that the 76 * client or server is willing to support. A qop value is one of 77 * <ul> 78 * <li>{@code "auth"} - authentication only</li> 79 * <li>{@code "auth-int"} - authentication plus integrity protection</li> 80 * <li>{@code "auth-conf"} - authentication plus integrity and confidentiality 81 * protection</li> 82 * </ul> 83 * 84 * The order of the list specifies the preference order of the client or 85 * server. If this property is absent, the default qop is {@code "auth"}. 86 * The value of this constant is {@code "javax.security.sasl.qop"}. 87 */ 88 public static final String QOP = "javax.security.sasl.qop"; 89 90 /** 91 * The name of a property that specifies the cipher strength to use. 92 * The property contains a comma-separated, ordered list 93 * of cipher strength values that 94 * the client or server is willing to support. A strength value is one of 95 * <ul> 96 * <li>{@code "low"}</li> 97 * <li>{@code "medium"}</li> 98 * <li>{@code "high"}</li> 99 * </ul> 100 * The order of the list specifies the preference order of the client or 101 * server. An implementation should allow configuration of the meaning 102 * of these values. An application may use the Java Cryptography 103 * Extension (JCE) with JCE-aware mechanisms to control the selection of 104 * cipher suites that match the strength values. 105 * <BR> 106 * If this property is absent, the default strength is 107 * {@code "high,medium,low"}. 108 * The value of this constant is {@code "javax.security.sasl.strength"}. 109 */ 110 public static final String STRENGTH = "javax.security.sasl.strength"; 111 112 /** 113 * The name of a property that specifies whether the 114 * server must authenticate to the client. The property contains 115 * {@code "true"} if the server must 116 * authenticate the to client; {@code "false"} otherwise. 117 * The default is {@code "false"}. 118 * <br>The value of this constant is 119 * {@code "javax.security.sasl.server.authentication"}. 120 */ 121 public static final String SERVER_AUTH = 122 "javax.security.sasl.server.authentication"; 123 124 /** 125 * The name of a property that specifies the bound server name for 126 * an unbound server. A server is created as an unbound server by setting 127 * the {@code serverName} argument in {@link #createSaslServer} as null. 128 * The property contains the bound host name after the authentication 129 * exchange has completed. It is only available on the server side. 130 * <br>The value of this constant is 131 * {@code "javax.security.sasl.bound.server.name"}. 132 */ 133 public static final String BOUND_SERVER_NAME = 134 "javax.security.sasl.bound.server.name"; 135 136 /** 137 * The name of a property that specifies the maximum size of the receive 138 * buffer in bytes of {@code SaslClient}/{@code SaslServer}. 139 * The property contains the string representation of an integer. 140 * <br>If this property is absent, the default size 141 * is defined by the mechanism. 142 * <br>The value of this constant is {@code "javax.security.sasl.maxbuffer"}. 143 */ 144 public static final String MAX_BUFFER = "javax.security.sasl.maxbuffer"; 145 146 /** 147 * The name of a property that specifies the maximum size of the raw send 148 * buffer in bytes of {@code SaslClient}/{@code SaslServer}. 149 * The property contains the string representation of an integer. 150 * The value of this property is negotiated between the client and server 151 * during the authentication exchange. 152 * <br>The value of this constant is {@code "javax.security.sasl.rawsendsize"}. 153 */ 154 public static final String RAW_SEND_SIZE = "javax.security.sasl.rawsendsize"; 155 156 /** 157 * The name of a property that specifies whether to reuse previously 158 * authenticated session information. The property contains "true" if the 159 * mechanism implementation may attempt to reuse previously authenticated 160 * session information; it contains "false" if the implementation must 161 * not reuse previously authenticated session information. A setting of 162 * "true" serves only as a hint: it does not necessarily entail actual 163 * reuse because reuse might not be possible due to a number of reasons, 164 * including, but not limited to, lack of mechanism support for reuse, 165 * expiration of reusable information, and the peer's refusal to support 166 * reuse. 167 * 168 * The property's default value is "false". The value of this constant 169 * is "javax.security.sasl.reuse". 170 * 171 * Note that all other parameters and properties required to create a 172 * SASL client/server instance must be provided regardless of whether 173 * this property has been supplied. That is, you cannot supply any less 174 * information in anticipation of reuse. 175 * 176 * Mechanism implementations that support reuse might allow customization 177 * of its implementation, for factors such as cache size, timeouts, and 178 * criteria for reusability. Such customizations are 179 * implementation-dependent. 180 */ 181 public static final String REUSE = "javax.security.sasl.reuse"; 182 183 /** 184 * The name of a property that specifies 185 * whether mechanisms susceptible to simple plain passive attacks (e.g., 186 * "PLAIN") are not permitted. The property 187 * contains {@code "true"} if such mechanisms are not permitted; 188 * {@code "false"} if such mechanisms are permitted. 189 * The default is {@code "false"}. 190 * <br>The value of this constant is 191 * {@code "javax.security.sasl.policy.noplaintext"}. 192 */ 193 public static final String POLICY_NOPLAINTEXT = 194 "javax.security.sasl.policy.noplaintext"; 195 196 /** 197 * The name of a property that specifies whether 198 * mechanisms susceptible to active (non-dictionary) attacks 199 * are not permitted. 200 * The property contains {@code "true"} 201 * if mechanisms susceptible to active attacks 202 * are not permitted; {@code "false"} if such mechanisms are permitted. 203 * The default is {@code "false"}. 204 * <br>The value of this constant is 205 * {@code "javax.security.sasl.policy.noactive"}. 206 */ 207 public static final String POLICY_NOACTIVE = 208 "javax.security.sasl.policy.noactive"; 209 210 /** 211 * The name of a property that specifies whether 212 * mechanisms susceptible to passive dictionary attacks are not permitted. 213 * The property contains {@code "true"} 214 * if mechanisms susceptible to dictionary attacks are not permitted; 215 * {@code "false"} if such mechanisms are permitted. 216 * The default is {@code "false"}. 217 *<br> 218 * The value of this constant is 219 * {@code "javax.security.sasl.policy.nodictionary"}. 220 */ 221 public static final String POLICY_NODICTIONARY = 222 "javax.security.sasl.policy.nodictionary"; 223 224 /** 225 * The name of a property that specifies whether mechanisms that accept 226 * anonymous login are not permitted. The property contains {@code "true"} 227 * if mechanisms that accept anonymous login are not permitted; 228 * {@code "false"} 229 * if such mechanisms are permitted. The default is {@code "false"}. 230 *<br> 231 * The value of this constant is 232 * {@code "javax.security.sasl.policy.noanonymous"}. 233 */ 234 public static final String POLICY_NOANONYMOUS = 235 "javax.security.sasl.policy.noanonymous"; 236 237 /** 238 * The name of a property that specifies whether mechanisms that implement 239 * forward secrecy between sessions are required. Forward secrecy 240 * means that breaking into one session will not automatically 241 * provide information for breaking into future sessions. 242 * The property 243 * contains {@code "true"} if mechanisms that implement forward secrecy 244 * between sessions are required; {@code "false"} if such mechanisms 245 * are not required. The default is {@code "false"}. 246 *<br> 247 * The value of this constant is 248 * {@code "javax.security.sasl.policy.forward"}. 249 */ 250 public static final String POLICY_FORWARD_SECRECY = 251 "javax.security.sasl.policy.forward"; 252 253 /** 254 * The name of a property that specifies whether 255 * mechanisms that pass client credentials are required. The property 256 * contains {@code "true"} if mechanisms that pass 257 * client credentials are required; {@code "false"} 258 * if such mechanisms are not required. The default is {@code "false"}. 259 *<br> 260 * The value of this constant is 261 * {@code "javax.security.sasl.policy.credentials"}. 262 */ 263 public static final String POLICY_PASS_CREDENTIALS = 264 "javax.security.sasl.policy.credentials"; 265 266 /** 267 * The name of a property that specifies the credentials to use. 268 * The property contains a mechanism-specific Java credential object. 269 * Mechanism implementations may examine the value of this property 270 * to determine whether it is a class that they support. 271 * The property may be used to supply credentials to a mechanism that 272 * supports delegated authentication. 273 *<br> 274 * The value of this constant is 275 * {@code "javax.security.sasl.credentials"}. 276 */ 277 public static final String CREDENTIALS = "javax.security.sasl.credentials"; 278 279 /** 280 * Creates a {@code SaslClient} using the parameters supplied. 281 * 282 * This method uses the 283 <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>, described in the 284 * "Java Cryptography Architecture API Specification & Reference", for 285 * locating and selecting a {@code SaslClient} implementation. 286 * 287 * First, it 288 * obtains an ordered list of {@code SaslClientFactory} instances from 289 * the registered security providers for the "SaslClientFactory" service 290 * and the specified SASL mechanism(s). It then invokes 291 * {@code createSaslClient()} on each factory instance on the list 292 * until one produces a non-null {@code SaslClient} instance. It returns 293 * the non-null {@code SaslClient} instance, or null if the search fails 294 * to produce a non-null {@code SaslClient} instance. 295 *<p> 296 * A security provider for SaslClientFactory registers with the 297 * JCA Security Provider Framework keys of the form <br> 298 * {@code SaslClientFactory.}<em>{@code mechanism_name}</em> 299 * <br> 300 * and values that are class names of implementations of 301 * {@code javax.security.sasl.SaslClientFactory}. 302 * 303 * For example, a provider that contains a factory class, 304 * {@code com.wiz.sasl.digest.ClientFactory}, that supports the 305 * "DIGEST-MD5" mechanism would register the following entry with the JCA: 306 * {@code SaslClientFactory.DIGEST-MD5 com.wiz.sasl.digest.ClientFactory} 307 *<p> 308 * See the 309 * "Java Cryptography Architecture API Specification & Reference" 310 * for information about how to install and configure security service 311 * providers. 312 * 313 * @implNote 314 * The JDK Reference Implementation additionally uses the 315 * {@code jdk.security.provider.preferred} property to determine 316 * the preferred provider order for the specified algorithm. This 317 * may be different than the order of providers returned by 318 * {@link Security#getProviders() Security.getProviders()}. 319 * 320 * @param mechanisms The non-null list of mechanism names to try. Each is the 321 * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5"). 322 * @param authorizationId The possibly null protocol-dependent 323 * identification to be used for authorization. 324 * If null or empty, the server derives an authorization 325 * ID from the client's authentication credentials. 326 * When the SASL authentication completes successfully, 327 * the specified entity is granted access. 328 * 329 * @param protocol The non-null string name of the protocol for which 330 * the authentication is being performed (e.g., "ldap"). 331 * 332 * @param serverName The non-null fully-qualified host name of the server 333 * to authenticate to. 334 * 335 * @param props The possibly null set of properties used to 336 * select the SASL mechanism and to configure the authentication 337 * exchange of the selected mechanism. 338 * For example, if {@code props} contains the 339 * {@code Sasl.POLICY_NOPLAINTEXT} property with the value 340 * {@code "true"}, then the selected 341 * SASL mechanism must not be susceptible to simple plain passive attacks. 342 * In addition to the standard properties declared in this class, 343 * other, possibly mechanism-specific, properties can be included. 344 * Properties not relevant to the selected mechanism are ignored, 345 * including any map entries with non-String keys. 346 * 347 * @param cbh The possibly null callback handler to used by the SASL 348 * mechanisms to get further information from the application/library 349 * to complete the authentication. For example, a SASL mechanism might 350 * require the authentication ID, password and realm from the caller. 351 * The authentication ID is requested by using a {@code NameCallback}. 352 * The password is requested by using a {@code PasswordCallback}. 353 * The realm is requested by using a {@code RealmChoiceCallback} if there is a list 354 * of realms to choose from, and by using a {@code RealmCallback} if 355 * the realm must be entered. 356 * 357 *@return A possibly null {@code SaslClient} created using the parameters 358 * supplied. If null, cannot find a {@code SaslClientFactory} 359 * that will produce one. 360 *@exception SaslException If cannot create a {@code SaslClient} because 361 * of an error. 362 */ 363 public static SaslClient createSaslClient( 364 String[] mechanisms, 365 String authorizationId, 366 String protocol, 367 String serverName, 368 Map<String,?> props, 369 CallbackHandler cbh) throws SaslException { 370 371 SaslClient mech = null; 372 SaslClientFactory fac; 373 Service service; 374 String mechName; 375 376 for (int i = 0; i < mechanisms.length; i++) { 377 if ((mechName=mechanisms[i]) == null) { 378 throw new NullPointerException( 379 "Mechanism name cannot be null"); 380 } else if (mechName.length() == 0) { 381 continue; 382 } 383 String type = "SaslClientFactory"; 384 Provider[] provs = Security.getProviders(type + "." + mechName); 385 if (provs != null) { 386 for (Provider p : provs) { 387 service = p.getService(type, mechName); 388 if (service == null) { 389 // no such service exists 390 continue; 391 } 392 393 fac = (SaslClientFactory) loadFactory(service); 394 if (fac != null) { 395 mech = fac.createSaslClient( 396 new String[]{mechanisms[i]}, authorizationId, 397 protocol, serverName, props, cbh); 398 if (mech != null) { 399 return mech; 400 } 401 } 402 } 403 } 404 } 405 return null; 406 } 407 408 private static Object loadFactory(Service service) 409 throws SaslException { 410 try { 411 /* 412 * Load the implementation class with the same class loader 413 * that was used to load the provider. 414 * In order to get the class loader of a class, the 415 * caller's class loader must be the same as or an ancestor of 416 * the class loader being returned. Otherwise, the caller must 417 * have "getClassLoader" permission, or a SecurityException 418 * will be thrown. 419 */ 420 return service.newInstance(null); 421 } catch (InvalidParameterException | NoSuchAlgorithmException e) { 422 throw new SaslException("Cannot instantiate service " + service, e); 423 } 424 } 425 426 427 /** 428 * Creates a {@code SaslServer} for the specified mechanism. 429 * 430 * This method uses the 431 <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#Provider">JCA Security Provider Framework</a>, 432 * described in the 433 * "Java Cryptography Architecture API Specification & Reference", for 434 * locating and selecting a {@code SaslServer} implementation. 435 * 436 * First, it 437 * obtains an ordered list of {@code SaslServerFactory} instances from 438 * the registered security providers for the "SaslServerFactory" service 439 * and the specified mechanism. It then invokes 440 * {@code createSaslServer()} on each factory instance on the list 441 * until one produces a non-null {@code SaslServer} instance. It returns 442 * the non-null {@code SaslServer} instance, or null if the search fails 443 * to produce a non-null {@code SaslServer} instance. 444 *<p> 445 * A security provider for SaslServerFactory registers with the 446 * JCA Security Provider Framework keys of the form <br> 447 * {@code SaslServerFactory.}<em>{@code mechanism_name}</em> 448 * <br> 449 * and values that are class names of implementations of 450 * {@code javax.security.sasl.SaslServerFactory}. 451 * 452 * For example, a provider that contains a factory class, 453 * {@code com.wiz.sasl.digest.ServerFactory}, that supports the 454 * "DIGEST-MD5" mechanism would register the following entry with the JCA: 455 * {@code SaslServerFactory.DIGEST-MD5 com.wiz.sasl.digest.ServerFactory} 456 *<p> 457 * See the 458 * "Java Cryptography Architecture API Specification & Reference" 459 * for information about how to install and configure security 460 * service providers. 461 * 462 * @implNote 463 * The JDK Reference Implementation additionally uses the 464 * {@code jdk.security.provider.preferred} property to determine 465 * the preferred provider order for the specified algorithm. This 466 * may be different than the order of providers returned by 467 * {@link Security#getProviders() Security.getProviders()}. 468 * 469 * @param mechanism The non-null mechanism name. It must be an 470 * IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5"). 471 * @param protocol The non-null string name of the protocol for which 472 * the authentication is being performed (e.g., "ldap"). 473 * @param serverName The fully qualified host name of the server, or null 474 * if the server is not bound to any specific host name. If the mechanism 475 * does not allow an unbound server, a {@code SaslException} will 476 * be thrown. 477 * @param props The possibly null set of properties used to 478 * select the SASL mechanism and to configure the authentication 479 * exchange of the selected mechanism. 480 * For example, if {@code props} contains the 481 * {@code Sasl.POLICY_NOPLAINTEXT} property with the value 482 * {@code "true"}, then the selected 483 * SASL mechanism must not be susceptible to simple plain passive attacks. 484 * In addition to the standard properties declared in this class, 485 * other, possibly mechanism-specific, properties can be included. 486 * Properties not relevant to the selected mechanism are ignored, 487 * including any map entries with non-String keys. 488 * 489 * @param cbh The possibly null callback handler to used by the SASL 490 * mechanisms to get further information from the application/library 491 * to complete the authentication. For example, a SASL mechanism might 492 * require the authentication ID, password and realm from the caller. 493 * The authentication ID is requested by using a {@code NameCallback}. 494 * The password is requested by using a {@code PasswordCallback}. 495 * The realm is requested by using a {@code RealmChoiceCallback} if there is a list 496 * of realms to choose from, and by using a {@code RealmCallback} if 497 * the realm must be entered. 498 * 499 *@return A possibly null {@code SaslServer} created using the parameters 500 * supplied. If null, cannot find a {@code SaslServerFactory} 501 * that will produce one. 502 *@exception SaslException If cannot create a {@code SaslServer} because 503 * of an error. 504 **/ 505 public static SaslServer 506 createSaslServer(String mechanism, 507 String protocol, 508 String serverName, 509 Map<String,?> props, 510 javax.security.auth.callback.CallbackHandler cbh) 511 throws SaslException { 512 513 SaslServer mech = null; 514 SaslServerFactory fac; 515 Service service; 516 517 if (mechanism == null) { 518 throw new NullPointerException("Mechanism name cannot be null"); 519 } else if (mechanism.length() == 0) { 520 return null; 521 } 522 523 String type = "SaslServerFactory"; 524 Provider[] provs = Security.getProviders(type + "." + mechanism); 525 if (provs != null) { 526 for (Provider p : provs) { 527 service = p.getService(type, mechanism); 528 if (service == null) { 529 throw new SaslException("Provider does not support " + 530 mechanism + " " + type); 531 } 532 fac = (SaslServerFactory) loadFactory(service); 533 if (fac != null) { 534 mech = fac.createSaslServer( 535 mechanism, protocol, serverName, props, cbh); 536 if (mech != null) { 537 return mech; 538 } 539 } 540 } 541 } 542 return null; 543 } 544 545 /** 546 * Gets an enumeration of known factories for producing {@code SaslClient}. 547 * This method uses the same algorithm for locating factories as 548 * {@code createSaslClient()}. 549 * @return A non-null enumeration of known factories for producing 550 * {@code SaslClient}. 551 * @see #createSaslClient 552 */ 553 public static Enumeration<SaslClientFactory> getSaslClientFactories() { 554 Set<Object> facs = getFactories("SaslClientFactory"); 555 final Iterator<Object> iter = facs.iterator(); 556 return new Enumeration<SaslClientFactory>() { 557 public boolean hasMoreElements() { 558 return iter.hasNext(); 559 } 560 public SaslClientFactory nextElement() { 561 return (SaslClientFactory)iter.next(); 562 } 563 }; 564 } 565 566 /** 567 * Gets an enumeration of known factories for producing {@code SaslServer}. 568 * This method uses the same algorithm for locating factories as 569 * {@code createSaslServer()}. 570 * @return A non-null enumeration of known factories for producing 571 * {@code SaslServer}. 572 * @see #createSaslServer 573 */ 574 public static Enumeration<SaslServerFactory> getSaslServerFactories() { 575 Set<Object> facs = getFactories("SaslServerFactory"); 576 final Iterator<Object> iter = facs.iterator(); 577 return new Enumeration<SaslServerFactory>() { 578 public boolean hasMoreElements() { 579 return iter.hasNext(); 580 } 581 public SaslServerFactory nextElement() { 582 return (SaslServerFactory)iter.next(); 583 } 584 }; 585 } 586 587 private static Set<Object> getFactories(String serviceName) { 588 HashSet<Object> result = new HashSet<Object>(); 589 590 if ((serviceName == null) || (serviceName.length() == 0) || 591 (serviceName.endsWith("."))) { 592 return result; 593 } 594 595 Provider[] provs = Security.getProviders(); 596 Object fac; 597 598 for (Provider p : provs) { 599 600 Iterator<Service> iter = p.getServices().iterator(); 601 while (iter.hasNext()) { 602 Service s = iter.next(); 603 if (s.getType().equals(serviceName)) { 604 try { 605 fac = loadFactory(s); 606 if (fac != null) { 607 result.add(fac); 608 } 609 } catch (Exception ignore) { 610 } 611 } 612 } 613 } 614 return Collections.unmodifiableSet(result); 615 } 616 }