Skip to content

Commit

Permalink
Add SAML authenticator setting to allow repeat attribute names
Browse files Browse the repository at this point in the history
Signed-off-by: Craig Perkins <[email protected]>
  • Loading branch information
cwperks committed Feb 9, 2024
1 parent ca4eedf commit 778cb8c
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class AuthTokenProcessorHandler {
private String jwtRolesKey;
private String samlSubjectKey;
private String samlRolesKey;
private boolean allowRepeatAttributeName;
private String kibanaRootUrl;

private long expiryOffset = 0;
Expand All @@ -88,6 +89,7 @@ class AuthTokenProcessorHandler {

this.jwtRolesKey = jwtSettings.get("roles_key", "roles");
this.jwtSubjectKey = jwtSettings.get("subject_key", "sub");
this.allowRepeatAttributeName = settings.getAsBoolean("allow_repeat_attribute_names", false);

this.samlRolesKey = settings.get("roles_key");
this.samlSubjectKey = settings.get("subject_key");
Expand Down Expand Up @@ -151,6 +153,10 @@ private AuthTokenProcessorAction.Response handleImpl(
}
}

if (allowRepeatAttributeName) {
saml2Settings.setAllowRepeatAttributeName(allowRepeatAttributeName);
}

try {

final SamlResponse samlResponse = new SamlResponse(saml2Settings, acsEndpoint, samlResponseBase64);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ public void testMetadataBody() throws Exception {
mockSamlIdpServer.loadSigningKeys("saml/kirk-keystore.jks", "kirk");
mockSamlIdpServer.setAuthenticateUser("horst");
mockSamlIdpServer.setEndpointQueryString(null);
mockSamlIdpServer.setAuthenticateUserRoles(Arrays.asList("Admin", "Developer"));

// Note: We need to replace endpoint with mockSamlIdpServer endpoint
final String metadataBody = FileHelper.loadFile("saml/metadata.xml")
Expand Down Expand Up @@ -475,6 +476,53 @@ public void testMetadataBody() throws Exception {

SignedJWT jwt = SignedJWT.parse(authorization.replaceAll("\\s*bearer\\s*", ""));

Assert.assertEquals(List.of("Admin", "Developer"), jwt.getJWTClaimsSet().getClaim("roles"));
Assert.assertEquals("horst", jwt.getJWTClaimsSet().getClaim("sub"));
}

@Test
public void testMetadataBodyAllowRepeatAttributeNames() throws Exception {
mockSamlIdpServer.setSignResponses(true);
mockSamlIdpServer.loadSigningKeys("saml/kirk-keystore.jks", "kirk");
mockSamlIdpServer.setAuthenticateUser("horst");
mockSamlIdpServer.setEndpointQueryString(null);
mockSamlIdpServer.setAuthenticateUserRoles(Arrays.asList("Admin", "Developer"));
mockSamlIdpServer.setAllowRepeatAttributeNames(true);

// Note: We need to replace endpoint with mockSamlIdpServer endpoint
final String metadataBody = FileHelper.loadFile("saml/metadata.xml")
.replaceAll("http://localhost:33667/", mockSamlIdpServer.getMetadataUri());

Settings settings = Settings.builder()
.put(IDP_METADATA_CONTENT, metadataBody)
.put("kibana_url", "http://wherever")
.put("idp.entity_id", mockSamlIdpServer.getIdpEntityId())
.put("exchange_key", "abc")
.put("roles_key", "role")
.put("allow_repeat_attribute_names", true)
.put("path.home", ".")
.build();

HTTPSamlAuthenticator samlAuthenticator = new HTTPSamlAuthenticator(settings, null);

AuthenticateHeaders authenticateHeaders = getAutenticateHeaders(samlAuthenticator);

String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location);

RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders);
String responseJson = getResponse(samlAuthenticator, tokenRestRequest);
HashMap<String, Object> response = DefaultObjectMapper.objectMapper.readValue(
responseJson,
new TypeReference<HashMap<String, Object>>() {
}
);
String authorization = (String) response.get("authorization");

Assert.assertNotNull("Expected authorization attribute in JSON: " + responseJson, authorization);

SignedJWT jwt = SignedJWT.parse(authorization.replaceAll("\\s*bearer\\s*", ""));

Assert.assertEquals(List.of("Admin", "Developer"), jwt.getJWTClaimsSet().getClaim("roles"));
Assert.assertEquals("horst", jwt.getJWTClaimsSet().getClaim("sub"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class MockSamlIdpServer implements Closeable {
private Credential signingCredential;
private String authenticateUser;
private List<String> authenticateUserRoles;
private boolean allowRepeatAttributes = false;
private int baseId = 1;
private boolean signResponses = true;
private X509Certificate spSignatureCertificate;
Expand Down Expand Up @@ -465,17 +466,31 @@ private String createSamlAuthResponse(AuthnRequest authnRequest) {
conditions.setNotOnOrAfter(Instant.now().plus(1, ChronoUnit.MINUTES));

if (authenticateUserRoles != null) {
AttributeStatement attributeStatement = createSamlElement(AttributeStatement.class);
assertion.getAttributeStatements().add(attributeStatement);
if (!allowRepeatAttributes) {
AttributeStatement attributeStatement = createSamlElement(AttributeStatement.class);
assertion.getAttributeStatements().add(attributeStatement);

Attribute attribute = createSamlElement(Attribute.class);
attributeStatement.getAttributes().add(attribute);
Attribute attribute = createSamlElement(Attribute.class);
attributeStatement.getAttributes().add(attribute);

attribute.setName("roles");
attribute.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:basic");
attribute.setName("roles");
attribute.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:basic");

for (String role : authenticateUserRoles) {
attribute.getAttributeValues().add(createXSAny(AttributeValue.DEFAULT_ELEMENT_NAME, role));
for (String role : authenticateUserRoles) {
attribute.getAttributeValues().add(createXSAny(AttributeValue.DEFAULT_ELEMENT_NAME, role));
}
} else {
for (String role : authenticateUserRoles) {
AttributeStatement attributeStatement = createSamlElement(AttributeStatement.class);
assertion.getAttributeStatements().add(attributeStatement);

Attribute attribute = createSamlElement(Attribute.class);
attributeStatement.getAttributes().add(attribute);

attribute.setName("role");
attribute.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:basic");
attribute.getAttributeValues().add(createXSAny(AttributeValue.DEFAULT_ELEMENT_NAME, role));
}
}
}

Expand Down Expand Up @@ -1112,6 +1127,10 @@ public void setAuthenticateUserRoles(List<String> authenticateUserRoles) {
this.authenticateUserRoles = authenticateUserRoles;
}

public void setAllowRepeatAttributeNames(boolean allowRepeatAttributes) {
this.allowRepeatAttributes = allowRepeatAttributes;
}

public boolean isSignResponses() {
return signResponses;
}
Expand Down

0 comments on commit 778cb8c

Please sign in to comment.