Skip to content

Commit 6ec2647

Browse files
authored
Do not set a NameID format in Policy by default (elastic#44090)
This commit changes the behavior of our SAML realm to not set a Format element in the NameIDPolicy of a SAML Authentication request if one has not been explicitly configured by the user with `nameid_format`. We select to not include a format, rather than setting it to `urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified` which would have the same effect, in order to maximize interoperability with IdP implementations. `AllowCreate` is not removed as this has a default value (false) in the specification. Relates: elastic#40353
1 parent bf2f103 commit 6ec2647

File tree

8 files changed

+41
-16
lines changed

8 files changed

+41
-16
lines changed

docs/reference/settings/security-settings.asciidoc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -938,11 +938,10 @@ As per `attribute_patterns.principal`, but for the _dn_ property.
938938

939939
`nameid_format`::
940940
The NameID format that should be requested when asking the IdP to authenticate
941-
the current user. Defaults to requesting _transient_ names
942-
(`urn:oasis:names:tc:SAML:2.0:nameid-format:transient`).
941+
the current user. The default is to not include the `nameid_format` attribute.
943942

944943
`nameid.allow_create`:: The value of the `AllowCreate` attribute of the
945-
`NameIdPolicy` element in an authentication request. Defaults to `false`.
944+
`NameIdPolicy` element in an authentication request. The default value is false.
946945

947946
`nameid.sp_qualifier`:: The value of the `SPNameQualifier` attribute of the
948947
`NameIdPolicy` element in an authentication request. The default is to not

x-pack/docs/en/security/authentication/saml-guide.asciidoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ additional names that can be used:
266266
mechanism that will cause an error if you attempt to map from a `NameID`
267267
that does not have a persistent value.
268268

269+
NOTE: Identity Providers can be either statically configured to release a `NameID`
270+
with a specific format, or they can be configured to try to conform with the
271+
requirements of the SP. The SP declares its requirements as part of the
272+
Authentication Request, using an element which is called the `NameIDPolicy`. If
273+
this is needed, you can set the relevant <<saml-settings, settings>> named
274+
`nameid_format` in order to request that the IdP releases a `NameID` with a
275+
specific format.
276+
269277
_friendlyName_::
270278
A SAML attribute may have a _friendlyName_ in addition to its URI based name.
271279
For example the attribute with a name of `urn:oid:0.9.2342.19200300.100.1.1`

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/saml/SamlRealmSettings.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
public class SamlRealmSettings {
2525

2626
public static final String TYPE = "saml";
27-
private static final String TRANSIENT_NAMEID_FORMAT = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";
2827

2928
// these settings will be used under the prefix xpack.security.authc.realms.REALM_NAME.
3029
private static final String IDP_METADATA_SETTING_PREFIX = "idp.metadata.";
@@ -49,9 +48,8 @@ public class SamlRealmSettings {
4948
public static final Setting.AffixSetting<String> SP_ACS = RealmSettings.simpleString(TYPE, "sp.acs", Setting.Property.NodeScope);
5049
public static final Setting.AffixSetting<String> SP_LOGOUT = RealmSettings.simpleString(TYPE, "sp.logout", Setting.Property.NodeScope);
5150

52-
public static final Setting.AffixSetting<String> NAMEID_FORMAT = Setting.affixKeySetting(
53-
RealmSettings.realmSettingPrefix(TYPE), "nameid_format",
54-
key -> new Setting<>(key, s -> TRANSIENT_NAMEID_FORMAT, Function.identity(), Setting.Property.NodeScope));
51+
public static final Setting.AffixSetting<String> NAMEID_FORMAT
52+
= RealmSettings.simpleString(TYPE, "nameid_format", Setting.Property.NodeScope);
5553

5654
public static final Setting.AffixSetting<Boolean> NAMEID_ALLOW_CREATE = Setting.affixKeySetting(
5755
RealmSettings.realmSettingPrefix(TYPE), "nameid.allow_create",

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlAuthnRequestBuilder.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.opensaml.saml.saml2.core.AuthnContextClassRef;
1111
import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
1212
import org.opensaml.saml.saml2.core.AuthnRequest;
13-
import org.opensaml.saml.saml2.core.NameID;
1413
import org.opensaml.saml.saml2.core.NameIDPolicy;
1514
import org.opensaml.saml.saml2.core.RequestedAuthnContext;
1615
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
@@ -31,7 +30,7 @@ class SamlAuthnRequestBuilder extends SamlMessageBuilder {
3130
super(idpDescriptor, spConfig, clock);
3231
this.spBinding = spBinding;
3332
this.idpBinding = idBinding;
34-
this.nameIdSettings = new NameIDPolicySettings(NameID.TRANSIENT, false, null);
33+
this.nameIdSettings = new NameIDPolicySettings(null, false, null);
3534
}
3635

3736
SamlAuthnRequestBuilder forceAuthn(Boolean forceAuthn) {
@@ -80,7 +79,7 @@ private RequestedAuthnContext buildRequestedAuthnContext() {
8079

8180
private NameIDPolicy buildNameIDPolicy() {
8281
NameIDPolicy nameIDPolicy = SamlUtils.buildObject(NameIDPolicy.class, NameIDPolicy.DEFAULT_ELEMENT_NAME);
83-
nameIDPolicy.setFormat(nameIdSettings.format);
82+
nameIDPolicy.setFormat(Strings.isNullOrEmpty(nameIdSettings.format) ? null : nameIdSettings.format);
8483
nameIDPolicy.setAllowCreate(nameIdSettings.allowCreate);
8584
nameIDPolicy.setSPNameQualifier(Strings.isNullOrEmpty(nameIdSettings.spNameQualifier) ? null : nameIdSettings.spNameQualifier);
8685
return nameIDPolicy;

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlRealm.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public static SamlRealm create(RealmConfig config, SSLService sslService, Resour
218218
this.idpDescriptor = idpDescriptor;
219219
this.serviceProvider = spConfiguration;
220220

221-
this.nameIdPolicy = new SamlAuthnRequestBuilder.NameIDPolicySettings(require(config, NAMEID_FORMAT),
221+
this.nameIdPolicy = new SamlAuthnRequestBuilder.NameIDPolicySettings(config.getSetting(NAMEID_FORMAT),
222222
config.getSetting(NAMEID_ALLOW_CREATE), config.getSetting(NAMEID_SP_QUALIFIER));
223223
this.forceAuthn = config.getSetting(FORCE_AUTHN, () -> null);
224224
this.useSingleLogout = config.getSetting(IDP_SINGLE_LOGOUT);

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/saml/SamlSpMetadataBuilder.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import org.elasticsearch.common.Strings;
99
import org.elasticsearch.common.collect.MapBuilder;
1010
import org.opensaml.saml.common.xml.SAMLConstants;
11-
import org.opensaml.saml.saml2.core.NameID;
1211
import org.opensaml.saml.saml2.metadata.AssertionConsumerService;
1312
import org.opensaml.saml.saml2.metadata.AttributeConsumingService;
1413
import org.opensaml.saml.saml2.metadata.ContactPerson;
@@ -92,7 +91,7 @@ public SamlSpMetadataBuilder(Locale locale, String entityId) {
9291
this.attributeNames = new LinkedHashMap<>();
9392
this.contacts = new ArrayList<>();
9493
this.serviceName = "Elasticsearch";
95-
this.nameIdFormat = NameID.TRANSIENT;
94+
this.nameIdFormat = null;
9695
this.authnRequestsSigned = Boolean.FALSE;
9796
}
9897

@@ -222,7 +221,7 @@ public EntityDescriptor build() throws Exception {
222221
spRoleDescriptor.setWantAssertionsSigned(true);
223222
spRoleDescriptor.setAuthnRequestsSigned(this.authnRequestsSigned);
224223

225-
if (Strings.hasLength(nameIdFormat)) {
224+
if (Strings.isNullOrEmpty(nameIdFormat) == false) {
226225
spRoleDescriptor.getNameIDFormats().add(buildNameIdFormat());
227226
}
228227
spRoleDescriptor.getAssertionConsumerServices().add(buildAssertionConsumerService());
@@ -247,6 +246,9 @@ public EntityDescriptor build() throws Exception {
247246
}
248247

249248
private NameIDFormat buildNameIdFormat() {
249+
if (Strings.isNullOrEmpty(nameIdFormat)) {
250+
throw new IllegalStateException("NameID format has not been specified");
251+
}
250252
final NameIDFormat format = new NameIDFormatBuilder().buildObject();
251253
format.setFormat(this.nameIdFormat);
252254
return format;

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlAuthnRequestBuilderTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,26 @@ public void init() throws Exception {
5151
idpDescriptor.getRoleDescriptors().add(idpRole);
5252
}
5353

54+
public void testBuildRequestWithDefaultSettingsHasNoNameIdPolicy() {
55+
SpConfiguration sp = new SpConfiguration(SP_ENTITY_ID, ACS_URL, null, null, null, Collections.emptyList());
56+
final SamlAuthnRequestBuilder builder = new SamlAuthnRequestBuilder(
57+
sp, SAMLConstants.SAML2_POST_BINDING_URI,
58+
idpDescriptor, SAMLConstants.SAML2_REDIRECT_BINDING_URI,
59+
Clock.systemUTC());
60+
61+
final AuthnRequest request = buildAndValidateAuthnRequest(builder);
62+
63+
assertThat(request.getIssuer().getValue(), equalTo(SP_ENTITY_ID));
64+
assertThat(request.getProtocolBinding(), equalTo(SAMLConstants.SAML2_POST_BINDING_URI));
65+
66+
assertThat(request.getAssertionConsumerServiceURL(), equalTo(ACS_URL));
67+
68+
assertThat(request.getNameIDPolicy(), notNullValue());
69+
assertThat(request.getNameIDPolicy().getFormat(), nullValue());
70+
assertThat(request.getNameIDPolicy().getSPNameQualifier(), nullValue());
71+
assertThat(request.getNameIDPolicy().getAllowCreate(), equalTo(Boolean.FALSE));
72+
}
73+
5474
public void testBuildRequestWithPersistentNameAndNoForceAuth() throws Exception {
5575
SpConfiguration sp = new SpConfiguration(SP_ENTITY_ID, ACS_URL, null, null, null, Collections.emptyList());
5676
final SamlAuthnRequestBuilder builder = new SamlAuthnRequestBuilder(

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlSpMetadataBuilderTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ public void testBuildMinimalistMetadata() throws Exception {
7171
"<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"https://my.sp.example.net/\">" +
7272
"<md:SPSSODescriptor AuthnRequestsSigned=\"false\" WantAssertionsSigned=\"true\"" +
7373
" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">" +
74-
"<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>" +
7574
"<md:AssertionConsumerService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"" +
7675
" Location=\"https://my.sp.example.net/saml/acs/post\" index=\"1\" isDefault=\"true\"/>" +
7776
"</md:SPSSODescriptor>" +
@@ -307,4 +306,4 @@ public void testAttributeNameIsRequired() {
307306
private void assertValidXml(String xml) throws Exception {
308307
SamlUtils.validate(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)), SamlMetadataCommand.METADATA_SCHEMA);
309308
}
310-
}
309+
}

0 commit comments

Comments
 (0)