001/* 002* The contents of this file are subject to the terms of the Common Development and 003* Distribution License (the License). You may not use this file except in compliance with the 004* License. 005* 006* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007* specific language governing permission and limitations under the License. 008* 009* When distributing Covered Software, include this CDDL Header Notice in each file and include 010* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011* Header, with the fields enclosed by brackets [] replaced by your own identifying 012* information: "Portions Copyrighted [year] [name of copyright owner]". 013* 014* Copyright 2014-2016 ForgeRock AS. 015*/ 016 017package org.forgerock.openam.sts.config.user; 018 019import org.apache.xml.security.encryption.XMLCipher; 020import org.forgerock.guava.common.base.Objects; 021import org.forgerock.json.JsonValue; 022import org.forgerock.openam.shared.sts.SharedSTSConstants; 023import org.forgerock.openam.sts.AMSTSConstants; 024import org.forgerock.openam.sts.MapMarshallUtils; 025import org.forgerock.openam.utils.CollectionUtils; 026 027import java.io.UnsupportedEncodingException; 028import java.util.Arrays; 029import java.util.Collections; 030import java.util.HashMap; 031import java.util.LinkedHashMap; 032import java.util.LinkedHashSet; 033import java.util.Map; 034import java.util.Set; 035 036import static org.forgerock.json.JsonValue.field; 037import static org.forgerock.json.JsonValue.json; 038import static org.forgerock.json.JsonValue.object; 039 040/** 041 * Encapsulates the configuration state necessary to produce SAML2 assertions. 042 * 043 * Each published rest-sts instance will encapsulate state to allow it to issue saml2 assertions for a single 044 * SP. Thus the spEntityId, and spAcsUrl (the url of the SP's assertion consumer service) are specified in this class. 045 * The signatureAlias corresponds to the IDP's signing key, and the encryptionKeyAlias could correspond to the SP's 046 * public key corresponding to the key used to encrypt the symmetric key used to encrypt assertion elements. 047 * 048 * @supported.all.api 049 */ 050public class SAML2Config { 051 052 /* 053 * TODO: Ambiguity in the context of setting the customAttributeStatementsProviderClassName 054 * and the customAttributeMapperClassName. As it currently stands, the customAttributeStatementsProvider will be passed 055 * an instance of the customAttributeMapper if both are specified. The usual case will simply to set the customAttributeMapper, 056 * as this allows custom attributes to be set in the AttributeStatement. 057 * 058 * TODO: do I want a name-qualifier in addition to a nameIdFormat? 059 */ 060 061 private static final String EQUALS = "="; 062 063 /** 064 * Builder used to programmatically create {@linkplain SAML2Config} objects 065 * 066 * @supported.all.api 067 */ 068 public static class SAML2ConfigBuilder { 069 private String idpId; 070 /* 071 Cannot use the SAML2Constants defined in openam-federation, as this dependency 072 introduces a dependency on openam-core, which pulls the ws-* dependencies into the soap-sts, which I don't want. 073 Also can't use the SAML2Constants in wss4j, as I don't want this dependency in the rest-sts (as it depends upon 074 SAML2Config). Just define the value here. 075 */ 076 private String nameIdFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"; 077 private Map<String, String> attributeMap; 078 private long tokenLifetimeInSeconds = 60 * 10; //default token lifetime is 10 minutes 079 private String customConditionsProviderClassName; 080 private String customSubjectProviderClassName; 081 private String customAuthenticationStatementsProviderClassName; 082 private String customAttributeStatementsProviderClassName; 083 private String customAuthzDecisionStatementsProviderClassName; 084 private String customAttributeMapperClassName; 085 private String customAuthNContextMapperClassName; 086 private String spEntityId; 087 private String spAcsUrl; 088 private boolean signAssertion; 089 private boolean encryptNameID; 090 private boolean encryptAttributes; 091 private boolean encryptAssertion; 092 private String encryptionAlgorithm; 093 private int encryptionAlgorithmStrength; 094 private String keystoreFileName; 095 private byte[] keystorePassword; 096 /* 097 Corresponds to the key used to sign the assertion. 098 */ 099 private String signatureKeyAlias; 100 private byte[] signatureKeyPassword; 101 /* 102 Corresponds to the SP's x509 cert - the corresponding public key is used to encrypt the symmetric key used to 103 encrypt assertion elements 104 */ 105 private String encryptionKeyAlias; 106 107 private SAML2ConfigBuilder() {} 108 109 /** 110 * Sets the name-id format on the SAML2ConfigBuilder. 111 * 112 * @param nameIdFormat the name-id format. 113 * @return the SAML2ConfigBuilder with the specified name-id format. 114 */ 115 public SAML2ConfigBuilder nameIdFormat(String nameIdFormat) { 116 //TODO - test to see if it matches one of the allowed values? 117 this.nameIdFormat = nameIdFormat; 118 return this; 119 } 120 121 /** 122 * Sets the Idenity Provider id on the SAML2ConfigBuilder. 123 * 124 * @param idpId the Identity Provider id. 125 * @return the SAML2ConfigBuilder with the specified Identity Provider id. 126 */ 127 public SAML2ConfigBuilder idpId(String idpId) { 128 this.idpId = idpId; 129 return this; 130 } 131 132 /** 133 * Sets the attribute map on the SAML2ConfigBuilder. 134 * 135 * @param attributeMap the attribute map. 136 * @return the SAML2ConfigBuilder with the specified attribute map. 137 */ 138 public SAML2ConfigBuilder attributeMap(Map<String, String> attributeMap) { 139 this.attributeMap = Collections.unmodifiableMap(attributeMap); 140 return this; 141 } 142 143 /** 144 * Sets the token lifetime (in seconds) on the SAML2ConfigBuilder. 145 * 146 * @param lifetimeInSeconds the token lifetime. 147 * @return the SAML2ConfigBuilder with the specified token lifetime. 148 */ 149 public SAML2ConfigBuilder tokenLifetimeInSeconds(long lifetimeInSeconds) { 150 this.tokenLifetimeInSeconds = lifetimeInSeconds; 151 return this; 152 } 153 154 /** 155 * Sets the CustomConditionsProvider classname on the SAML2ConfigBuilder. 156 * 157 * @param customConditionsProviderClassName the CustomConditionsProvider classname. 158 * @return the SAML2ConfigBuilder with the specified CustomConditionsProvider classname. 159 */ 160 public SAML2ConfigBuilder customConditionsProviderClassName(String customConditionsProviderClassName) { 161 this.customConditionsProviderClassName = customConditionsProviderClassName; 162 return this; 163 } 164 165 /** 166 * Sets the CustomSubjectProvider classname on the SAML2ConfigBuilder. 167 * 168 * @param customSubjectProviderClassName the CustomSubjectProvider classname. 169 * @return the SAML2ConfigBuilder with the specified CustomSubjectProvider classname. 170 */ 171 public SAML2ConfigBuilder customSubjectProviderClassName(String customSubjectProviderClassName) { 172 this.customSubjectProviderClassName = customSubjectProviderClassName; 173 return this; 174 } 175 176 /** 177 * Sets the CustomAuthenticationStatementsProvider classname on the SAML2ConfigBuilder. 178 * 179 * @param customAuthenticationStatementsProviderClassName the CustomAuthenticationStatementsProvider classname. 180 * @return the SAML2ConfigBuilder with the specified CustomAuthenticationStatementsProvider classname. 181 */ 182 public SAML2ConfigBuilder customAuthenticationStatementsProviderClassName(String customAuthenticationStatementsProviderClassName) { 183 this.customAuthenticationStatementsProviderClassName = customAuthenticationStatementsProviderClassName; 184 return this; 185 } 186 187 /** 188 * Sets the CustomAttributeStatementsProvider classname on the SAML2ConfigBuilder. 189 * 190 * @param customAttributeStatementsProviderClassName the CustomAuthenticationStatementsProvider classname. 191 * @return the SAML2ConfigBuilder with the specified CustomAuthenticationStatementsProvider classname. 192 */ 193 public SAML2ConfigBuilder customAttributeStatementsProviderClassName(String customAttributeStatementsProviderClassName) { 194 this.customAttributeStatementsProviderClassName = customAttributeStatementsProviderClassName; 195 return this; 196 } 197 198 /** 199 * Sets the CustomAuthzDecisionStatementsProvider classname on the SAML2ConfigBuilder. 200 * 201 * @param customAuthzDecisionStatementsProviderClassName the CustomAuthzDecisionStatementsProvider classname. 202 * @return the SAML2ConfigBuilder with the specified CustomAuthzDecisionStatementsProvider classname. 203 */ 204 public SAML2ConfigBuilder customAuthzDecisionStatementsProviderClassName(String customAuthzDecisionStatementsProviderClassName) { 205 this.customAuthzDecisionStatementsProviderClassName = customAuthzDecisionStatementsProviderClassName; 206 return this; 207 } 208 209 /** 210 * Sets the CustomAttributeMapper classname on the SAML2ConfigBuilder. 211 * 212 * @param customAttributeMapperClassName the CustomAttributeMapper classname. 213 * @return the SAML2ConfigBuilder with the specified CustomAttributeMapper classname. 214 */ 215 public SAML2ConfigBuilder customAttributeMapperClassName(String customAttributeMapperClassName) { 216 this.customAttributeMapperClassName = customAttributeMapperClassName; 217 return this; 218 } 219 220 /** 221 * Sets the CustomAuthNContextMapper classname on the SAML2ConfigBuilder. 222 * 223 * @param customAuthNContextMapperClassName the CustomAuthNContextMapper classname. 224 * @return the SAML2ConfigBuilder with the specified CustomAuthNContextMapper classname. 225 */ 226 public SAML2ConfigBuilder customAuthNContextMapperClassName(String customAuthNContextMapperClassName) { 227 this.customAuthNContextMapperClassName = customAuthNContextMapperClassName; 228 return this; 229 } 230 231 /** 232 * Sets the SP entity id on the SAML2ConfigBuilder. 233 * 234 * @param spEntityId the SP entity id. 235 * @return the SAML2Config builder with the specified SP entity id. 236 */ 237 public SAML2ConfigBuilder spEntityId(String spEntityId) { 238 this.spEntityId = spEntityId; 239 return this; 240 } 241 242 /** 243 * Sets the SP ACS url on the SAML2ConfigBuilder. 244 * 245 * @param spAcsUrl the SP ACS url. 246 * @return the SAML2Config builder with the specified SP ACS url. 247 */ 248 public SAML2ConfigBuilder spAcsUrl(String spAcsUrl) { 249 this.spAcsUrl = spAcsUrl; 250 return this; 251 } 252 253 /** 254 * Sets the signature key alias on the SAML2ConfigBuilder. 255 * 256 * @param signatureKeyAlias the signature key alias. 257 * @return the SAML2Config builder with the specified signature key alias. 258 */ 259 public SAML2ConfigBuilder signatureKeyAlias(String signatureKeyAlias) { 260 this.signatureKeyAlias = signatureKeyAlias; 261 return this; 262 } 263 264 /** 265 * Sets the signature key password on the SAML2ConfigBuilder. 266 * 267 * @param signatureKeyPassword the signature key password. 268 * @return the SAML2Config builder with the specified signature key password. 269 */ 270 public SAML2ConfigBuilder signatureKeyPassword(byte[] signatureKeyPassword) { 271 this.signatureKeyPassword = signatureKeyPassword; 272 return this; 273 } 274 275 /** 276 * Sets the encryption key alias on the SAML2ConfigBuilder. 277 * 278 * @param encryptionKeyAlias the encryption key alias. 279 * @return the SAML2Config builder with the specified encryption key alias. 280 */ 281 public SAML2ConfigBuilder encryptionKeyAlias(String encryptionKeyAlias) { 282 this.encryptionKeyAlias = encryptionKeyAlias; 283 return this; 284 } 285 286 /** 287 * Sets whether the SAML2Config assertion should be signed. 288 * 289 * @param signAssertion whether the assertion should be signed. 290 * @return the SAML2ConfigBuilder with the assertion signed flag set. 291 */ 292 public SAML2ConfigBuilder signAssertion(boolean signAssertion) { 293 this.signAssertion = signAssertion; 294 return this; 295 } 296 297 /** 298 * Sets whether the SAML2Config name-id should be encrypted. 299 * 300 * @param encryptNameID whether the name-id should be encrypted. 301 * @return the SAML2ConfigBuilder with the name-id encryption flag set. 302 */ 303 public SAML2ConfigBuilder encryptNameID(boolean encryptNameID) { 304 this.encryptNameID = encryptNameID; 305 return this; 306 } 307 308 /** 309 * Sets whether SAML2Config attributes should be encrypted. 310 * 311 * @param encryptAttributes whether the attributes should be encrypted. 312 * @return the SAML2ConfigBuilder with the attribute encryption flag set. 313 */ 314 public SAML2ConfigBuilder encryptAttributes(boolean encryptAttributes) { 315 this.encryptAttributes = encryptAttributes; 316 return this; 317 } 318 319 /** 320 * Sets whether SAML2Config assertion should be encrypted. 321 * 322 * @param encryptAssertion whether the assertion should be encrypted. 323 * @return the SAML2ConfigBuilder with the assertion encryption flag set. 324 */ 325 public SAML2ConfigBuilder encryptAssertion(boolean encryptAssertion) { 326 this.encryptAssertion = encryptAssertion; 327 return this; 328 } 329 330 /* 331 Note that the encryption of SAML2 assertions, is, by default, delegated to the FMEncProvider class, which supports 332 only http://www.w3.org/2001/04/xmlenc#aes128-cbc, http://www.w3.org/2001/04/xmlenc#aes192-cbc, 333 http://www.w3.org/2001/04/xmlenc#aes256-cbc, or http://www.w3.org/2001/04/xmlenc#tripledes-cbc. However, because 334 this EncProvider implementation can be over-ridden by setting the com.sun.identity.saml2.xmlenc.EncryptionProvider 335 property, I can't reject the specification of an encryption algorithm not supported by the FMEncProvider, as 336 I don't know whether this property has been over-ridden. 337 338 Note also that I will remove http://www.w3.org/2001/04/xmlenc#tripledes-cbc from the set of choices exposed 339 in the UI. There seems to be a bug in the FMEncProvider - when the tripledes-cbc is chosen, note on line 294 that 340 this string http://www.w3.org/2001/04/xmlenc#tripledes-cbc is passed to XMLCipher.getInstance resulting in the 341 error below: 342 org.apache.xml.security.encryption.XMLEncryptionException: Wrong algorithm: DESede or TripleDES required 343 The correct thing is done in FMEncProvider#generateSecretKey, where the http://www.w3.org/2001/04/xmlenc#tripledes-cbc 344 is translated to 'TripleDES' before being passed to the XMLCipher - and this actually works. 345 */ 346 /** 347 * Sets the SAML2Config encryption algorithm. 348 * 349 * @param encryptionAlgorithm the encryption algorithm. 350 * @return the SAML2ConfigBuilder with the specified encryption algorithm. 351 */ 352 public SAML2ConfigBuilder encryptionAlgorithm(String encryptionAlgorithm) { 353 this.encryptionAlgorithm = encryptionAlgorithm; 354 return this; 355 } 356 357 /* 358 Note that the encryption of SAML2 assertions, is, by default, delegated to the FMEncProvider class, which supports 359 only encryption algorithm strength values of 128, 192, and 256 for the encryption types XMLCipher.AES_128, 360 XMLCipher.AES_192, and XMLCipher.AES_256, respectively. It does not look like the XMLCipher.TRIPLEDES supports a 361 key encryption strength (see FMEncProvider for details). Given that the encryption strength is directly related 362 to the cipher, it seems a bit silly to set these values. However, because 363 this EncProvider implementation can be over-ridden by setting the com.sun.identity.saml2.xmlenc.EncryptionProvider 364 property, and because the EncProvider specifies an encryption strength parameter, it would seem that I would have 365 to support the setting of this seemingly superfluous parameter, just to support the plug-in interface. For now, 366 I will not expose this value in the UI, as it adds unnecessary complexity, and the encryption algorithms are 367 pre-defined as well. I will simply set this value in the UI context based upon the encryption algorithm. If 368 a customer wants to specify a custom value because they have implemented their own EncryptionProvider, then they 369 can publish a rest-sts instance programmatically. 370 */ 371 /** 372 * Sets the SAML2Config encryption strength. 373 * 374 * @param encryptionAlgorithmStrength the encryption strength. 375 * @return the SAML2ConfigBuilder with the specified encryption strength. 376 */ 377 public SAML2ConfigBuilder encryptionAlgorithmStrength(int encryptionAlgorithmStrength) { 378 this.encryptionAlgorithmStrength = encryptionAlgorithmStrength; 379 return this; 380 } 381 382 /** 383 * Sets the keystore filename on the SAML2ConfigBuilder. 384 * 385 * @param keystoreFileName the keystore filename. 386 * @return the SAML2Config builder with the specified keystore filename. 387 */ 388 public SAML2ConfigBuilder keystoreFile(String keystoreFileName) { 389 this.keystoreFileName = keystoreFileName; 390 return this; 391 } 392 393 /** 394 * Sets the keystore password on the SAML2ConfigBuilder. 395 * 396 * @param keystorePassword the keystore password. 397 * @return the SAML2Config builder with the specified keystore password. 398 */ 399 public SAML2ConfigBuilder keystorePassword(byte[] keystorePassword) { 400 this.keystorePassword = keystorePassword; 401 return this; 402 } 403 404 /** 405 * Builds a SAML2Config object. 406 * 407 * @return a SAML2Config object. 408 */ 409 public SAML2Config build() { 410 return new SAML2Config(this); 411 } 412 } 413 414 /* 415 Define the names of fields to aid in json marshalling. Note that these names match the names of the AttributeSchema 416 entries in restSTS.xml and soapSTS.xml, as this aids in marshalling an instance of this class into the attribute map needed for 417 SMS persistence. 418 */ 419 static final String NAME_ID_FORMAT = "saml2-name-id-format"; 420 static final String ATTRIBUTE_MAP = SharedSTSConstants.SAML2_ATTRIBUTE_MAP; 421 static final String TOKEN_LIFETIME = SharedSTSConstants.SAML2_TOKEN_LIFETIME; 422 static final String CUSTOM_CONDITIONS_PROVIDER_CLASS = "saml2-custom-conditions-provider-class-name"; 423 static final String CUSTOM_SUBJECT_PROVIDER_CLASS = "saml2-custom-subject-provider-class-name"; 424 static final String CUSTOM_ATTRIBUTE_STATEMENTS_PROVIDER_CLASS = "saml2-custom-attribute-statements-provider-class-name"; 425 static final String CUSTOM_AUTHENTICATION_STATEMENTS_PROVIDER_CLASS = "saml2-custom-authentication-statements-provider-class-name"; 426 static final String CUSTOM_AUTHZ_DECISION_STATEMENTS_PROVIDER_CLASS = "saml2-custom-authz-decision-statements-provider-class-name"; 427 static final String CUSTOM_ATTRIBUTE_MAPPER_CLASS = "saml2-custom-attribute-mapper-class-name"; 428 static final String CUSTOM_AUTHN_CONTEXT_MAPPER_CLASS = "saml2-custom-authn-context-mapper-class-name"; 429 static final String SIGN_ASSERTION = SharedSTSConstants.SAML2_SIGN_ASSERTION; 430 static final String ENCRYPT_ATTRIBUTES = SharedSTSConstants.SAML2_ENCRYPT_ATTRIBUTES; 431 static final String ENCRYPT_NAME_ID = SharedSTSConstants.SAML2_ENCRYPT_NAME_ID; 432 static final String ENCRYPT_ASSERTION = SharedSTSConstants.SAML2_ENCRYPT_ASSERTION; 433 static final String ENCRYPTION_ALGORITHM = SharedSTSConstants.SAML2_ENCRYPTION_ALGORITHM; 434 static final String ENCRYPTION_ALGORITHM_STRENGTH = SharedSTSConstants.SAML2_ENCRYPTION_ALGORITHM_STRENGTH; 435 static final String KEYSTORE_FILE_NAME = SharedSTSConstants.SAML2_KEYSTORE_FILE_NAME; 436 static final String KEYSTORE_PASSWORD = SharedSTSConstants.SAML2_KEYSTORE_PASSWORD; 437 static final String SP_ENTITY_ID = SharedSTSConstants.SAML2_SP_ENTITY_ID; 438 static final String SP_ACS_URL = SharedSTSConstants.SAML2_SP_ACS_URL; 439 static final String ENCRYPTION_KEY_ALIAS = SharedSTSConstants.SAML2_ENCRYPTION_KEY_ALIAS; 440 static final String SIGNATURE_KEY_ALIAS = SharedSTSConstants.SAML2_SIGNATURE_KEY_ALIAS; 441 static final String SIGNATURE_KEY_PASSWORD = SharedSTSConstants.SAML2_SIGNATURE_KEY_PASSWORD; 442 /* 443 Note that this attribute(issuer-name) was defined in STSInstanceConfig, and thus global to an STS instance. It was 444 used to set the issuer field in issued SAML2 assertions, when the STS only issued SAML2 assertions. Now that 445 OIDC tokens are also issued, the issuer-name must be scoped to the token-specific config. Thus, by convention, 446 the name of the AttributeSchema element would be saml2-issuer-name. However, changing the name of this attribute 447 would involve a schema migration step. This can be avoided by encapsulating this same attribute in the SAML2Config 448 class, and via an update to the AdminUI to describe this attribute as the IDP identifier 449 */ 450 static final String ISSUER_NAME = SharedSTSConstants.ISSUER_NAME; 451 452 private final String nameIdFormat; 453 private final Map<String, String> attributeMap; 454 private final long tokenLifetimeInSeconds; 455 private final String customConditionsProviderClassName; 456 private final String customSubjectProviderClassName; 457 private final String customAuthenticationStatementsProviderClassName; 458 private final String customAttributeStatementsProviderClassName; 459 private final String customAuthzDecisionStatementsProviderClassName; 460 private final String customAttributeMapperClassName; 461 private final String customAuthNContextMapperClassName; 462 private final String spEntityId; 463 private final String spAcsUrl; 464 private final boolean signAssertion; 465 private final boolean encryptNameID; 466 private final boolean encryptAttributes; 467 private final boolean encryptAssertion; 468 private final String encryptionAlgorithm; 469 private final int encryptionAlgorithmStrength; 470 private final String keystoreFileName; 471 private final byte[] keystorePassword; 472 private final String signatureKeyAlias; 473 private final byte[] signatureKeyPassword; 474 private final String encryptionKeyAlias; 475 private final String idpId; 476 477 private SAML2Config(SAML2ConfigBuilder builder) { 478 this.nameIdFormat = builder.nameIdFormat; //not required so don't reject if null 479 if (builder.attributeMap != null) { 480 this.attributeMap = Collections.unmodifiableMap(builder.attributeMap); 481 } else { 482 attributeMap = Collections.emptyMap(); 483 } 484 tokenLifetimeInSeconds = builder.tokenLifetimeInSeconds; //will be set to default if not explicitly set 485 customConditionsProviderClassName = builder.customConditionsProviderClassName; 486 customSubjectProviderClassName = builder.customSubjectProviderClassName; 487 customAuthenticationStatementsProviderClassName = builder.customAuthenticationStatementsProviderClassName; 488 customAuthzDecisionStatementsProviderClassName = builder.customAuthzDecisionStatementsProviderClassName; 489 customAttributeStatementsProviderClassName = builder.customAttributeStatementsProviderClassName; 490 customAttributeMapperClassName = builder.customAttributeMapperClassName; 491 customAuthNContextMapperClassName = builder.customAuthNContextMapperClassName; 492 this.signAssertion = builder.signAssertion; 493 this.encryptNameID = builder.encryptNameID; 494 this.encryptAttributes = builder.encryptAttributes; 495 this.encryptAssertion = builder.encryptAssertion; 496 this.encryptionAlgorithm = builder.encryptionAlgorithm; 497 this.encryptionAlgorithmStrength = builder.encryptionAlgorithmStrength; 498 this.keystoreFileName = builder.keystoreFileName; 499 this.keystorePassword = builder.keystorePassword; 500 this.spEntityId = builder.spEntityId; 501 this.spAcsUrl = builder.spAcsUrl; 502 this.signatureKeyAlias = builder.signatureKeyAlias; 503 this.signatureKeyPassword = builder.signatureKeyPassword; 504 this.encryptionKeyAlias = builder.encryptionKeyAlias; 505 this.idpId = builder.idpId; 506 507 if (spEntityId == null) { 508 throw new IllegalArgumentException("The entity id of the consumer (SP) for issued assertions must be specified."); 509 } 510 if (encryptAssertion || encryptNameID || encryptAttributes) { 511 if (encryptionAlgorithm == null) { 512 throw new IllegalArgumentException("If elements of the assertion are to be encrypted, an encryption " + 513 "algorithm must be specified."); 514 } 515 if (encryptionAlgorithmStrength == 0 && !XMLCipher.TRIPLEDES.equals(encryptionAlgorithm)) { 516 throw new IllegalArgumentException("If elements of the assertion are to be encrypted, an encryption " + 517 "algorithm strength must be specified."); 518 } 519 if (encryptionKeyAlias == null) { 520 throw new IllegalArgumentException("If elements of the assertion are to be encrypted, an encryption key" + 521 "alias must be specified."); 522 } 523 } 524 if (encryptAssertion || encryptNameID || encryptAttributes || signAssertion) { 525 if (keystorePassword == null || keystoreFileName == null) { 526 throw new IllegalArgumentException("If the assertions are to be signed or encrypted, then the keystore " + 527 "file and password must be specified."); 528 } 529 } 530 if (signAssertion) { 531 if ((signatureKeyPassword == null) || (signatureKeyAlias == null)) { 532 throw new IllegalArgumentException("If the assertion is to be signed, then the signature key alias and" + 533 " signature key password must be specified."); 534 } 535 } 536 537 if (encryptAssertion && (encryptNameID || encryptAttributes)) { 538 throw new IllegalArgumentException("Either the entire assertion can be encrypted, or the Attributes and/or NameID."); 539 } 540 541 if (idpId == null) { 542 throw new IllegalArgumentException("The Identity Provider id must be set."); 543 } 544 } 545 546 /** 547 * Creates a new {@code SAML2ConfigBuilder}. 548 * 549 * @return a new {@code SAML2ConfigBuilder}. 550 */ 551 public static SAML2ConfigBuilder builder() { 552 return new SAML2ConfigBuilder(); 553 } 554 555 /** 556 * Gets the name-id format. 557 * 558 * @return the name-id format. 559 */ 560 public String getNameIdFormat() { 561 return nameIdFormat; 562 } 563 564 /** 565 * Gets the token lifetime (in seconds). 566 * 567 * @return the token lifetime. 568 */ 569 public long getTokenLifetimeInSeconds() { 570 return tokenLifetimeInSeconds; 571 } 572 573 /** 574 * Gets the attribute map. 575 * 576 * @return the attribute map. 577 */ 578 public Map<String, String> getAttributeMap() { 579 return attributeMap; 580 } 581 582 /** 583 * Gets the classname of the CustomConditionsProvider. 584 * 585 * @return the classname of the CustomConditionsProvider. 586 */ 587 public String getCustomConditionsProviderClassName() { 588 return customConditionsProviderClassName; 589 } 590 591 /** 592 * Gets the classname of the CustomSubjectProvider. 593 * 594 * @return the classname of the CustomSubjectProvider. 595 */ 596 public String getCustomSubjectProviderClassName() { 597 return customSubjectProviderClassName; 598 } 599 600 /** 601 * Gets the classname of the CustomAuthenticationStatementsProvider. 602 * 603 * @return the classname of the CustomAuthenticationStatementsProvider. 604 */ 605 public String getCustomAuthenticationStatementsProviderClassName() { 606 return customAuthenticationStatementsProviderClassName; 607 } 608 609 /** 610 * Gets the classname of the CustomAttributeMapper. 611 * 612 * @return the classname of the CustomAttributeMapper. 613 */ 614 public String getCustomAttributeMapperClassName() { 615 return customAttributeMapperClassName; 616 } 617 618 /** 619 * Gets the classname of the CustomAuthNContextMapper. 620 * 621 * @return the classname of the CustomAuthNContextMapper. 622 */ 623 public String getCustomAuthNContextMapperClassName() { 624 return customAuthNContextMapperClassName; 625 } 626 627 /** 628 * Gets the classname of the CustomAttributeStatementsProvider. 629 * 630 * @return the classname of the CustomAttributeStatementsProvider. 631 */ 632 public String getCustomAttributeStatementsProviderClassName() { 633 return customAttributeStatementsProviderClassName; 634 } 635 636 /** 637 * Gets the classname of the CustomAuthzDecisionStatementsProvider. 638 * 639 * @return the classname of the CustomAuthzDecisionStatementsProvider. 640 */ 641 public String getCustomAuthzDecisionStatementsProviderClassName() { 642 return customAuthzDecisionStatementsProviderClassName; 643 } 644 645 /** 646 * Gets whether the assertion should be signed. 647 * 648 * @return whether the assertion should be signed. 649 */ 650 public boolean signAssertion() { 651 return signAssertion; 652 } 653 654 /** 655 * Gets whether the name-id should be encrypted. 656 * 657 * @return whether the name-id should be encrypted. 658 */ 659 public boolean encryptNameID() { 660 return encryptNameID; 661 } 662 663 /** 664 * Gets whether the attributes should be encrypted. 665 * 666 * @return whether the attributes should be encrypted. 667 */ 668 public boolean encryptAttributes() { 669 return encryptAttributes; 670 } 671 672 /** 673 * Gets whether the assertion should be encrypted. 674 * 675 * @return whether the assertion should be encrypted. 676 */ 677 public boolean encryptAssertion() { 678 return encryptAssertion; 679 } 680 681 /** 682 * Gets the encryption algorithm. 683 * 684 * @return the encryption algorithm. 685 */ 686 public String getEncryptionAlgorithm() { 687 return encryptionAlgorithm; 688 } 689 690 /** 691 * Gets the encryption algorithm strength. 692 * 693 * @return the encryption algorithm strength. 694 */ 695 public int getEncryptionAlgorithmStrength() { 696 return encryptionAlgorithmStrength; 697 } 698 699 /** 700 * Gets the keystore filename. 701 * 702 * @return the keystore filename. 703 */ 704 public String getKeystoreFileName() { 705 return keystoreFileName; 706 } 707 708 /** 709 * Gets the keystore password. 710 * 711 * @return they keystore password. 712 */ 713 public byte[] getKeystorePassword() { 714 return keystorePassword; 715 } 716 717 /** 718 * Gets the SP entity id. 719 * 720 * @return the SP entity id. 721 */ 722 public String getSpEntityId() { 723 return spEntityId; 724 } 725 726 /** 727 * Gets the SP ACS url. 728 * 729 * @return the SP ACS url. 730 */ 731 public String getSpAcsUrl() { 732 return spAcsUrl; 733 } 734 735 /** 736 * Gets the encryption key alias. 737 * 738 * @return the encryption key alias. 739 */ 740 public String getEncryptionKeyAlias() { 741 return encryptionKeyAlias; 742 } 743 744 /** 745 * Gets the signature key alias. 746 * 747 * @return the signature key alias. 748 */ 749 public String getSignatureKeyAlias() { 750 return signatureKeyAlias; 751 } 752 753 /** 754 * Gets the signature key password. 755 * 756 * @return the signature key password. 757 */ 758 public byte[] getSignatureKeyPassword() { 759 return signatureKeyPassword; 760 } 761 762 /** 763 * Gets the Identity Provider id. 764 * 765 * @return the Identity Provider id. 766 */ 767 public String getIdpId() { 768 return idpId; 769 } 770 771 /** 772 * {@inheritDoc} 773 */ 774 @Override 775 public String toString() { 776 StringBuilder sb = new StringBuilder(); 777 sb.append("SAML2Config instance:").append('\n'); 778 sb.append('\t').append("IDP id: ").append(idpId).append('\n'); 779 sb.append('\t').append("nameIDFormat: ").append(nameIdFormat).append('\n'); 780 sb.append('\t').append("attributeMap: ").append(attributeMap).append('\n'); 781 sb.append('\t').append("tokenLifetimeInSeconds: ").append(tokenLifetimeInSeconds).append('\n'); 782 sb.append('\t').append("customConditionsProviderClassName: ").append(customConditionsProviderClassName).append('\n'); 783 sb.append('\t').append("customSubjectProviderClassName: ").append(customSubjectProviderClassName).append('\n'); 784 sb.append('\t').append("customAttributeStatementsProviderClassName: ").append(customAttributeStatementsProviderClassName).append('\n'); 785 sb.append('\t').append("customAttributeMapperClassName: ").append(customAttributeMapperClassName).append('\n'); 786 sb.append('\t').append("customAuthNContextMapperClassName: ").append(customAuthNContextMapperClassName).append('\n'); 787 sb.append('\t').append("customAuthenticationStatementsProviderClassName: ").append(customAuthenticationStatementsProviderClassName).append('\n'); 788 sb.append('\t').append("customAuthzDecisionStatementsProviderClassName: ").append(customAuthzDecisionStatementsProviderClassName).append('\n'); 789 sb.append('\t').append("Sign assertion ").append(signAssertion).append('\n'); 790 sb.append('\t').append("Encrypt NameID ").append(encryptNameID).append('\n'); 791 sb.append('\t').append("Encrypt Attributes ").append(encryptAttributes).append('\n'); 792 sb.append('\t').append("Encrypt Assertion ").append(encryptAssertion).append('\n'); 793 sb.append('\t').append("Encryption Algorithm ").append(encryptionAlgorithm).append('\n'); 794 sb.append('\t').append("Encryption Algorithm Strength ").append(encryptionAlgorithmStrength).append('\n'); 795 sb.append('\t').append("Keystore File ").append(keystoreFileName).append('\n'); 796 sb.append('\t').append("Keystore Password ").append("xxx").append('\n'); 797 sb.append('\t').append("SP Entity Id ").append(spEntityId).append('\n'); 798 sb.append('\t').append("SP ACS URL ").append(spAcsUrl).append('\n'); 799 sb.append('\t').append("Encryption key alias ").append(encryptionKeyAlias).append('\n'); 800 sb.append('\t').append("Signature key alias").append(signatureKeyAlias).append('\n'); 801 return sb.toString(); 802 } 803 804 /** 805 * {@inheritDoc} 806 */ 807 @Override 808 public boolean equals(Object other) { 809 if (other instanceof SAML2Config) { 810 SAML2Config otherConfig = (SAML2Config)other; 811 return nameIdFormat.equals(otherConfig.nameIdFormat) && 812 idpId.equals(otherConfig.idpId) && 813 tokenLifetimeInSeconds == otherConfig.tokenLifetimeInSeconds && 814 attributeMap.equals(otherConfig.attributeMap) && 815 signAssertion == otherConfig.signAssertion && 816 encryptAssertion == otherConfig.encryptAssertion && 817 encryptAttributes == otherConfig.encryptAttributes && 818 encryptNameID == otherConfig.encryptNameID && 819 encryptionAlgorithmStrength == otherConfig.encryptionAlgorithmStrength && 820 spEntityId.equals(otherConfig.spEntityId) && 821 Objects.equal(encryptionAlgorithm, otherConfig.encryptionAlgorithm) && 822 Objects.equal(customConditionsProviderClassName, otherConfig.customConditionsProviderClassName) && 823 Objects.equal(customSubjectProviderClassName, otherConfig.customSubjectProviderClassName) && 824 Objects.equal(customAttributeStatementsProviderClassName, otherConfig.customAttributeStatementsProviderClassName) && 825 Objects.equal(customAuthzDecisionStatementsProviderClassName, otherConfig.customAuthzDecisionStatementsProviderClassName) && 826 Objects.equal(customAttributeMapperClassName, otherConfig.customAttributeMapperClassName) && 827 Objects.equal(customAuthNContextMapperClassName, otherConfig.customAuthNContextMapperClassName) && 828 Objects.equal(customAuthenticationStatementsProviderClassName, otherConfig.customAuthenticationStatementsProviderClassName) && 829 Objects.equal(keystoreFileName, otherConfig.keystoreFileName) && 830 Arrays.equals(keystorePassword, otherConfig.keystorePassword) && 831 Objects.equal(spAcsUrl, otherConfig.spAcsUrl) && 832 Objects.equal(signatureKeyAlias, otherConfig.signatureKeyAlias) && 833 Objects.equal(encryptionKeyAlias, otherConfig.encryptionKeyAlias) && 834 Arrays.equals(signatureKeyPassword, otherConfig.signatureKeyPassword); 835 } 836 return false; 837 } 838 839 /** 840 * {@inheritDoc} 841 */ 842 @Override 843 public int hashCode() { 844 return (nameIdFormat + attributeMap + spEntityId + Long.toString(tokenLifetimeInSeconds)).hashCode(); 845 } 846 847 /** 848 * Gets the {@link JsonValue} representation of the SAML2Config. 849 * 850 * @return The {@link JsonValue} representation of the SAML2Config. 851 */ 852 public JsonValue toJson() { 853 /* 854 Because toJson will be used to produce the map that will also be used to marshal to the SMS attribute map 855 format, and because the SMS attribute map format represents all values as Set<String>, I need to represent all 856 of the json values as strings as well. 857 */ 858 try { 859 return json(object( 860 field(ISSUER_NAME, idpId), 861 field(NAME_ID_FORMAT, nameIdFormat), 862 field(TOKEN_LIFETIME, String.valueOf(tokenLifetimeInSeconds)), 863 field(CUSTOM_CONDITIONS_PROVIDER_CLASS, customConditionsProviderClassName), 864 field(CUSTOM_SUBJECT_PROVIDER_CLASS, customSubjectProviderClassName), 865 field(CUSTOM_ATTRIBUTE_STATEMENTS_PROVIDER_CLASS, customAttributeStatementsProviderClassName), 866 field(CUSTOM_ATTRIBUTE_MAPPER_CLASS, customAttributeMapperClassName), 867 field(CUSTOM_AUTHN_CONTEXT_MAPPER_CLASS, customAuthNContextMapperClassName), 868 field(CUSTOM_AUTHENTICATION_STATEMENTS_PROVIDER_CLASS, customAuthenticationStatementsProviderClassName), 869 field(CUSTOM_AUTHZ_DECISION_STATEMENTS_PROVIDER_CLASS, customAuthzDecisionStatementsProviderClassName), 870 field(SIGN_ASSERTION, String.valueOf(signAssertion)), 871 field(ENCRYPT_ASSERTION, String.valueOf(encryptAssertion)), 872 field(ENCRYPT_ATTRIBUTES, String.valueOf(encryptAttributes)), 873 field(ENCRYPT_NAME_ID, String.valueOf(encryptNameID)), 874 field(ENCRYPTION_ALGORITHM, encryptionAlgorithm), 875 field(ENCRYPTION_ALGORITHM_STRENGTH, String.valueOf(encryptionAlgorithmStrength)), 876 field(ATTRIBUTE_MAP, attributeMap), 877 field(KEYSTORE_FILE_NAME, keystoreFileName), 878 field(KEYSTORE_PASSWORD, 879 keystorePassword != null ? new String(keystorePassword, AMSTSConstants.UTF_8_CHARSET_ID) : null), 880 field(SP_ACS_URL, spAcsUrl), 881 field(SP_ENTITY_ID, spEntityId), 882 field(SIGNATURE_KEY_ALIAS, signatureKeyAlias), 883 field(SIGNATURE_KEY_PASSWORD, 884 signatureKeyPassword != null ? new String(signatureKeyPassword, AMSTSConstants.UTF_8_CHARSET_ID) : null), 885 field(ENCRYPTION_KEY_ALIAS, encryptionKeyAlias))); 886 } catch (UnsupportedEncodingException e) { 887 throw new IllegalStateException("Unsupported encoding when marshalling from String to to byte[]: " + e, e); 888 } 889 } 890 891 /** 892 * Creates a SAML2Config object from a {@link JsonValue} representation 893 * 894 * @param json the {@link JsonValue} representation. 895 * @return a SAML2Config object 896 * @throws IllegalStateException 897 */ 898 public static SAML2Config fromJson(JsonValue json) throws IllegalStateException { 899 try { 900 return SAML2Config.builder() 901 .idpId(json.get(ISSUER_NAME).asString()) 902 .nameIdFormat(json.get(NAME_ID_FORMAT).asString()) 903 //because we have to go to the SMS Map representation, where all values are Set<String>, I need to 904 // pull the value from Json as a string, and then parse out a Long. 905 .tokenLifetimeInSeconds(Long.valueOf(json.get(TOKEN_LIFETIME).asString())) 906 .customConditionsProviderClassName(json.get(CUSTOM_CONDITIONS_PROVIDER_CLASS).asString()) 907 .customSubjectProviderClassName(json.get(CUSTOM_SUBJECT_PROVIDER_CLASS).asString()) 908 .customAttributeStatementsProviderClassName(json.get(CUSTOM_ATTRIBUTE_STATEMENTS_PROVIDER_CLASS).asString()) 909 .customAttributeMapperClassName(json.get(CUSTOM_ATTRIBUTE_MAPPER_CLASS).asString()) 910 .customAuthNContextMapperClassName(json.get(CUSTOM_AUTHN_CONTEXT_MAPPER_CLASS).asString()) 911 .customAuthenticationStatementsProviderClassName(json.get(CUSTOM_AUTHENTICATION_STATEMENTS_PROVIDER_CLASS).asString()) 912 .customAuthzDecisionStatementsProviderClassName(json.get(CUSTOM_AUTHZ_DECISION_STATEMENTS_PROVIDER_CLASS).asString()) 913 .signAssertion(Boolean.valueOf(json.get(SIGN_ASSERTION).asString())) 914 .encryptAssertion(Boolean.valueOf(json.get(ENCRYPT_ASSERTION).asString())) 915 .encryptNameID(Boolean.valueOf(json.get(ENCRYPT_NAME_ID).asString())) 916 .encryptAttributes(Boolean.valueOf(json.get(ENCRYPT_ATTRIBUTES).asString())) 917 .encryptionAlgorithm(json.get(ENCRYPTION_ALGORITHM).asString()) 918 .encryptionAlgorithmStrength(Integer.valueOf(json.get(ENCRYPTION_ALGORITHM_STRENGTH).asString())) 919 .attributeMap(json.get(ATTRIBUTE_MAP).asMap(String.class)) 920 .keystoreFile(json.get(KEYSTORE_FILE_NAME).asString()) 921 .keystorePassword(json.get(KEYSTORE_PASSWORD).isString() 922 ? json.get(KEYSTORE_PASSWORD).asString().getBytes(AMSTSConstants.UTF_8_CHARSET_ID) : null) 923 .signatureKeyPassword(json.get(SIGNATURE_KEY_PASSWORD).isString() 924 ? json.get(SIGNATURE_KEY_PASSWORD).asString().getBytes(AMSTSConstants.UTF_8_CHARSET_ID) : null) 925 .signatureKeyAlias(json.get(SIGNATURE_KEY_ALIAS).asString()) 926 .spAcsUrl(json.get(SP_ACS_URL).asString()) 927 .spEntityId(json.get(SP_ENTITY_ID).asString()) 928 .encryptionKeyAlias(json.get(ENCRYPTION_KEY_ALIAS).asString()) 929 .build(); 930 } catch (UnsupportedEncodingException e) { 931 throw new IllegalStateException("Unsupported encoding when marshalling from String to to byte[]: " + e, e); 932 } 933 } 934 935 /** 936 * Marshals the SAML2Config into an attribute map 937 * 938 * @return a map containing the SAML2Config attributes. 939 */ 940 public Map<String, Set<String>> marshalToAttributeMap() { 941 /* 942 We need to marshal the SAML2Config instance to a Map<String, Object>. The JsonValue of toJson gets us there, 943 except for the complex types for the audiences and attribute map. These need to be marshaled into aSet<String>, 944 and these entries included in the top-level map, replacing the existing complex entries. 945 */ 946 Map<String, Object> preMap = toJson().asMap(); 947 Map<String, Set<String>> finalMap = MapMarshallUtils.toSmsMap(preMap); 948 Object attributesObject = preMap.get(ATTRIBUTE_MAP); 949 if (attributesObject instanceof Map) { 950 finalMap.remove(ATTRIBUTE_MAP); 951 Set<String> attributeValues = new LinkedHashSet<>(); 952 finalMap.put(ATTRIBUTE_MAP, attributeValues); 953 for (Map.Entry<String, String> entry : ((Map<String, String>)attributesObject).entrySet()) { 954 attributeValues.add(entry.getKey() + EQUALS + entry.getValue()); 955 } 956 } else { 957 throw new IllegalStateException("Type corresponding to " + ATTRIBUTE_MAP + " key unexpected. Type: " 958 + (attributesObject != null ? attributesObject.getClass().getName() :" null")); 959 } 960 return finalMap; 961 } 962 963 /** 964 * Marshals an attribute map into a SAML2Config 965 * 966 * @param smsAttributeMap the attribute map. 967 * @return a SAML2Config object. 968 */ 969 public static SAML2Config marshalFromAttributeMap(Map<String, Set<String>> smsAttributeMap) { 970 /* 971 Here we have to modify the ATTRIBUTE_MAP and AUDIENCES entries to match the JsonValue format expected by 972 fromJson, and then call the static fromJson. This method must marshal between the Json representation of a 973 complex object, and the representation expected by the SMS 974 */ 975 Set<String> issuerName = smsAttributeMap.get(ISSUER_NAME); 976 /* 977 The STSInstanceConfig may not have SAML2Config, if there are no defined token transformations that result 978 in a SAML2 assertion. So we check for the ISSUER_NAME attribute, which is the IdP id, a mandatory field if 979 SAML2 assertions are to be issued. 980 */ 981 if (CollectionUtils.isEmpty(issuerName)) { 982 return null; 983 } 984 Map<String, Object> jsonAttributes = MapMarshallUtils.toJsonValueMap(smsAttributeMap); 985 jsonAttributes.remove(ATTRIBUTE_MAP); 986 Set<String> attributes = smsAttributeMap.get(ATTRIBUTE_MAP); 987 Map<String, Object> jsonAttributeMap = new LinkedHashMap<>(); 988 for (String entry : attributes) { 989 String[] breakdown = entry.split(EQUALS); 990 jsonAttributeMap.put(breakdown[0], breakdown[1]); 991 } 992 jsonAttributes.put(ATTRIBUTE_MAP, new JsonValue(jsonAttributeMap)); 993 994 return fromJson(new JsonValue(jsonAttributes)); 995 } 996 997 /** 998 * Returns an empty attribute map. 999 * 1000 * @return an empty attribute map. 1001 */ 1002 public static Map<String, Set<String>> getEmptySMSAttributeState() { 1003 /* 1004 This method is called from Rest/SoapSTSInstanceConfig if the encapsulated SAML2Config reference is null. It 1005 should return a Map<String,Set<String>> for each of the sms attributes defined for the SAML2Config object, with 1006 an empty Set<String> value, so that SMS writes will over-write any previous, non-null values. This will occur 1007 in the AdminUI when a sts instance goes from issuing SAML2 tokens, to not issuing these token types. 1008 */ 1009 HashMap<String, Set<String>> emptyAttributeMap = new HashMap<>(); 1010 emptyAttributeMap.put(NAME_ID_FORMAT, Collections.<String>emptySet()); 1011 emptyAttributeMap.put(ATTRIBUTE_MAP, Collections.<String>emptySet()); 1012 emptyAttributeMap.put(TOKEN_LIFETIME, Collections.<String>emptySet()); 1013 emptyAttributeMap.put(CUSTOM_CONDITIONS_PROVIDER_CLASS, Collections.<String>emptySet()); 1014 emptyAttributeMap.put(CUSTOM_SUBJECT_PROVIDER_CLASS, Collections.<String>emptySet()); 1015 emptyAttributeMap.put(CUSTOM_ATTRIBUTE_STATEMENTS_PROVIDER_CLASS, Collections.<String>emptySet()); 1016 emptyAttributeMap.put(CUSTOM_AUTHENTICATION_STATEMENTS_PROVIDER_CLASS, Collections.<String>emptySet()); 1017 emptyAttributeMap.put(CUSTOM_AUTHZ_DECISION_STATEMENTS_PROVIDER_CLASS, Collections.<String>emptySet()); 1018 emptyAttributeMap.put(CUSTOM_ATTRIBUTE_MAPPER_CLASS, Collections.<String>emptySet()); 1019 emptyAttributeMap.put(CUSTOM_AUTHN_CONTEXT_MAPPER_CLASS, Collections.<String>emptySet()); 1020 emptyAttributeMap.put(SIGN_ASSERTION, Collections.<String>emptySet()); 1021 emptyAttributeMap.put(ENCRYPT_ATTRIBUTES, Collections.<String>emptySet()); 1022 emptyAttributeMap.put(ENCRYPT_NAME_ID, Collections.<String>emptySet()); 1023 emptyAttributeMap.put(ENCRYPT_ASSERTION, Collections.<String>emptySet()); 1024 emptyAttributeMap.put(ENCRYPTION_ALGORITHM, Collections.<String>emptySet()); 1025 emptyAttributeMap.put(ENCRYPTION_ALGORITHM_STRENGTH, Collections.<String>emptySet()); 1026 emptyAttributeMap.put(KEYSTORE_FILE_NAME, Collections.<String>emptySet()); 1027 emptyAttributeMap.put(KEYSTORE_PASSWORD, Collections.<String>emptySet()); 1028 emptyAttributeMap.put(SP_ENTITY_ID, Collections.<String>emptySet()); 1029 emptyAttributeMap.put(SP_ACS_URL, Collections.<String>emptySet()); 1030 emptyAttributeMap.put(ENCRYPTION_KEY_ALIAS, Collections.<String>emptySet()); 1031 emptyAttributeMap.put(SIGNATURE_KEY_ALIAS, Collections.<String>emptySet()); 1032 emptyAttributeMap.put(SIGNATURE_KEY_PASSWORD, Collections.<String>emptySet()); 1033 emptyAttributeMap.put(ISSUER_NAME, Collections.<String>emptySet()); 1034 return emptyAttributeMap; 1035 } 1036}