diff --git a/changelog/unreleased/SOLR-18073-jwt-bool-claims.yml b/changelog/unreleased/SOLR-18073-jwt-bool-claims.yml new file mode 100644 index 000000000000..0053d2c78de6 --- /dev/null +++ b/changelog/unreleased/SOLR-18073-jwt-bool-claims.yml @@ -0,0 +1,9 @@ +title: JWT Authentication plugin now supports matching non-string claims such as boolean +type: fixed +authors: + - name: Jan Høydahl + url: https://home.apache.org/phonebook.html?uid=janhoy + - name: Tony Panza +links: + - name: SOLR-18073 + url: https://issues.apache.org/jira/browse/SOLR-18073 diff --git a/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java b/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java index 83d0e99303b3..4c4c35eaabbd 100644 --- a/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java +++ b/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java @@ -576,13 +576,15 @@ protected JWTAuthenticationResponse authenticate(String authorizationHeader) { for (Map.Entry entry : claimsMatchCompiled.entrySet()) { String claim = entry.getKey(); if (jwtClaims.hasClaim(claim)) { - if (!entry.getValue().matcher(jwtClaims.getStringClaimValue(claim)).matches()) { + Object claimValue = jwtClaims.getClaimValue(claim); + String claimValueStr = (claimValue != null) ? String.valueOf(claimValue) : ""; + if (!entry.getValue().matcher(claimValueStr).matches()) { return new JWTAuthenticationResponse( AuthCode.CLAIM_MISMATCH, "Claim " + claim + "=" - + jwtClaims.getStringClaimValue(claim) + + claimValueStr + " does not match required regular expression " + entry.getValue().pattern()); } diff --git a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java index 0d6cc759cb2f..7b9ace8084b4 100644 --- a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java +++ b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java @@ -141,6 +141,8 @@ protected static JwtClaims generateClaims() { claims.setClaim("claim1", "foo"); // additional claims/attributes about the subject can be added claims.setClaim("claim2", "bar"); // additional claims/attributes about the subject can be added claims.setClaim("claim3", "foo"); // additional claims/attributes about the subject can be added + claims.setClaim("email_verified", true); // boolean claim as per OIDC spec + claims.setClaim("admin", false); // another boolean claim List roles = Arrays.asList("group-one", "other-group", "group-three"); claims.setStringListClaim( "roles", roles); // multi-valued claims work too and will end up as a JSON array @@ -336,6 +338,38 @@ public void claimMatch() { assertEquals(CLAIM_MISMATCH, resp.getAuthCode()); } + @Test + public void claimMatchWithBooleanClaim() { + // Test that boolean claims work correctly with claimsMatch + Map shouldMatch = new HashMap<>(); + shouldMatch.put("email_verified", "true"); + testConfig.put("claimsMatch", shouldMatch); + plugin.init(testConfig); + JWTAuthPlugin.JWTAuthenticationResponse resp = plugin.authenticate(testHeader); + assertTrue(resp.getErrorMessage(), resp.isAuthenticated()); + + // Test matching false boolean value + shouldMatch.clear(); + shouldMatch.put("admin", "false"); + plugin.init(testConfig); + resp = plugin.authenticate(testHeader); + assertTrue(resp.getErrorMessage(), resp.isAuthenticated()); + + // Test mismatch with boolean claim + shouldMatch.clear(); + shouldMatch.put("email_verified", "false"); + plugin.init(testConfig); + resp = plugin.authenticate(testHeader); + assertEquals(CLAIM_MISMATCH, resp.getAuthCode()); + + // Test regex pattern with boolean claim + shouldMatch.clear(); + shouldMatch.put("email_verified", "true|false"); + plugin.init(testConfig); + resp = plugin.authenticate(testHeader); + assertTrue(resp.getErrorMessage(), resp.isAuthenticated()); + } + @Test public void missingIssAudExp() { testConfig.put("requireIss", "false");