diff --git a/pom.xml b/pom.xml index f0c12e2914..964b9266ce 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 0.10.5 1.2.3 4.5.13 - 3.4.4 + 3.4.5 2.5.0 2.5.0 3.4.5 diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index b36972a531..9613a2ade1 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -22,6 +22,7 @@ import java.util.Map.Entry; import java.util.regex.Pattern; +import com.google.common.annotations.VisibleForTesting; import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtToken; import org.apache.http.HttpHeaders; @@ -163,7 +164,8 @@ protected String getJwtTokenString(RestRequest request) { return jwtToken; } - protected String extractSubject(JwtClaims claims) { + @VisibleForTesting + public String extractSubject(JwtClaims claims) { String subject = claims.getSubject(); if (subjectKey != null) { @@ -189,7 +191,8 @@ protected String extractSubject(JwtClaims claims) { } @SuppressWarnings("unchecked") - protected String[] extractRoles(JwtClaims claims) { + @VisibleForTesting + public String[] extractRoles(JwtClaims claims) { if (rolesKey == null) { return new String[0]; } diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java index 96beff9051..5d73f24c7a 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java @@ -22,6 +22,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import com.google.common.annotations.VisibleForTesting; import net.shibboleth.utilities.java.support.xml.BasicParserPool; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.cxf.rs.security.jose.jwk.JsonWebKey; @@ -95,7 +96,8 @@ public class HTTPSamlAuthenticator implements HTTPAuthenticator, Destroyable { private Saml2SettingsProvider saml2SettingsProvider; private MetadataResolver metadataResolver; private AuthTokenProcessorHandler authTokenProcessorHandler; - private HTTPJwtAuthenticator httpJwtAuthenticator; + @VisibleForTesting + protected HTTPJwtAuthenticator httpJwtAuthenticator; private Settings jwtSettings; private static int resolverIdCounter = 0; diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index d8efce92db..0ae0e4824a 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -193,6 +193,90 @@ public void decryptAssertionsTest() throws Exception { Assert.assertEquals("horst", jwt.getClaim("sub")); } + @Test + public void unescapeSamlEntitiesTest() throws Exception { + mockSamlIdpServer.setAuthenticateUser("ABC\\User1"); + mockSamlIdpServer.setEndpointQueryString(null); + mockSamlIdpServer.setSpSignatureCertificate(spSigningCertificate); + mockSamlIdpServer.setEncryptAssertion(true); + mockSamlIdpServer.setAuthenticateUserRoles(Arrays.asList("ABC\\Admin")); + + Settings settings = Settings.builder().put(IDP_METADATA_URL, mockSamlIdpServer.getMetadataUri()) + .put("kibana_url", "http://wherever").put("idp.entity_id", mockSamlIdpServer.getIdpEntityId()) + .put("sp.signature_private_key", "-BEGIN PRIVATE KEY-\n" + + Base64.getEncoder().encodeToString(spSigningPrivateKey.getEncoded()) + "-END PRIVATE KEY-") + .put("exchange_key", "abc").put("roles_key", "roles").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); + TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); + + samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); + + String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + HashMap response = DefaultObjectMapper.objectMapper.readValue(responseJson, + new TypeReference>() { + }); + String authorization = (String) response.get("authorization"); + + Assert.assertNotNull("Expected authorization attribute in JSON: " + responseJson, authorization); + + JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(authorization.replaceAll("\\s*bearer\\s*", "")); + JwtToken jwt = jwtConsumer.getJwtToken(); + + Assert.assertEquals("ABC\\User1", jwt.getClaim("sub")); + Assert.assertEquals("ABC\\User1", samlAuthenticator.httpJwtAuthenticator.extractSubject(jwt.getClaims())); + Assert.assertEquals("[ABC\\Admin]", String.valueOf(jwt.getClaim("roles"))); + Assert.assertEquals("ABC\\Admin", samlAuthenticator.httpJwtAuthenticator.extractRoles(jwt.getClaims())[0]); + } + + @Test + public void unescapeSamlEntitiesTest2() throws Exception { + mockSamlIdpServer.setAuthenticateUser("ABC\"User1"); + mockSamlIdpServer.setEndpointQueryString(null); + mockSamlIdpServer.setSpSignatureCertificate(spSigningCertificate); + mockSamlIdpServer.setEncryptAssertion(true); + mockSamlIdpServer.setAuthenticateUserRoles(Arrays.asList("ABC\"Admin")); + + Settings settings = Settings.builder().put(IDP_METADATA_URL, mockSamlIdpServer.getMetadataUri()) + .put("kibana_url", "http://wherever").put("idp.entity_id", mockSamlIdpServer.getIdpEntityId()) + .put("sp.signature_private_key", "-BEGIN PRIVATE KEY-\n" + + Base64.getEncoder().encodeToString(spSigningPrivateKey.getEncoded()) + "-END PRIVATE KEY-") + .put("exchange_key", "abc").put("roles_key", "roles").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); + TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); + + samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); + + String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + HashMap response = DefaultObjectMapper.objectMapper.readValue(responseJson, + new TypeReference>() { + }); + String authorization = (String) response.get("authorization"); + + Assert.assertNotNull("Expected authorization attribute in JSON: " + responseJson, authorization); + + JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(authorization.replaceAll("\\s*bearer\\s*", "")); + JwtToken jwt = jwtConsumer.getJwtToken(); + + Assert.assertEquals("ABC\"User1", jwt.getClaim("sub")); + Assert.assertEquals("ABC\"User1", samlAuthenticator.httpJwtAuthenticator.extractSubject(jwt.getClaims())); + Assert.assertEquals("[ABC\"Admin]", String.valueOf(jwt.getClaim("roles"))); + Assert.assertEquals("ABC\"Admin", samlAuthenticator.httpJwtAuthenticator.extractRoles(jwt.getClaims())[0]); + } + @Test public void testMetadataBody() throws Exception { mockSamlIdpServer.setSignResponses(true);