From eb7f8218be7ed49da4d76fbb22b7b473847c4068 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 23 Oct 2024 13:59:21 -0400 Subject: [PATCH] Generalize public key reading in the JWT authenticator (#4833) Signed-off-by: Craig Perkins --- .../opensearch/security/util/KeyUtils.java | 4 +- .../http/jwt/HTTPJwtAuthenticatorTest.java | 72 +++++++++++++------ 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/opensearch/security/util/KeyUtils.java b/src/main/java/org/opensearch/security/util/KeyUtils.java index 920cf198be..bb2abea795 100644 --- a/src/main/java/org/opensearch/security/util/KeyUtils.java +++ b/src/main/java/org/opensearch/security/util/KeyUtils.java @@ -52,8 +52,8 @@ public JwtParserBuilder run() { } else { try { PublicKey key = null; - - final String minimalKeyFormat = signingKey.replace("-----BEGIN PUBLIC KEY-----\n", "") + final String minimalKeyFormat = signingKey.replaceAll("\\r|\\n", "") + .replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .trim(); final byte[] decoded = Base64.getDecoder().decode(minimalKeyFormat); diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java index 4214e8ed06..48a14916a0 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java @@ -389,7 +389,6 @@ public void testNbf() throws Exception { @Test public void testRS256() throws Exception { - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(2048); KeyPair pair = keyGen.generateKeyPair(); @@ -397,27 +396,61 @@ public void testRS256() throws Exception { PublicKey pub = pair.getPublic(); String jwsToken = Jwts.builder().setSubject("Leonard McCoy").signWith(priv, SignatureAlgorithm.RS256).compact(); - Settings settings = Settings.builder() - .put( - "signing_key", - "-----BEGIN PUBLIC KEY-----\n" + BaseEncoding.base64().encode(pub.getEncoded()) + "-----END PUBLIC KEY-----" - ) - .build(); + String signingKey = "-----BEGIN PUBLIC KEY-----\n" + BaseEncoding.base64().encode(pub.getEncoded()) + "-----END PUBLIC KEY-----"; + AuthCredentials creds = testJwtAuthenticationWithSigningKey(signingKey, jwsToken); - HTTPJwtAuthenticator jwtAuth = new HTTPJwtAuthenticator(settings, null); - Map headers = new HashMap(); - headers.put("Authorization", "Bearer " + jwsToken); + Assert.assertNotNull(creds); + assertThat(creds.getUsername(), is("Leonard McCoy")); + assertThat(creds.getBackendRoles().size(), is(0)); + } - AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), - null - ); + private static String formatKeyWithNewlines(String keyAsString) { + StringBuilder result = new StringBuilder(); + int lineLength = 64; + int length = keyAsString.length(); + + for (int i = 0; i < length; i += lineLength) { + if (i + lineLength < length) { + result.append(keyAsString, i, i + lineLength); + } else { + result.append(keyAsString.substring(i)); + } + result.append("\n"); + } + + return result.toString().trim(); + } + + @Test + public void testRS256WithNewlines() throws Exception { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + KeyPair pair = keyGen.generateKeyPair(); + PrivateKey priv = pair.getPrivate(); + PublicKey pub = pair.getPublic(); + + String jwsToken = Jwts.builder().setSubject("Leonard McCoy").signWith(priv, SignatureAlgorithm.RS256).compact(); + + String signingKey = "-----BEGIN PUBLIC KEY-----\n" + + formatKeyWithNewlines(BaseEncoding.base64().encode(pub.getEncoded())) + + "\n-----END PUBLIC KEY-----"; + AuthCredentials creds = testJwtAuthenticationWithSigningKey(signingKey, jwsToken); Assert.assertNotNull(creds); assertThat(creds.getUsername(), is("Leonard McCoy")); assertThat(creds.getBackendRoles().size(), is(0)); } + private AuthCredentials testJwtAuthenticationWithSigningKey(String signingKey, String jwsToken) throws NoSuchAlgorithmException { + Settings settings = Settings.builder().put("signing_key", signingKey).build(); + + HTTPJwtAuthenticator jwtAuth = new HTTPJwtAuthenticator(settings, null); + Map headers = new HashMap(); + headers.put("Authorization", "Bearer " + jwsToken); + + return jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + } + @Test public void testES512() throws Exception { @@ -427,17 +460,10 @@ public void testES512() throws Exception { PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic(); - Settings settings = Settings.builder().put("signing_key", BaseEncoding.base64().encode(pub.getEncoded())).build(); + String signingKey = BaseEncoding.base64().encode(pub.getEncoded()); String jwsToken = Jwts.builder().setSubject("Leonard McCoy").signWith(priv, SignatureAlgorithm.ES512).compact(); - HTTPJwtAuthenticator jwtAuth = new HTTPJwtAuthenticator(settings, null); - Map headers = new HashMap(); - headers.put("Authorization", jwsToken); - - AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), - null - ); + AuthCredentials creds = testJwtAuthenticationWithSigningKey(signingKey, jwsToken); Assert.assertNotNull(creds); assertThat(creds.getUsername(), is("Leonard McCoy"));