From d643fb285fa7173357627f2756ec42fd56cb7145 Mon Sep 17 00:00:00 2001
From: Ryan Liang <109499885+RyanL1997@users.noreply.github.com>
Date: Fri, 4 Aug 2023 22:57:18 -0700
Subject: [PATCH] [Feature/Extension] Restrict OBO token's usage for certain
 endpoints (#3008)

Signed-off-by: Ryan Liang <jiallian@amazon.com>
---
 .../http/OnBehalfOfJwtAuthenticationTest.java | 84 +++++++++++--------
 .../framework/cluster/TestRestClient.java     | 20 +++++
 .../onbehalf/CreateOnBehalfOfTokenAction.java |  2 +-
 .../security/authtoken/jwt/JwtVendor.java     |  3 +
 .../security/filter/SecurityRestFilter.java   |  1 -
 .../http/OnBehalfOfAuthenticator.java         | 29 ++++++-
 .../security/ssl/util/ExceptionUtils.java     |  4 +
 .../security/authtoken/jwt/JwtVendorTest.java |  1 +
 .../http/OnBehalfOfAuthenticatorTest.java     | 44 ++++++----
 9 files changed, 134 insertions(+), 54 deletions(-)

diff --git a/src/integrationTest/java/org/opensearch/security/http/OnBehalfOfJwtAuthenticationTest.java b/src/integrationTest/java/org/opensearch/security/http/OnBehalfOfJwtAuthenticationTest.java
index 9afebe457b..4e90044ec4 100644
--- a/src/integrationTest/java/org/opensearch/security/http/OnBehalfOfJwtAuthenticationTest.java
+++ b/src/integrationTest/java/org/opensearch/security/http/OnBehalfOfJwtAuthenticationTest.java
@@ -19,6 +19,7 @@
 import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
 import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.message.BasicHeader;
+import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,8 +56,15 @@ public class OnBehalfOfJwtAuthenticationTest {
     private static final String encryptionKey = Base64.getEncoder().encodeToString("encryptionKey".getBytes(StandardCharsets.UTF_8));
     public static final String ADMIN_USER_NAME = "admin";
     public static final String DEFAULT_PASSWORD = "secret";
+    public static final String NEW_PASSWORD = "testPassword123!!";
     public static final String OBO_TOKEN_REASON = "{\"reason\":\"Test generation\"}";
     public static final String OBO_ENDPOINT_PREFIX = "_plugins/_security/api/user/onbehalfof";
+    public static final String OBO_REASON = "{\"reason\":\"Testing\", \"service\":\"self-issued\"}";
+    public static final String CURRENT_AND_NEW_PASSWORDS = "{ \"current_password\": \""
+        + DEFAULT_PASSWORD
+        + "\", \"password\": \""
+        + NEW_PASSWORD
+        + "\" }";
 
     @ClassRule
     public static final LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
@@ -76,60 +84,62 @@ public class OnBehalfOfJwtAuthenticationTest {
 
     @Test
     public void shouldAuthenticateWithOBOTokenEndPoint() {
-        Header adminOboAuthHeader;
-
-        try (TestRestClient client = cluster.getRestClient(ADMIN_USER_NAME, DEFAULT_PASSWORD)) {
-
-            client.assertCorrectCredentials(ADMIN_USER_NAME);
-
-            TestRestClient.HttpResponse response = client.postJson(OBO_ENDPOINT_PREFIX, OBO_TOKEN_REASON);
-            response.assertStatusCode(200);
-
-            Map<String, Object> oboEndPointResponse = response.getBodyAs(Map.class);
-            assertThat(oboEndPointResponse, allOf(aMapWithSize(3), hasKey("user"), hasKey("onBehalfOfToken"), hasKey("duration")));
+        String oboToken = generateOboToken(ADMIN_USER_NAME, DEFAULT_PASSWORD);
+        Header adminOboAuthHeader = new BasicHeader("Authorization", "Bearer " + oboToken);
+        authenticateWithOboToken(adminOboAuthHeader, ADMIN_USER_NAME, 200);
+    }
 
-            String encodedOboTokenStr = oboEndPointResponse.get("onBehalfOfToken").toString();
+    @Test
+    public void shouldNotAuthenticateWithATemperedOBOToken() {
+        String oboToken = generateOboToken(ADMIN_USER_NAME, DEFAULT_PASSWORD);
+        oboToken = oboToken.substring(0, oboToken.length() - 1); // tampering the token
+        Header adminOboAuthHeader = new BasicHeader("Authorization", "Bearer " + oboToken);
+        authenticateWithOboToken(adminOboAuthHeader, ADMIN_USER_NAME, 401);
+    }
 
-            adminOboAuthHeader = new BasicHeader("Authorization", "Bearer " + encodedOboTokenStr);
-        }
+    @Test
+    public void shouldNotAuthenticateForUsingOBOTokenToAccessOBOEndpoint() {
+        String oboToken = generateOboToken(ADMIN_USER_NAME, DEFAULT_PASSWORD);
+        Header adminOboAuthHeader = new BasicHeader("Authorization", "Bearer " + oboToken);
 
         try (TestRestClient client = cluster.getRestClient(adminOboAuthHeader)) {
-
-            TestRestClient.HttpResponse response = client.getAuthInfo();
-            response.assertStatusCode(200);
-
-            String username = response.getTextFromJsonBody(POINTER_USERNAME);
-            assertThat(username, equalTo(ADMIN_USER_NAME));
+            TestRestClient.HttpResponse response = client.getOBOTokenFromOboEndpoint(OBO_REASON, adminOboAuthHeader);
+            response.assertStatusCode(401);
         }
     }
 
     @Test
-    public void shouldNotAuthenticateWithATemperedOBOToken() {
-        Header adminOboAuthHeader;
+    public void shouldNotAuthenticateForUsingOBOTokenToAccessAccountEndpoint() {
+        String oboToken = generateOboToken(ADMIN_USER_NAME, DEFAULT_PASSWORD);
+        Header adminOboAuthHeader = new BasicHeader("Authorization", "Bearer " + oboToken);
 
-        try (TestRestClient client = cluster.getRestClient(ADMIN_USER_NAME, DEFAULT_PASSWORD)) {
-
-            client.assertCorrectCredentials(ADMIN_USER_NAME);
+        try (TestRestClient client = cluster.getRestClient(adminOboAuthHeader)) {
+            TestRestClient.HttpResponse response = client.changeInternalUserPassword(CURRENT_AND_NEW_PASSWORDS, adminOboAuthHeader);
+            response.assertStatusCode(401);
+        }
+    }
 
+    private String generateOboToken(String username, String password) {
+        try (TestRestClient client = cluster.getRestClient(username, password)) {
+            client.assertCorrectCredentials(username);
             TestRestClient.HttpResponse response = client.postJson(OBO_ENDPOINT_PREFIX, OBO_TOKEN_REASON);
             response.assertStatusCode(200);
-
             Map<String, Object> oboEndPointResponse = response.getBodyAs(Map.class);
             assertThat(oboEndPointResponse, allOf(aMapWithSize(3), hasKey("user"), hasKey("onBehalfOfToken"), hasKey("duration")));
-
-            String encodedOboTokenStr = oboEndPointResponse.get("onBehalfOfToken").toString();
-            StringBuilder stringBuilder = new StringBuilder(encodedOboTokenStr);
-            stringBuilder.deleteCharAt(encodedOboTokenStr.length() - 1);
-            String temperedOboTokenStr = stringBuilder.toString();
-
-            adminOboAuthHeader = new BasicHeader("Authorization", "Bearer " + temperedOboTokenStr);
+            return oboEndPointResponse.get("onBehalfOfToken").toString();
         }
+    }
 
-        try (TestRestClient client = cluster.getRestClient(adminOboAuthHeader)) {
-
+    private void authenticateWithOboToken(Header authHeader, String expectedUsername, int expectedStatusCode) {
+        try (TestRestClient client = cluster.getRestClient(authHeader)) {
             TestRestClient.HttpResponse response = client.getAuthInfo();
-            response.assertStatusCode(401);
-            response.getBody().contains("Unauthorized");
+            response.assertStatusCode(expectedStatusCode);
+            if (expectedStatusCode == 200) {
+                String username = response.getTextFromJsonBody(POINTER_USERNAME);
+                assertThat(username, equalTo(expectedUsername));
+            } else {
+                Assert.assertTrue(response.getBody().contains("Unauthorized"));
+            }
         }
     }
 }
diff --git a/src/integrationTest/java/org/opensearch/test/framework/cluster/TestRestClient.java b/src/integrationTest/java/org/opensearch/test/framework/cluster/TestRestClient.java
index f446cac933..e48acafd2f 100644
--- a/src/integrationTest/java/org/opensearch/test/framework/cluster/TestRestClient.java
+++ b/src/integrationTest/java/org/opensearch/test/framework/cluster/TestRestClient.java
@@ -135,6 +135,26 @@ public HttpResponse getAuthInfo(Header... headers) {
         return executeRequest(new HttpGet(getHttpServerUri() + "/_opendistro/_security/authinfo?pretty"), headers);
     }
 
+    public HttpResponse getOBOTokenFromOboEndpoint(String jsonData, Header... headers) {
+        try {
+            HttpPost httpPost = new HttpPost(new URIBuilder(getHttpServerUri() + "/_plugins/_security/api/user/onbehalfof?pretty").build());
+            httpPost.setEntity(toStringEntity(jsonData));
+            return executeRequest(httpPost, mergeHeaders(CONTENT_TYPE_JSON, headers));
+        } catch (URISyntaxException ex) {
+            throw new RuntimeException("Incorrect URI syntax", ex);
+        }
+    }
+
+    public HttpResponse changeInternalUserPassword(String jsonData, Header... headers) {
+        try {
+            HttpPut httpPut = new HttpPut(new URIBuilder(getHttpServerUri() + "/_plugins/_security/api/account?pretty").build());
+            httpPut.setEntity(toStringEntity(jsonData));
+            return executeRequest(httpPut, mergeHeaders(CONTENT_TYPE_JSON, headers));
+        } catch (URISyntaxException ex) {
+            throw new RuntimeException("Incorrect URI syntax", ex);
+        }
+    }
+
     public void assertCorrectCredentials(String expectedUserName) {
         HttpResponse response = getAuthInfo();
         assertThat(response, notNullValue());
diff --git a/src/main/java/org/opensearch/security/action/onbehalf/CreateOnBehalfOfTokenAction.java b/src/main/java/org/opensearch/security/action/onbehalf/CreateOnBehalfOfTokenAction.java
index be12de5bae..69c51482b2 100644
--- a/src/main/java/org/opensearch/security/action/onbehalf/CreateOnBehalfOfTokenAction.java
+++ b/src/main/java/org/opensearch/security/action/onbehalf/CreateOnBehalfOfTokenAction.java
@@ -24,7 +24,7 @@
 import org.opensearch.client.node.NodeClient;
 import org.opensearch.cluster.service.ClusterService;
 import org.opensearch.common.settings.Settings;
-import org.opensearch.common.transport.TransportAddress;
+import org.opensearch.core.common.transport.TransportAddress;
 import org.opensearch.core.xcontent.XContentBuilder;
 import org.opensearch.rest.BaseRestHandler;
 import org.opensearch.rest.BytesRestResponse;
diff --git a/src/main/java/org/opensearch/security/authtoken/jwt/JwtVendor.java b/src/main/java/org/opensearch/security/authtoken/jwt/JwtVendor.java
index 3cec339647..21d7caad57 100644
--- a/src/main/java/org/opensearch/security/authtoken/jwt/JwtVendor.java
+++ b/src/main/java/org/opensearch/security/authtoken/jwt/JwtVendor.java
@@ -105,6 +105,7 @@ public String createJwt(
         List<String> roles,
         List<String> backendRoles
     ) throws Exception {
+        String tokenIdentifier = "obo";
         long timeMillis = timeProvider.getAsLong();
         Instant now = Instant.ofEpochMilli(timeProvider.getAsLong());
 
@@ -112,6 +113,8 @@ public String createJwt(
         JwtClaims jwtClaims = new JwtClaims();
         JwtToken jwt = new JwtToken(jwtClaims);
 
+        jwtClaims.setProperty("typ", tokenIdentifier);
+
         jwtClaims.setIssuer(issuer);
 
         jwtClaims.setIssuedAt(timeMillis);
diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java
index 54d98ffe13..9b06e15c5d 100644
--- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java
+++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java
@@ -258,7 +258,6 @@ private boolean checkAndAuthenticateRequest(RestRequest request, RestChannel cha
                 );
             }
         }
-
         return false;
     }
 
diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java
index 00f69c55dc..f812cc97ee 100644
--- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java
+++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java
@@ -17,6 +17,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -28,6 +29,7 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import org.opensearch.OpenSearchException;
 import org.opensearch.OpenSearchSecurityException;
 import org.opensearch.SpecialPermission;
 import org.opensearch.common.settings.Settings;
@@ -36,16 +38,26 @@
 import org.opensearch.rest.RestRequest;
 import org.opensearch.security.auth.HTTPAuthenticator;
 import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil;
+import org.opensearch.security.ssl.util.ExceptionUtils;
 import org.opensearch.security.user.AuthCredentials;
 import org.opensearch.security.util.keyUtil;
 
+import static org.opensearch.security.OpenSearchSecurityPlugin.LEGACY_OPENDISTRO_PREFIX;
+import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX;
+
 public class OnBehalfOfAuthenticator implements HTTPAuthenticator {
 
+    private static final String REGEX_PATH_PREFIX = "/(" + LEGACY_OPENDISTRO_PREFIX + "|" + PLUGINS_PREFIX + ")/" + "(.*)";
+    private static final Pattern PATTERN_PATH_PREFIX = Pattern.compile(REGEX_PATH_PREFIX);
+    private static final String ON_BEHALF_OF_SUFFIX = "api/user/onbehalfof";
+    private static final String ACCOUNT_SUFFIX = "api/account";
+
     protected final Logger log = LogManager.getLogger(this.getClass());
 
     private static final Pattern BEARER = Pattern.compile("^\\s*Bearer\\s.*", Pattern.CASE_INSENSITIVE);
     private static final String BEARER_PREFIX = "bearer ";
-    private static final String SUBJECT_CLAIM = "sub";
+    private static final String TOKEN_TYPE_CLAIM = "typ";
+    private static final String TOKEN_TYPE = "obo";
 
     private final JwtParser jwtParser;
     private final String encryptionKey;
@@ -168,6 +180,15 @@ private AuthCredentials extractCredentials0(final RestRequest request) {
         }
 
         try {
+            Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path());
+            final String suffix = matcher.matches() ? matcher.group(2) : null;
+            if (request.method() == RestRequest.Method.POST && ON_BEHALF_OF_SUFFIX.equals(suffix)
+                || request.method() == RestRequest.Method.PUT && ACCOUNT_SUFFIX.equals(suffix)) {
+                final OpenSearchException exception = ExceptionUtils.invalidUsageOfOBOTokenException();
+                log.error(exception.toString());
+                return null;
+            }
+
             final Claims claims = jwtParser.parseClaimsJws(jwtToken).getBody();
 
             final String subject = claims.getSubject();
@@ -182,6 +203,12 @@ private AuthCredentials extractCredentials0(final RestRequest request) {
                 return null;
             }
 
+            final String tokenType = claims.get(TOKEN_TYPE_CLAIM).toString();
+            if (!tokenType.equals(TOKEN_TYPE)) {
+                log.error("This toke is not verifying as an on-behalf-of token");
+                return null;
+            }
+
             List<String> roles = extractSecurityRolesFromClaims(claims);
             String[] backendRoles = extractBackendRolesFromClaims(claims);
 
diff --git a/src/main/java/org/opensearch/security/ssl/util/ExceptionUtils.java b/src/main/java/org/opensearch/security/ssl/util/ExceptionUtils.java
index 9d6d3dade8..972f7ea035 100644
--- a/src/main/java/org/opensearch/security/ssl/util/ExceptionUtils.java
+++ b/src/main/java/org/opensearch/security/ssl/util/ExceptionUtils.java
@@ -64,6 +64,10 @@ public static OpenSearchException createBadHeaderException() {
         );
     }
 
+    public static OpenSearchException invalidUsageOfOBOTokenException() {
+        return new OpenSearchException("On-Behalf-Of Token is not allowed to be used for accessing this endopoint.");
+    }
+
     public static OpenSearchException createTransportClientNoLongerSupportedException() {
         return new OpenSearchException("Transport client authentication no longer supported.");
     }
diff --git a/src/test/java/org/opensearch/security/authtoken/jwt/JwtVendorTest.java b/src/test/java/org/opensearch/security/authtoken/jwt/JwtVendorTest.java
index a278a526b3..60ed365285 100644
--- a/src/test/java/org/opensearch/security/authtoken/jwt/JwtVendorTest.java
+++ b/src/test/java/org/opensearch/security/authtoken/jwt/JwtVendorTest.java
@@ -62,6 +62,7 @@ public void testCreateJwtWithRoles() throws Exception {
         JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer(encodedJwt);
         JwtToken jwt = jwtConsumer.getJwtToken();
 
+        Assert.assertEquals("obo", jwt.getClaim("typ"));
         Assert.assertEquals("cluster_0", jwt.getClaim("iss"));
         Assert.assertEquals("admin", jwt.getClaim("sub"));
         Assert.assertEquals("audience_0", jwt.getClaim("aud"));
diff --git a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java
index d71fe54951..e9208ccac8 100644
--- a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java
+++ b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java
@@ -16,7 +16,6 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.crypto.SecretKey;
@@ -52,7 +51,7 @@ public void testNoKey() throws Exception {
             final AuthCredentials credentials = extractCredentialsFromJwtHeader(
                 null,
                 claimsEncryptionKey,
-                Jwts.builder().setSubject("Leonard McCoy"),
+                Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy"),
                 false
             );
             Assert.fail("Expected a RuntimeException");
@@ -68,7 +67,7 @@ public void testEmptyKey() throws Exception {
             final AuthCredentials credentials = extractCredentialsFromJwtHeader(
                 null,
                 claimsEncryptionKey,
-                Jwts.builder().setSubject("Leonard McCoy"),
+                Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy"),
                 false
             );
             Assert.fail("Expected a RuntimeException");
@@ -84,7 +83,7 @@ public void testBadKey() throws Exception {
             final AuthCredentials credentials = extractCredentialsFromJwtHeader(
                 BaseEncoding.base64().encode(new byte[] { 1, 3, 3, 4, 3, 6, 7, 8, 3, 10 }),
                 claimsEncryptionKey,
-                Jwts.builder().setSubject("Leonard McCoy"),
+                Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy"),
                 false
             );
             Assert.fail("Expected a WeakKeyException");
@@ -120,6 +119,7 @@ public void testInvalid() throws Exception {
     @Test
     public void testDisabled() throws Exception {
         String jwsToken = Jwts.builder()
+            .claim("typ", "obo")
             .setSubject("Leonard McCoy")
             .setAudience("ext_0")
             .signWith(Keys.hmacShaKeyFor(Base64.getDecoder().decode(signingKeyB64Encoded)), SignatureAlgorithm.HS512)
@@ -136,6 +136,7 @@ public void testDisabled() throws Exception {
     @Test
     public void testNonSpecifyOBOSetting() throws Exception {
         String jwsToken = Jwts.builder()
+            .claim("typ", "obo")
             .setSubject("Leonard McCoy")
             .setAudience("ext_0")
             .signWith(Keys.hmacShaKeyFor(Base64.getDecoder().decode(signingKeyB64Encoded)), SignatureAlgorithm.HS512)
@@ -153,6 +154,7 @@ public void testNonSpecifyOBOSetting() throws Exception {
     public void testBearer() throws Exception {
 
         String jwsToken = Jwts.builder()
+            .claim("typ", "obo")
             .setSubject("Leonard McCoy")
             .setAudience("ext_0")
             .signWith(Keys.hmacShaKeyFor(Base64.getDecoder().decode(signingKeyB64Encoded)), SignatureAlgorithm.HS512)
@@ -168,13 +170,14 @@ public void testBearer() throws Exception {
         Assert.assertEquals("Leonard McCoy", credentials.getUsername());
         Assert.assertEquals(0, credentials.getSecurityRoles().size());
         Assert.assertEquals(0, credentials.getBackendRoles().size());
-        Assert.assertEquals(2, credentials.getAttributes().size());
+        Assert.assertEquals(3, credentials.getAttributes().size());
     }
 
     @Test
     public void testBearerWrongPosition() throws Exception {
 
         String jwsToken = Jwts.builder()
+            .claim("typ", "obo")
             .setSubject("Leonard McCoy")
             .setAudience("ext_0")
             .signWith(secretKey, SignatureAlgorithm.HS512)
@@ -192,6 +195,7 @@ public void testBearerWrongPosition() throws Exception {
     @Test
     public void testBasicAuthHeader() throws Exception {
         String jwsToken = Jwts.builder()
+            .claim("typ", "obo")
             .setSubject("Leonard McCoy")
             .setAudience("ext_0")
             .signWith(secretKey, SignatureAlgorithm.HS512)
@@ -207,11 +211,10 @@ public void testBasicAuthHeader() throws Exception {
     @Test
     public void testRoles() throws Exception {
 
-        List<String> roles = List.of("IT", "HR");
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().setSubject("Leonard McCoy").claim("dr", "role1,role2").setAudience("svc1"),
+            Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy").claim("dr", "role1,role2").setAudience("svc1"),
             true
         );
 
@@ -221,13 +224,26 @@ public void testRoles() throws Exception {
         Assert.assertEquals(0, credentials.getBackendRoles().size());
     }
 
+    @Test
+    public void testNoTokenType() throws Exception {
+
+        final AuthCredentials credentials = extractCredentialsFromJwtHeader(
+            signingKeyB64Encoded,
+            claimsEncryptionKey,
+            Jwts.builder().setSubject("Leonard McCoy").claim("dr", "role1,role2").setAudience("svc1"),
+            true
+        );
+
+        Assert.assertNull(credentials);
+    }
+
     @Test
     public void testNullClaim() throws Exception {
 
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().setSubject("Leonard McCoy").claim("dr", null).setAudience("svc1"),
+            Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy").claim("dr", null).setAudience("svc1"),
             false
         );
 
@@ -242,7 +258,7 @@ public void testNonStringClaim() throws Exception {
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().setSubject("Leonard McCoy").claim("dr", 123L).setAudience("svc1"),
+            Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy").claim("dr", 123L).setAudience("svc1"),
             true
         );
 
@@ -258,7 +274,7 @@ public void testRolesMissing() throws Exception {
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().setSubject("Leonard McCoy").setAudience("svc1"),
+            Jwts.builder().claim("typ", "obo").setSubject("Leonard McCoy").setAudience("svc1"),
             false
         );
 
@@ -274,7 +290,7 @@ public void testWrongSubjectKey() throws Exception {
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().claim("roles", "role1,role2").claim("asub", "Dr. Who").setAudience("svc1"),
+            Jwts.builder().claim("typ", "obo").claim("roles", "role1,role2").claim("asub", "Dr. Who").setAudience("svc1"),
             false
         );
 
@@ -287,7 +303,7 @@ public void testExp() throws Exception {
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().setSubject("Expired").setExpiration(new Date(100)),
+            Jwts.builder().claim("typ", "obo").setSubject("Expired").setExpiration(new Date(100)),
             false
         );
 
@@ -300,7 +316,7 @@ public void testNbf() throws Exception {
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(
             signingKeyB64Encoded,
             claimsEncryptionKey,
-            Jwts.builder().setSubject("Expired").setNotBefore(new Date(System.currentTimeMillis() + (1000 * 36000))),
+            Jwts.builder().claim("typ", "obo").setSubject("Expired").setNotBefore(new Date(System.currentTimeMillis() + (1000 * 36000))),
             false
         );
 
@@ -311,7 +327,7 @@ public void testNbf() throws Exception {
     public void testRolesArray() throws Exception {
 
         JwtBuilder builder = Jwts.builder()
-            .setPayload("{" + "\"sub\": \"Cluster_0\"," + "\"aud\": \"ext_0\"," + "\"dr\": \"a,b,3rd\"" + "}");
+            .setPayload("{" + "\"typ\": \"obo\"," + "\"sub\": \"Cluster_0\"," + "\"aud\": \"ext_0\"," + "\"dr\": \"a,b,3rd\"" + "}");
 
         final AuthCredentials credentials = extractCredentialsFromJwtHeader(signingKeyB64Encoded, claimsEncryptionKey, builder, true);