forked from elastic/elasticsearch
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for splitting saml groups by delimiter (elastic#102769)
* Add support for splitting saml groups by delimiter
- Loading branch information
Showing
4 changed files
with
284 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -352,14 +352,30 @@ public void testAuthenticateWithRoleMapping() throws Exception { | |
final boolean principalIsEmailAddress = randomBoolean(); | ||
final Boolean populateUserMetadata = randomFrom(Boolean.TRUE, Boolean.FALSE, null); | ||
final String authenticatingRealm = randomBoolean() ? REALM_NAME : null; | ||
AuthenticationResult<User> result = performAuthentication( | ||
roleMapper, | ||
useNameId, | ||
principalIsEmailAddress, | ||
populateUserMetadata, | ||
false, | ||
authenticatingRealm | ||
); | ||
final boolean testWithDelimiter = randomBoolean(); | ||
final AuthenticationResult<User> result; | ||
|
||
if (testWithDelimiter) { | ||
result = performAuthentication( | ||
roleMapper, | ||
useNameId, | ||
principalIsEmailAddress, | ||
populateUserMetadata, | ||
false, | ||
authenticatingRealm, | ||
List.of("STRIKE Team: Delta$shield"), | ||
"$" | ||
); | ||
} else { | ||
result = performAuthentication( | ||
roleMapper, | ||
useNameId, | ||
principalIsEmailAddress, | ||
populateUserMetadata, | ||
false, | ||
authenticatingRealm | ||
); | ||
} | ||
assertThat(result, notNullValue()); | ||
assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.SUCCESS)); | ||
assertThat(result.getValue().principal(), equalTo(useNameId ? "clint.barton" : "cbarton")); | ||
|
@@ -377,7 +393,11 @@ public void testAuthenticateWithRoleMapping() throws Exception { | |
} | ||
|
||
assertThat(userData.get().getUsername(), equalTo(useNameId ? "clint.barton" : "cbarton")); | ||
assertThat(userData.get().getGroups(), containsInAnyOrder("avengers", "shield")); | ||
if (testWithDelimiter) { | ||
assertThat(userData.get().getGroups(), containsInAnyOrder("STRIKE Team: Delta", "shield")); | ||
} else { | ||
assertThat(userData.get().getGroups(), containsInAnyOrder("avengers", "shield")); | ||
} | ||
} | ||
|
||
public void testAuthenticateWithAuthorizingRealm() throws Exception { | ||
|
@@ -431,6 +451,28 @@ private AuthenticationResult<User> performAuthentication( | |
Boolean populateUserMetadata, | ||
boolean useAuthorizingRealm, | ||
String authenticatingRealm | ||
) throws Exception { | ||
return performAuthentication( | ||
roleMapper, | ||
useNameId, | ||
principalIsEmailAddress, | ||
populateUserMetadata, | ||
useAuthorizingRealm, | ||
authenticatingRealm, | ||
Arrays.asList("avengers", "shield"), | ||
null | ||
); | ||
} | ||
|
||
private AuthenticationResult<User> performAuthentication( | ||
UserRoleMapper roleMapper, | ||
boolean useNameId, | ||
boolean principalIsEmailAddress, | ||
Boolean populateUserMetadata, | ||
boolean useAuthorizingRealm, | ||
String authenticatingRealm, | ||
List<String> groups, | ||
String groupsDelimiter | ||
) throws Exception { | ||
final EntityDescriptor idp = mockIdp(); | ||
final SpConfiguration sp = new SpConfiguration("<sp>", "https://saml/", null, null, null, Collections.emptyList()); | ||
|
@@ -453,8 +495,12 @@ private AuthenticationResult<User> performAuthentication( | |
|
||
final Settings.Builder settingsBuilder = Settings.builder() | ||
.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.PRINCIPAL_ATTRIBUTE.getAttribute()), useNameId ? "nameid" : "uid") | ||
.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.GROUPS_ATTRIBUTE.getAttribute()), "groups") | ||
.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.GROUPS_ATTRIBUTE.getAttributeSetting().getAttribute()), "groups") | ||
.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.MAIL_ATTRIBUTE.getAttribute()), "mail"); | ||
|
||
if (groupsDelimiter != null) { | ||
settingsBuilder.put(getFullSettingKey(REALM_NAME, SamlRealmSettings.GROUPS_ATTRIBUTE.getDelimiter()), groupsDelimiter); | ||
} | ||
if (principalIsEmailAddress) { | ||
final boolean anchoredMatch = randomBoolean(); | ||
settingsBuilder.put( | ||
|
@@ -497,7 +543,7 @@ private AuthenticationResult<User> performAuthentication( | |
randomAlphaOfLength(16), | ||
Arrays.asList( | ||
new SamlAttributes.SamlAttribute("urn:oid:0.9.2342.19200300.100.1.1", "uid", Collections.singletonList(uidValue)), | ||
new SamlAttributes.SamlAttribute("urn:oid:1.3.6.1.4.1.5923.1.5.1.1", "groups", Arrays.asList("avengers", "shield")), | ||
new SamlAttributes.SamlAttribute("urn:oid:1.3.6.1.4.1.5923.1.5.1.1", "groups", groups), | ||
new SamlAttributes.SamlAttribute("urn:oid:0.9.2342.19200300.100.1.3", "mail", Arrays.asList("[email protected]")) | ||
) | ||
); | ||
|
@@ -534,7 +580,120 @@ public SamlRealm buildRealm( | |
} | ||
} | ||
|
||
public void testAttributeSelectionWithRegex() throws Exception { | ||
public void testAttributeSelectionWithSplit() { | ||
List<String> strings = performAttributeSelectionWithSplit(",", "departments", "engineering", "elasticsearch-admins", "employees"); | ||
assertThat("For attributes: " + strings, strings, contains("engineering", "elasticsearch-admins", "employees")); | ||
} | ||
|
||
public void testAttributeSelectionWithSplitEmptyInput() { | ||
List<String> strings = performAttributeSelectionWithSplit(",", "departments"); | ||
assertThat("For attributes: " + strings, strings, is(empty())); | ||
} | ||
|
||
public void testAttributeSelectionWithSplitJustDelimiter() { | ||
List<String> strings = performAttributeSelectionWithSplit(",", ","); | ||
assertThat("For attributes: " + strings, strings, is(empty())); | ||
} | ||
|
||
public void testAttributeSelectionWithSplitNoDelimiter() { | ||
List<String> strings = performAttributeSelectionWithSplit(",", "departments", "elasticsearch-team"); | ||
assertThat("For attributes: " + strings, strings, contains("elasticsearch-team")); | ||
} | ||
|
||
private List<String> performAttributeSelectionWithSplit(String delimiter, String groupAttributeName, String... returnedGroups) { | ||
final Settings settings = Settings.builder() | ||
.put(REALM_SETTINGS_PREFIX + ".attributes.groups", groupAttributeName) | ||
.put(REALM_SETTINGS_PREFIX + ".attribute_delimiters.groups", delimiter) | ||
.build(); | ||
|
||
final RealmConfig config = buildConfig(settings); | ||
|
||
final SamlRealmSettings.AttributeSettingWithDelimiter groupSetting = new SamlRealmSettings.AttributeSettingWithDelimiter("groups"); | ||
final SamlRealm.AttributeParser parser = SamlRealm.AttributeParser.forSetting(logger, groupSetting, config); | ||
|
||
final SamlAttributes attributes = new SamlAttributes( | ||
new SamlNameId(NameIDType.TRANSIENT, randomAlphaOfLength(24), null, null, null), | ||
randomAlphaOfLength(16), | ||
Collections.singletonList( | ||
new SamlAttributes.SamlAttribute( | ||
"departments", | ||
"departments", | ||
Collections.singletonList(String.join(delimiter, returnedGroups)) | ||
) | ||
) | ||
); | ||
return parser.getAttribute(attributes); | ||
} | ||
|
||
public void testAttributeSelectionWithDelimiterAndPatternThrowsSettingsException() throws Exception { | ||
final Settings settings = Settings.builder() | ||
.put(REALM_SETTINGS_PREFIX + ".attributes.groups", "departments") | ||
.put(REALM_SETTINGS_PREFIX + ".attribute_delimiters.groups", ",") | ||
.put(REALM_SETTINGS_PREFIX + ".attribute_patterns.groups", "^(.+)@\\w+.example.com$") | ||
.build(); | ||
|
||
final RealmConfig config = buildConfig(settings); | ||
|
||
final SamlRealmSettings.AttributeSettingWithDelimiter groupSetting = new SamlRealmSettings.AttributeSettingWithDelimiter("groups"); | ||
|
||
final SettingsException settingsException = expectThrows( | ||
SettingsException.class, | ||
() -> SamlRealm.AttributeParser.forSetting(logger, groupSetting, config) | ||
); | ||
|
||
assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attribute_delimiters.groups")); | ||
assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attribute_patterns.groups")); | ||
} | ||
|
||
public void testAttributeSelectionNoGroupsConfiguredThrowsSettingsException() { | ||
String delimiter = ","; | ||
final Settings settings = Settings.builder().put(REALM_SETTINGS_PREFIX + ".attribute_delimiters.groups", delimiter).build(); | ||
final RealmConfig config = buildConfig(settings); | ||
final SamlRealmSettings.AttributeSettingWithDelimiter groupSetting = new SamlRealmSettings.AttributeSettingWithDelimiter("groups"); | ||
|
||
final SettingsException settingsException = expectThrows( | ||
SettingsException.class, | ||
() -> SamlRealm.AttributeParser.forSetting(logger, groupSetting, config) | ||
); | ||
|
||
assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attribute_delimiters.groups")); | ||
assertThat(settingsException.getMessage(), containsString(REALM_SETTINGS_PREFIX + ".attributes.groups")); | ||
} | ||
|
||
public void testAttributeSelectionWithSplitAndListThrowsSecurityException() { | ||
String delimiter = ","; | ||
|
||
final Settings settings = Settings.builder() | ||
.put(REALM_SETTINGS_PREFIX + ".attributes.groups", "departments") | ||
.put(REALM_SETTINGS_PREFIX + ".attribute_delimiters.groups", delimiter) | ||
.build(); | ||
|
||
final RealmConfig config = buildConfig(settings); | ||
|
||
final SamlRealmSettings.AttributeSettingWithDelimiter groupSetting = new SamlRealmSettings.AttributeSettingWithDelimiter("groups"); | ||
final SamlRealm.AttributeParser parser = SamlRealm.AttributeParser.forSetting(logger, groupSetting, config); | ||
|
||
final SamlAttributes attributes = new SamlAttributes( | ||
new SamlNameId(NameIDType.TRANSIENT, randomAlphaOfLength(24), null, null, null), | ||
randomAlphaOfLength(16), | ||
Collections.singletonList( | ||
new SamlAttributes.SamlAttribute( | ||
"departments", | ||
"departments", | ||
List.of("engineering", String.join(delimiter, "elasticsearch-admins", "employees")) | ||
) | ||
) | ||
); | ||
|
||
ElasticsearchSecurityException securityException = expectThrows( | ||
ElasticsearchSecurityException.class, | ||
() -> parser.getAttribute(attributes) | ||
); | ||
|
||
assertThat(securityException.getMessage(), containsString("departments")); | ||
} | ||
|
||
public void testAttributeSelectionWithRegex() { | ||
final boolean useFriendlyName = randomBoolean(); | ||
final Settings settings = Settings.builder() | ||
.put(REALM_SETTINGS_PREFIX + ".attributes.principal", useFriendlyName ? "mail" : "urn:oid:0.9.2342.19200300.100.1.3") | ||
|