Skip to content

Commit f41aaa8

Browse files
Merge pull request #3606 from mevan-karu/api_key_impl
Move token resolving logic from the request ctx to separate method
2 parents 5b262cc + 6205760 commit f41aaa8

File tree

3 files changed

+55
-42
lines changed

3 files changed

+55
-42
lines changed

adapter/config/default_config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ var defaultConfig = &Config{
228228
DropConsoleTestHeaders: true,
229229
},
230230
APIKeyConfig: apiKeyConfig{
231-
InternalAPIKeyHeader: "Choreo-API-Key",
231+
InternalAPIKeyHeader: "choreo-api-key",
232232
OAuthAgentURL: "https://localhost:9443",
233233
},
234234
PATConfig: patConfig{

enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/ChoreoAPIKeyAuthenticator.java

+13-12
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
import org.wso2.choreo.connect.enforcer.commons.model.AuthenticationContext;
2626
import org.wso2.choreo.connect.enforcer.commons.model.RequestContext;
2727
import org.wso2.choreo.connect.enforcer.config.ConfigHolder;
28-
import org.wso2.choreo.connect.enforcer.constants.APIConstants;
2928
import org.wso2.choreo.connect.enforcer.exception.APISecurityException;
30-
import org.wso2.choreo.connect.enforcer.security.jwt.validator.JWTConstants;
3129

3230
import java.util.Base64;
3331
import java.util.Map;
@@ -65,6 +63,18 @@ public boolean canAuthenticate(RequestContext requestContext) {
6563
@Override
6664
public AuthenticationContext authenticate(RequestContext requestContext) throws APISecurityException {
6765

66+
return super.authenticate(requestContext);
67+
}
68+
69+
private String getAPIKeyFromRequest(RequestContext requestContext) {
70+
Map<String, String> headers = requestContext.getHeaders();
71+
return headers.get(ConfigHolder.getInstance().getConfig().getApiKeyConfig()
72+
.getApiKeyInternalHeader().toLowerCase());
73+
}
74+
75+
@Override
76+
protected String retrieveTokenFromRequestCtx(RequestContext requestContext) {
77+
6878
String apiKeyHeaderValue = getAPIKeyFromRequest(requestContext);
6979
// Skipping the prefix(`chk_`) and checksum.
7080
String apiKeyData = apiKeyHeaderValue.substring(4, apiKeyHeaderValue.length() - 6);
@@ -73,16 +83,7 @@ public AuthenticationContext authenticate(RequestContext requestContext) throws
7383
// Convert data into JSON.
7484
JSONObject jsonObject = (JSONObject) JSONValue.parse(decodedKeyData);
7585
// Extracting the jwt token.
76-
String jwtToken = jsonObject.getAsString(APIKeyConstants.API_KEY_JSON_KEY);
77-
// Add the JWT as the Authorization header to authenticate the request.
78-
requestContext.getHeaders().put(APIConstants.AUTHORIZATION_HEADER_DEFAULT,
79-
JWTConstants.BEARER + " " + jwtToken);
80-
return super.authenticate(requestContext);
81-
}
82-
83-
private String getAPIKeyFromRequest(RequestContext requestContext) {
84-
Map<String, String> headers = requestContext.getHeaders();
85-
return headers.get(ConfigHolder.getInstance().getConfig().getApiKeyConfig().getApiKeyInternalHeader());
86+
return jsonObject.getAsString(APIKeyConstants.API_KEY_JSON_KEY);
8687
}
8788

8889
@Override

enforcer-parent/enforcer/src/main/java/org/wso2/choreo/connect/enforcer/security/jwt/JWTAuthenticator.java

+41-29
Original file line numberDiff line numberDiff line change
@@ -171,30 +171,8 @@ public AuthenticationContext authenticate(RequestContext requestContext) throws
171171
Utils.setTag(jwtAuthenticatorInfoSpan, APIConstants.LOG_TRACE_ID,
172172
ThreadContext.get(APIConstants.LOG_TRACE_ID));
173173
}
174-
String authHeaderVal = retrieveAuthHeaderValue(requestContext);
175174

176-
if (authHeaderVal == null
177-
&& requestContext.getMatchedAPI().getApiType().equalsIgnoreCase(APIConstants.ApiType.WEB_SOCKET)) {
178-
String tokenValue = extractJWTInWSProtocolHeader(requestContext);
179-
if (StringUtils.isNotEmpty(tokenValue)) {
180-
authHeaderVal = JWTConstants.BEARER + " " + tokenValue;
181-
}
182-
}
183-
184-
if (authHeaderVal == null || !authHeaderVal.toLowerCase().contains(JWTConstants.BEARER)) {
185-
throw new APISecurityException(APIConstants.StatusCodes.UNAUTHENTICATED.getCode(),
186-
APISecurityConstants.API_AUTH_MISSING_CREDENTIALS, "Missing Credentials");
187-
}
188-
String[] splitToken = authHeaderVal.split("\\s");
189-
String token = authHeaderVal;
190-
// Extract the token when it is sent as bearer token. i.e Authorization: Bearer <token>
191-
if (splitToken.length > 1) {
192-
token = splitToken[1];
193-
}
194-
// Handle PAT logic
195-
if (isPATEnabled && token.startsWith(APIKeyConstants.PAT_PREFIX)) {
196-
token = exchangeJWTForPAT(requestContext, token);
197-
}
175+
String token = retrieveTokenFromRequestCtx(requestContext);
198176
String context = requestContext.getMatchedAPI().getBasePath();
199177
String name = requestContext.getMatchedAPI().getName();
200178
String version = requestContext.getMatchedAPI().getVersion();
@@ -266,7 +244,7 @@ public AuthenticationContext authenticate(RequestContext requestContext) throws
266244
ThreadContext.get(APIConstants.LOG_TRACE_ID));
267245
}
268246
// if the token is self contained, validation subscription from `subscribedApis` claim
269-
JSONObject api = validateSubscriptionFromClaim(name, version, claims, splitToken,
247+
JSONObject api = validateSubscriptionFromClaim(name, version, claims, token,
270248
apiKeyValidationInfoDTO, true);
271249
if (api == null) {
272250
if (log.isDebugEnabled()) {
@@ -527,6 +505,40 @@ private String retrieveAuthHeaderValue(RequestContext requestContext) {
527505
return headers.get(FilterUtils.getAuthHeaderName(requestContext));
528506
}
529507

508+
/**
509+
* Extract the JWT token from the request context.
510+
*
511+
* @param requestContext Request context
512+
* @return JWT token
513+
* @throws APISecurityException If an error occurs while extracting the JWT token
514+
*/
515+
protected String retrieveTokenFromRequestCtx(RequestContext requestContext) throws APISecurityException {
516+
517+
String authHeaderVal = retrieveAuthHeaderValue(requestContext);
518+
if (authHeaderVal == null
519+
&& requestContext.getMatchedAPI().getApiType().equalsIgnoreCase(APIConstants.ApiType.WEB_SOCKET)) {
520+
String tokenValue = extractJWTInWSProtocolHeader(requestContext);
521+
if (StringUtils.isNotEmpty(tokenValue)) {
522+
authHeaderVal = JWTConstants.BEARER + " " + tokenValue;
523+
}
524+
}
525+
if (authHeaderVal == null || !authHeaderVal.toLowerCase().contains(JWTConstants.BEARER)) {
526+
throw new APISecurityException(APIConstants.StatusCodes.UNAUTHENTICATED.getCode(),
527+
APISecurityConstants.API_AUTH_MISSING_CREDENTIALS, "Missing Credentials");
528+
}
529+
String[] splitToken = authHeaderVal.split("\\s");
530+
String token = authHeaderVal;
531+
// Extract the token when it is sent as bearer token. i.e Authorization: Bearer <token>
532+
if (splitToken.length > 1) {
533+
token = splitToken[1];
534+
}
535+
// Handle PAT logic
536+
if (isPATEnabled && token.startsWith(APIKeyConstants.PAT_PREFIX)) {
537+
token = exchangeJWTForPAT(requestContext, token);
538+
}
539+
return token;
540+
}
541+
530542
@Override
531543
public int getPriority() {
532544
return 10;
@@ -612,9 +624,9 @@ private APIKeyValidationInfoDTO validateSubscriptionUsingKeyManager(RequestConte
612624
* If the subscription information is not found, return a null object.
613625
* @throws APISecurityException if the user is not subscribed to the API
614626
*/
615-
private JSONObject validateSubscriptionFromClaim(String name, String version, JWTClaimsSet payload,
616-
String[] splitToken, APIKeyValidationInfoDTO validationInfo,
617-
boolean isOauth) throws APISecurityException {
627+
private JSONObject validateSubscriptionFromClaim(String name, String version, JWTClaimsSet payload, String token,
628+
APIKeyValidationInfoDTO validationInfo, boolean isOauth)
629+
throws APISecurityException {
618630
JSONObject api = null;
619631
try {
620632
validationInfo.setEndUserName(payload.getSubject());
@@ -678,15 +690,15 @@ private JSONObject validateSubscriptionFromClaim(String name, String version, JW
678690
}
679691
if (log.isDebugEnabled()) {
680692
log.debug("User is subscribed to the API: " + name + ", " +
681-
"version: " + version + ". Token: " + FilterUtils.getMaskedToken(splitToken[0]));
693+
"version: " + version + ". Token: " + FilterUtils.getMaskedToken(token));
682694
}
683695
break;
684696
}
685697
}
686698
if (api == null) {
687699
if (log.isDebugEnabled()) {
688700
log.debug("User is not subscribed to access the API: " + name +
689-
", version: " + version + ". Token: " + FilterUtils.getMaskedToken(splitToken[0]));
701+
", version: " + version + ". Token: " + FilterUtils.getMaskedToken(token));
690702
}
691703
log.error("User is not subscribed to access the API.");
692704
throw new APISecurityException(APIConstants.StatusCodes.UNAUTHORIZED.getCode(),

0 commit comments

Comments
 (0)