use of org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo in project carbon-apimgt by wso2.
the class JWTValidator method validateTokenForWS.
/**
* Validates token for Websocket requests.
*
* @param signedJWTInfo SignedJWT Info
* @param tokenSignature Token Signature
* @param jti JTI
* @return JWT Validation Info
* @throws APISecurityException If an error occurs
*/
private JWTValidationInfo validateTokenForWS(SignedJWTInfo signedJWTInfo, String tokenSignature, String jti) throws APISecurityException {
JWTValidationInfo jwtValidationInfo;
String jwtHeader = signedJWTInfo.getSignedJWT().getHeader().toString();
jwtValidationInfo = getJwtValidationInfo(signedJWTInfo, jti);
if (RevokedJWTDataHolder.isJWTTokenSignatureExistsInRevokedMap(tokenSignature)) {
if (log.isDebugEnabled()) {
log.debug("Token retrieved from the revoked jwt token map. Token: " + GatewayUtils.getMaskedToken(jwtHeader));
}
log.error("Invalid JWT token. " + GatewayUtils.getMaskedToken(jwtHeader));
jwtValidationInfo.setValidationCode(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS);
jwtValidationInfo.setValid(false);
}
return jwtValidationInfo;
}
use of org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo in project carbon-apimgt by wso2.
the class JWTValidator method validateScopesForGraphQLSubscriptions.
/**
* Validate scopes for GraphQL subscription API calls using token scopes in authentication context.
*
* @param apiContext API Context
* @param apiVersion API Version
* @param matchingResource Matching resource
* @param jwtToken JWT Token
* @param authenticationContext AuthenticationContext
* @throws APISecurityException if an error occurs
*/
public void validateScopesForGraphQLSubscriptions(String apiContext, String apiVersion, String matchingResource, SignedJWTInfo jwtToken, AuthenticationContext authenticationContext) throws APISecurityException {
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
// Generate TokenValidationContext
TokenValidationContext tokenValidationContext = new TokenValidationContext();
APIKeyValidationInfoDTO apiKeyValidationInfoDTO = new APIKeyValidationInfoDTO();
Set<String> scopeSet = new HashSet<>();
scopeSet.addAll(authenticationContext.getRequestTokenScopes());
apiKeyValidationInfoDTO.setScopes(scopeSet);
tokenValidationContext.setValidationInfoDTO(apiKeyValidationInfoDTO);
tokenValidationContext.setAccessToken(jwtToken.getToken());
tokenValidationContext.setHttpVerb(GraphQLConstants.SubscriptionConstants.HTTP_METHOD_NAME);
tokenValidationContext.setMatchingResource(matchingResource);
tokenValidationContext.setContext(apiContext);
tokenValidationContext.setVersion(apiVersion);
boolean valid = this.apiKeyValidator.validateScopes(tokenValidationContext, tenantDomain);
if (valid) {
if (log.isDebugEnabled()) {
log.debug("Scope validation successful for the resource: " + matchingResource + ", user: " + authenticationContext.getUsername());
}
} else {
String message = "User is NOT authorized to access the Resource: " + matchingResource + ". Scope validation failed.";
log.debug(message);
throw new APISecurityException(APISecurityConstants.INVALID_SCOPE, message);
}
}
use of org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo in project carbon-apimgt by wso2.
the class JWTValidator method authenticate.
/**
* Authenticates the given request with a JWT token to see if an API consumer is allowed to access
* a particular API or not.
*
* @param signedJWTInfo The JWT token sent with the API request
* @param synCtx The message to be authenticated
* @return an AuthenticationContext object which contains the authentication information
* @throws APISecurityException in case of authentication failure
*/
@MethodStats
public AuthenticationContext authenticate(SignedJWTInfo signedJWTInfo, MessageContext synCtx) throws APISecurityException {
String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
org.apache.axis2.context.MessageContext axis2MsgContext = ((Axis2MessageContext) synCtx).getAxis2MessageContext();
String httpMethod = (String) axis2MsgContext.getProperty(Constants.Configuration.HTTP_METHOD);
String matchingResource = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
String jwtTokenIdentifier = getJWTTokenIdentifier(signedJWTInfo);
String jwtHeader = signedJWTInfo.getSignedJWT().getHeader().toString();
try {
X509Certificate clientCertificate = Utils.getClientCertificate(axis2MsgContext);
signedJWTInfo.setX509ClientCertificate(clientCertificate);
} catch (APIManagementException e) {
log.error("Error while obtaining client certificate. " + GatewayUtils.getMaskedToken(jwtHeader));
}
if (StringUtils.isNotEmpty(jwtTokenIdentifier)) {
if (RevokedJWTDataHolder.isJWTTokenSignatureExistsInRevokedMap(jwtTokenIdentifier)) {
if (log.isDebugEnabled()) {
log.debug("Token retrieved from the revoked jwt token map. Token: " + GatewayUtils.getMaskedToken(jwtHeader));
}
log.error("Invalid JWT token. " + GatewayUtils.getMaskedToken(jwtHeader));
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
}
}
JWTValidationInfo jwtValidationInfo = getJwtValidationInfo(signedJWTInfo, jwtTokenIdentifier);
if (jwtValidationInfo != null) {
if (jwtValidationInfo.isValid()) {
// Validate subscriptions
APIKeyValidationInfoDTO apiKeyValidationInfoDTO;
log.debug("Begin subscription validation via Key Manager: " + jwtValidationInfo.getKeyManager());
apiKeyValidationInfoDTO = validateSubscriptionUsingKeyManager(synCtx, jwtValidationInfo);
if (log.isDebugEnabled()) {
log.debug("Subscription validation via Key Manager. Status: " + apiKeyValidationInfoDTO.isAuthorized());
}
if (!apiKeyValidationInfoDTO.isAuthorized()) {
log.debug("User is NOT authorized to access the Resource. API Subscription validation failed.");
throw new APISecurityException(apiKeyValidationInfoDTO.getValidationStatus(), "User is NOT authorized to access the Resource. API Subscription validation failed.");
}
// Validate scopes
validateScopes(apiContext, apiVersion, matchingResource, httpMethod, jwtValidationInfo, signedJWTInfo);
synCtx.setProperty(APIMgtGatewayConstants.SCOPES, jwtValidationInfo.getScopes().toString());
if (apiKeyValidationInfoDTO.isAuthorized()) {
/*
* Set api.ut.apiPublisher of the subscribed api to the message context.
* This is necessary for the functionality of Publisher alerts.
* Set API_NAME of the subscribed api to the message context.
* */
synCtx.setProperty(APIMgtGatewayConstants.API_PUBLISHER, apiKeyValidationInfoDTO.getApiPublisher());
synCtx.setProperty("API_NAME", apiKeyValidationInfoDTO.getApiName());
/* GraphQL Query Analysis Information */
if (APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
synCtx.setProperty(APIConstants.MAXIMUM_QUERY_DEPTH, apiKeyValidationInfoDTO.getGraphQLMaxDepth());
synCtx.setProperty(APIConstants.MAXIMUM_QUERY_COMPLEXITY, apiKeyValidationInfoDTO.getGraphQLMaxComplexity());
}
log.debug("JWT authentication successful.");
}
log.debug("JWT authentication successful.");
String endUserToken = null;
if (jwtGenerationEnabled) {
JWTInfoDto jwtInfoDto = GatewayUtils.generateJWTInfoDto(null, jwtValidationInfo, apiKeyValidationInfoDTO, synCtx);
endUserToken = generateAndRetrieveJWTToken(jwtTokenIdentifier, jwtInfoDto);
}
return GatewayUtils.generateAuthenticationContext(jwtTokenIdentifier, jwtValidationInfo, apiKeyValidationInfoDTO, endUserToken, true);
} else {
throw new APISecurityException(jwtValidationInfo.getValidationCode(), APISecurityConstants.getAuthenticationFailureMessage(jwtValidationInfo.getValidationCode()));
}
} else {
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
}
use of org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo in project carbon-apimgt by wso2.
the class InboundWebsocketProcessorUtil method getSignedJwtInfo.
/**
* Get signed JWT info for access token
*
* @param accessToken Access token
* @return SignedJWTInfo
* @throws ParseException if an error occurs
*/
private static SignedJWTInfo getSignedJwtInfo(String accessToken) throws ParseException {
String signature = accessToken.split("\\.")[2];
SignedJWTInfo signedJWTInfo = null;
Cache gatewaySignedJWTParseCache = CacheProvider.getGatewaySignedJWTParseCache();
if (gatewaySignedJWTParseCache != null) {
Object cachedEntry = gatewaySignedJWTParseCache.get(signature);
if (cachedEntry != null) {
signedJWTInfo = (SignedJWTInfo) cachedEntry;
}
if (signedJWTInfo == null || !signedJWTInfo.getToken().equals(accessToken)) {
SignedJWT signedJWT = SignedJWT.parse(accessToken);
JWTClaimsSet jwtClaimsSet = signedJWT.getJWTClaimsSet();
signedJWTInfo = new SignedJWTInfo(accessToken, signedJWT, jwtClaimsSet);
gatewaySignedJWTParseCache.put(signature, signedJWTInfo);
}
} else {
SignedJWT signedJWT = SignedJWT.parse(accessToken);
JWTClaimsSet jwtClaimsSet = signedJWT.getJWTClaimsSet();
signedJWTInfo = new SignedJWTInfo(accessToken, signedJWT, jwtClaimsSet);
}
return signedJWTInfo;
}
use of org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo in project carbon-apimgt by wso2.
the class OAuthJwtAuthenticatorImpl method handleScopeValidation.
/**
* Handle scope validation
*
* @param accessToken JWT token
* @param signedJWTInfo : Signed token info
* @param message : cxf Message
*/
private boolean handleScopeValidation(Message message, SignedJWTInfo signedJWTInfo, String accessToken) throws APIManagementException, ParseException {
String maskedToken = message.get(RestApiConstants.MASKED_TOKEN).toString();
OAuthTokenInfo oauthTokenInfo = new OAuthTokenInfo();
oauthTokenInfo.setAccessToken(accessToken);
oauthTokenInfo.setEndUserName(signedJWTInfo.getJwtClaimsSet().getSubject());
String scopeClaim = signedJWTInfo.getJwtClaimsSet().getStringClaim(JwtTokenConstants.SCOPE);
if (scopeClaim != null) {
String orgId = RestApiUtil.resolveOrganization(message);
String[] scopes = scopeClaim.split(JwtTokenConstants.SCOPE_DELIMITER);
scopes = java.util.Arrays.stream(scopes).filter(s -> s.contains(orgId)).map(s -> s.replace(APIConstants.URN_CHOREO + orgId + ":", "")).toArray(size -> new String[size]);
oauthTokenInfo.setScopes(scopes);
if (validateScopes(message, oauthTokenInfo)) {
// Add the user scopes list extracted from token to the cxf message
message.getExchange().put(RestApiConstants.USER_REST_API_SCOPES, oauthTokenInfo.getScopes());
// If scope validation successful then set tenant name and user name to current context
String tenantDomain = MultitenantUtils.getTenantDomain(oauthTokenInfo.getEndUserName());
int tenantId;
PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
RealmService realmService = (RealmService) carbonContext.getOSGiService(RealmService.class, null);
try {
String username = oauthTokenInfo.getEndUserName();
if (MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
// when the username is an email in supertenant, it has at least 2 occurrences of '@'
long count = username.chars().filter(ch -> ch == '@').count();
// in the case of email, there will be more than one '@'
boolean isEmailUsernameEnabled = Boolean.parseBoolean(CarbonUtils.getServerConfiguration().getFirstProperty("EnableEmailUserName"));
if (isEmailUsernameEnabled || (username.endsWith(SUPER_TENANT_SUFFIX) && count <= 1)) {
username = MultitenantUtils.getTenantAwareUsername(username);
}
}
if (log.isDebugEnabled()) {
log.debug("username = " + username + "masked token " + maskedToken);
}
tenantId = realmService.getTenantManager().getTenantId(tenantDomain);
carbonContext.setTenantDomain(tenantDomain);
carbonContext.setTenantId(tenantId);
carbonContext.setUsername(username);
message.put(RestApiConstants.SUB_ORGANIZATION, orgId);
if (!tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
APIUtil.loadTenantConfigBlockingMode(tenantDomain);
}
return true;
} catch (UserStoreException e) {
log.error("Error while retrieving tenant id for tenant domain: " + tenantDomain, e);
}
log.debug("Scope validation success for the token " + maskedToken);
return true;
}
log.error("scopes validation failed for the token" + maskedToken);
return false;
}
log.error("scopes validation failed for the token" + maskedToken);
return false;
}
Aggregations