Skip to content

Commit 8999c16

Browse files
committed
Change JwtScopeService methods access to private
1 parent f40e2c3 commit 8999c16

5 files changed

Lines changed: 42 additions & 39 deletions

File tree

infobip-openapi-mcp-core/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<properties>
1414
<jakarta-servlet.version>6.1.0</jakarta-servlet.version>
1515
<swagger-parser.version>2.1.36</swagger-parser.version>
16+
<nimbus-jwt.version>10.6</nimbus-jwt.version>
1617
</properties>
1718

1819
<dependencies>

infobip-openapi-mcp-core/src/main/java/com/infobip/openapi/mcp/auth/ScopeProperties.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/**
77
* Scope discovery properties for OpenAPI MCP Server.
88
*
9-
* @param enabled Enable OAuth scope discovery. Default is false.
9+
* @param enabled Enable OAuth scope discovery. Default is true.
1010
* @param scopeExtensions Scope extensions to read scopes from. Default is an empty string.
1111
* @param mandatoryScopes Mandatory scopes that must be present. Scopes should be comma-separated.
1212
* Default is an empty string.
@@ -19,15 +19,15 @@
1919
@Validated
2020
@ConfigurationProperties(prefix = ScopeProperties.PREFIX)
2121
public record ScopeProperties(
22-
boolean enabled, String scopeExtensions, String mandatoryScopes, ScopeAlgorithm calculateMinimalScopes) {
22+
Boolean enabled, String scopeExtensions, String mandatoryScopes, ScopeAlgorithm calculateMinimalScopes) {
2323

2424
public static final String PREFIX = OAuthProperties.PREFIX + ".scope-discovery";
2525

2626
/**
2727
* Constructor with defaults for optional properties.
2828
*/
2929
public ScopeProperties {
30-
if (!enabled) {
30+
if (enabled == null) {
3131
enabled = true;
3232
}
3333

infobip-openapi-mcp-core/src/main/java/com/infobip/openapi/mcp/auth/scope/JwtScopeService.java

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import com.nimbusds.jwt.JWTClaimsSet;
44
import com.nimbusds.jwt.JWTParser;
5+
import org.jspecify.annotations.Nullable;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
59
import java.text.ParseException;
610
import java.util.Arrays;
711
import java.util.HashSet;
812
import java.util.Set;
9-
import org.slf4j.Logger;
10-
import org.slf4j.LoggerFactory;
1113

1214
/**
1315
* Service for prechecking JWT token scopes before forwarding to the authorization server.
@@ -43,24 +45,41 @@ public JwtScopeService(ScopeDiscoveryService scopeDiscoveryService) {
4345
this.scopeDiscoveryService = scopeDiscoveryService;
4446
}
4547

48+
/**
49+
* Verifies that the token from authorization header is jwt token and contains all required scopes.
50+
* Tokens must be prefixed with "Bearer". Bearer prefix is case-insensitive and leading/trailing
51+
* whitespace around the token is ignored. Uses the "scope" claim, which is expected to be a
52+
* space-separated string as per RFC 6749.
53+
*
54+
* @param authHeader The Authorization header value
55+
* @return True if all required scopes are present, false otherwise
56+
*/
57+
public boolean verifyScopes(String authHeader) {
58+
var tokenScopes = decodeAndExtractScopesFromJwtToken(authHeader);
59+
var requiredScopes = scopeDiscoveryService.getDiscoveredScopes();
60+
return tokenScopes.containsAll(requiredScopes);
61+
}
62+
4663
/**
4764
* Decodes a JWT token from the Authorization header. Tokens must be prefixed with "Bearer".
4865
* Bearer prefix is case-insensitive and leading/trailing whitespace around the token is ignored.
4966
*
5067
* @param authHeader The Authorization header value
51-
* @return The decoded JWT claims, or null if decoding fails
68+
* @return A set of scopes extracted from the token, or an empty set if decoding fails
5269
*/
53-
public JWTClaimsSet decodeJwtToken(String authHeader) {
70+
private Set<String> decodeAndExtractScopesFromJwtToken(String authHeader) {
5471
if (authHeader == null || !authHeader.regionMatches(true, 0, "Bearer ", 0, 7)) {
55-
return null;
72+
return Set.of();
5673
}
5774

5875
var token = authHeader.substring(7).trim();
5976
try {
60-
return JWTParser.parse(token).getJWTClaimsSet();
61-
} catch (Exception e) {
62-
return null;
77+
var claimsSet = JWTParser.parse(token).getJWTClaimsSet();
78+
return extractScopes(claimsSet);
79+
} catch (ParseException e) {
80+
LOGGER.debug("No 'scope' claim found in JWT token.", e);
6381
}
82+
return Set.of();
6483
}
6584

6685
/**
@@ -70,29 +89,17 @@ public JWTClaimsSet decodeJwtToken(String authHeader) {
7089
* @param claims The JWT claims
7190
* @return A set of scopes extracted from the "scope" claim
7291
*/
73-
public Set<String> extractScopes(JWTClaimsSet claims) {
74-
var scopes = new HashSet<String>();
92+
private Set<String> extractScopes(@Nullable JWTClaimsSet claims) throws ParseException {
93+
if (claims == null) {
94+
return Set.of();
95+
}
7596

76-
try {
77-
var scopeString = claims.getStringClaim("scope");
78-
if (scopeString != null && !scopeString.isBlank()) {
79-
scopes.addAll(Arrays.asList(scopeString.split(" ")));
80-
}
81-
} catch (ParseException e) {
82-
LOGGER.debug("No 'scope' claim found in JWT token.", e);
97+
var scopeString = claims.getStringClaim("scope");
98+
if (scopeString != null && !scopeString.isBlank()) {
99+
return new HashSet<>(Arrays.asList(scopeString.split(" ")));
83100
}
84101

85-
return scopes;
102+
return Set.of();
86103
}
87104

88-
/**
89-
* Verifies that the token scopes include all required scopes.
90-
*
91-
* @param tokenScopes The scopes extracted from the JWT token
92-
* @return True if all required scopes are present, false otherwise
93-
*/
94-
public boolean verifyScopes(Set<String> tokenScopes) {
95-
var requiredScopes = scopeDiscoveryService.getDiscoveredScopes();
96-
return tokenScopes.containsAll(requiredScopes);
97-
}
98105
}

infobip-openapi-mcp-core/src/main/java/com/infobip/openapi/mcp/auth/web/InitialAuthenticationFilter.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
106106

107107
if (jwtScopeService.isPresent()) {
108108
var jwtService = jwtScopeService.get();
109-
var tokenClaims = jwtService.decodeJwtToken(authHeader);
110-
if (tokenClaims != null) {
111-
var scopes = jwtService.extractScopes(tokenClaims);
112-
if (!jwtService.verifyScopes(scopes)) {
113-
writeWwwAuthenticateResponse(request, response, HttpStatus.FORBIDDEN);
114-
return;
115-
}
109+
if (!jwtService.verifyScopes(authHeader)) {
110+
writeWwwAuthenticateResponse(request, response, HttpStatus.FORBIDDEN);
111+
return;
116112
}
117113
}
118114

pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
<mockito.version>5.20.0</mockito.version>
5050
<assertj.version>3.27.6</assertj.version>
5151
<wiremock.version>3.13.1</wiremock.version>
52-
<nimbus-jwt.version>10.6</nimbus-jwt.version>
5352
</properties>
5453

5554
<dependencyManagement>

0 commit comments

Comments
 (0)