Search in sources :

Example 1 with JWTTokenPayloadInfo

use of org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo in project carbon-apimgt by wso2.

the class InternalAPIKeyAuthenticatorTest method testAuthenticateWithExpiredToken.

@Test
public void testAuthenticateWithExpiredToken() throws Exception {
    PowerMockito.when(GatewayUtils.isInternalKey(Mockito.any(JWTClaimsSet.class))).thenReturn(true);
    InternalAPIKeyAuthenticator internalAPIKeyAuthenticator = new InternalAPIKeyAuthenticator(APIMgtGatewayConstants.INTERNAL_KEY);
    MessageContext messageContext = Mockito.mock(Axis2MessageContext.class);
    Mockito.when(messageContext.getProperty(RESTConstants.REST_API_CONTEXT)).thenReturn("/api1/1.0.0");
    Mockito.when(messageContext.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION)).thenReturn("1.0.0");
    API api = new API();
    PowerMockito.when(GatewayUtils.getAPI(messageContext)).thenReturn(api);
    TreeMap transportHeaders = new TreeMap();
    transportHeaders.put(APIMgtGatewayConstants.INTERNAL_KEY, internalKey);
    org.apache.axis2.context.MessageContext axis2MsgCntxt = Mockito.mock(org.apache.axis2.context.MessageContext.class);
    Mockito.when(axis2MsgCntxt.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS)).thenReturn(transportHeaders);
    Mockito.when(((Axis2MessageContext) messageContext).getAxis2MessageContext()).thenReturn(axis2MsgCntxt);
    Mockito.when(axis2MsgCntxt.getProperty(Constants.Configuration.HTTP_METHOD)).thenReturn("GET");
    Mockito.when(messageContext.getProperty(APIConstants.API_ELECTED_RESOURCE)).thenReturn("/resource");
    OpenAPI openAPI = Mockito.mock(OpenAPI.class);
    Mockito.when(messageContext.getProperty(APIMgtGatewayConstants.OPEN_API_OBJECT)).thenReturn(openAPI);
    PowerMockito.when(OpenAPIUtils.getResourceThrottlingTier(openAPI, messageContext)).thenReturn("GOLD");
    PowerMockito.when(GatewayUtils.getTenantDomain()).thenReturn("carbon.super");
    Cache internalKeyCache = Mockito.mock(Cache.class);
    PowerMockito.when(CacheProvider.getGatewayInternalKeyCache()).thenReturn(internalKeyCache);
    Mockito.when(internalKeyCache.get("28f8d7b0-9e62-4341-bf17-094453d5ffa4")).thenReturn("carbon.super");
    Cache internalKeyDataCache = Mockito.mock(Cache.class);
    PowerMockito.when(CacheProvider.getGatewayInternalKeyDataCache()).thenReturn(internalKeyDataCache);
    Cache invalidCache = Mockito.mock(Cache.class);
    PowerMockito.when(CacheProvider.getInvalidGatewayInternalKeyCache()).thenReturn(invalidCache);
    JWTTokenPayloadInfo jwtTokenPayloadInfo = new JWTTokenPayloadInfo();
    jwtTokenPayloadInfo.setPayload(signedJWT.getJWTClaimsSet());
    jwtTokenPayloadInfo.setAccessToken(internalKey);
    String cacheKey = GatewayUtils.getAccessTokenCacheKey("28f8d7b0-9e62-4341-bf17-094453d5ffa4", "/api1/1.0.0", "1.0.0", "/resource", "GET");
    JSONObject subscribedAPI = Mockito.mock(JSONObject.class);
    Mockito.when(internalKeyDataCache.get(cacheKey)).thenReturn(jwtTokenPayloadInfo);
    PowerMockito.when(GatewayUtils.isJwtTokenExpired(signedJWT.getJWTClaimsSet())).thenReturn(true);
    PowerMockito.when(GatewayUtils.validateAPISubscription("/api1/1.0.0", "1.0.0", signedJWT.getJWTClaimsSet(), internalKey.split("\\."), false)).thenReturn(subscribedAPI);
    AuthenticationContext authenticationContext = Mockito.mock(AuthenticationContext.class);
    PowerMockito.when(GatewayUtils.generateAuthenticationContext("28f8d7b0-9e62-4341-bf17-094453d5ffa4", signedJWT.getJWTClaimsSet(), subscribedAPI, api.getApiTier())).thenReturn(authenticationContext);
    PowerMockito.doNothing().when(APISecurityUtils.class, "setAuthenticationContext", messageContext, authenticationContext);
    AuthenticationResponse authenticate = internalAPIKeyAuthenticator.authenticate(messageContext);
    Assert.assertNotNull(authenticate);
    Assert.assertTrue(authenticate.isMandatoryAuthentication());
    Assert.assertFalse(authenticate.isAuthenticated());
    Assert.assertFalse(authenticate.isContinueToNextAuthenticator());
    Assert.assertEquals(authenticate.getErrorCode(), APISecurityConstants.API_AUTH_INVALID_CREDENTIALS);
    Assert.assertEquals(authenticate.getErrorMessage(), APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
}
Also used : JWTTokenPayloadInfo(org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo) AuthenticationContext(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext) TreeMap(java.util.TreeMap) AuthenticationResponse(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationResponse) JSONObject(net.minidev.json.JSONObject) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) OpenAPI(io.swagger.v3.oas.models.OpenAPI) API(org.wso2.carbon.apimgt.keymgt.model.entity.API) MessageContext(org.apache.synapse.MessageContext) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) OpenAPI(io.swagger.v3.oas.models.OpenAPI) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) Cache(javax.cache.Cache) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 2 with JWTTokenPayloadInfo

use of org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo in project carbon-apimgt by wso2.

the class ApiKeyAuthenticator method authenticate.

@Override
public AuthenticationResponse authenticate(MessageContext synCtx) {
    if (log.isDebugEnabled()) {
        log.info("ApiKey Authentication initialized");
    }
    try {
        // Extract apikey from the request while removing it from the msg context.
        String apiKey = extractApiKey(synCtx);
        JWTTokenPayloadInfo payloadInfo = null;
        if (jwtConfigurationDto == null) {
            jwtConfigurationDto = ServiceReferenceHolder.getInstance().getAPIManagerConfiguration().getJwtConfigurationDto();
        }
        if (jwtGenerationEnabled == null) {
            jwtGenerationEnabled = jwtConfigurationDto.isEnabled();
        }
        if (apiMgtGatewayJWTGenerator == null) {
            apiMgtGatewayJWTGenerator = ServiceReferenceHolder.getInstance().getApiMgtGatewayJWTGenerator().get(jwtConfigurationDto.getGatewayJWTGeneratorImpl());
        }
        String[] splitToken = apiKey.split("\\.");
        JWSHeader decodedHeader;
        JWTClaimsSet payload = null;
        SignedJWT signedJWT = null;
        String tokenIdentifier, certAlias;
        if (splitToken.length != 3) {
            log.error("Api Key does not have the format {header}.{payload}.{signature} ");
            throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
        }
        signedJWT = SignedJWT.parse(apiKey);
        payload = signedJWT.getJWTClaimsSet();
        decodedHeader = signedJWT.getHeader();
        tokenIdentifier = payload.getJWTID();
        // Check if the decoded header contains type as 'JWT'.
        if (!JOSEObjectType.JWT.equals(decodedHeader.getType())) {
            if (log.isDebugEnabled()) {
                log.debug("Invalid Api Key token type. Api Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
            }
            log.error("Invalid Api Key token type.");
            throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
        }
        if (!GatewayUtils.isAPIKey(payload)) {
            log.error("Invalid Api Key. Internal Key Sent");
            throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
        }
        if (decodedHeader.getKeyID() == null) {
            if (log.isDebugEnabled()) {
                log.debug("Invalid Api Key. Could not find alias in header. Api Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
            }
            log.error("Invalid Api Key. Could not find alias in header");
            throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
        } else {
            certAlias = decodedHeader.getKeyID();
        }
        String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
        String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
        String httpMethod = (String) ((Axis2MessageContext) synCtx).getAxis2MessageContext().getProperty(Constants.Configuration.HTTP_METHOD);
        String matchingResource = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
        OpenAPI openAPI = (OpenAPI) synCtx.getProperty(APIMgtGatewayConstants.OPEN_API_OBJECT);
        if (openAPI == null && !APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
            log.error("Swagger is missing in the gateway. " + "Therefore, Api Key authentication cannot be performed.");
            return new AuthenticationResponse(false, isMandatory, true, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF_ERROR_MESSAGE);
        }
        String resourceCacheKey = APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, matchingResource, httpMethod);
        VerbInfoDTO verbInfoDTO = new VerbInfoDTO();
        verbInfoDTO.setHttpVerb(httpMethod);
        // Not doing resource level authentication
        verbInfoDTO.setAuthType(APIConstants.AUTH_NO_AUTHENTICATION);
        verbInfoDTO.setRequestKey(resourceCacheKey);
        verbInfoDTO.setThrottling(OpenAPIUtils.getResourceThrottlingTier(openAPI, synCtx));
        List<VerbInfoDTO> verbInfoList = new ArrayList<>();
        verbInfoList.add(verbInfoDTO);
        synCtx.setProperty(APIConstants.VERB_INFO_DTO, verbInfoList);
        String cacheKey = GatewayUtils.getAccessTokenCacheKey(tokenIdentifier, apiContext, apiVersion, matchingResource, httpMethod);
        String tenantDomain = GatewayUtils.getTenantDomain();
        boolean isVerified = false;
        // Validate from cache
        if (isGatewayTokenCacheEnabled == null) {
            isGatewayTokenCacheEnabled = GatewayUtils.isGatewayTokenCacheEnabled();
        }
        if (isGatewayTokenCacheEnabled) {
            String cacheToken = (String) getGatewayApiKeyCache().get(tokenIdentifier);
            if (cacheToken != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Api Key retrieved from the Api Key cache.");
                }
                if (getGatewayApiKeyDataCache().get(cacheKey) != null) {
                    // Token is found in the key cache
                    payloadInfo = (JWTTokenPayloadInfo) getGatewayApiKeyDataCache().get(cacheKey);
                    String accessToken = payloadInfo.getAccessToken();
                    if (!accessToken.equals(apiKey)) {
                        isVerified = false;
                    } else {
                        isVerified = true;
                    }
                }
            } else if (getInvalidGatewayApiKeyCache().get(tokenIdentifier) != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Api Key retrieved from the invalid Api Key cache. Api Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
                }
                log.error("Invalid Api Key." + GatewayUtils.getMaskedToken(splitToken[0]));
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
            } else if (RevokedJWTDataHolder.isJWTTokenSignatureExistsInRevokedMap(tokenIdentifier)) {
                if (log.isDebugEnabled()) {
                    log.debug("Token retrieved from the revoked jwt token map. Token: " + GatewayUtils.getMaskedToken(splitToken[0]));
                }
                log.error("Invalid API Key. " + GatewayUtils.getMaskedToken(splitToken[0]));
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid API Key");
            }
        } else {
            if (RevokedJWTDataHolder.isJWTTokenSignatureExistsInRevokedMap(tokenIdentifier)) {
                if (log.isDebugEnabled()) {
                    log.debug("Token retrieved from the revoked jwt token map. Token: " + GatewayUtils.getMaskedToken(splitToken[0]));
                }
                log.error("Invalid JWT token. " + GatewayUtils.getMaskedToken(splitToken[0]));
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
            }
        }
        // Not found in cache or caching disabled
        if (!isVerified) {
            if (log.isDebugEnabled()) {
                log.debug("Api Key not found in the cache.");
            }
            try {
                signedJWT = (SignedJWT) JWTParser.parse(apiKey);
                payload = signedJWT.getJWTClaimsSet();
            } catch (JSONException | IllegalArgumentException | ParseException e) {
                if (log.isDebugEnabled()) {
                    log.debug("Invalid Api Key. Api Key: " + GatewayUtils.getMaskedToken(splitToken[0]), e);
                }
                log.error("Invalid JWT token. Failed to decode the Api Key body.");
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE, e);
            }
            try {
                isVerified = GatewayUtils.verifyTokenSignature(signedJWT, certAlias);
            } catch (APISecurityException e) {
                if (e.getErrorCode() == APISecurityConstants.API_AUTH_INVALID_CREDENTIALS) {
                    throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
                } else {
                    throw e;
                }
            }
            if (isGatewayTokenCacheEnabled) {
                // Add token to tenant token cache
                if (isVerified) {
                    getGatewayApiKeyCache().put(tokenIdentifier, tenantDomain);
                } else {
                    getInvalidGatewayApiKeyCache().put(tokenIdentifier, tenantDomain);
                }
                if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                    try {
                        // Start super tenant flow
                        PrivilegedCarbonContext.startTenantFlow();
                        PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, true);
                        // Add token to super tenant token cache
                        if (isVerified) {
                            getGatewayApiKeyCache().put(tokenIdentifier, tenantDomain);
                        } else {
                            getInvalidGatewayApiKeyCache().put(tokenIdentifier, tenantDomain);
                        }
                    } finally {
                        PrivilegedCarbonContext.endTenantFlow();
                    }
                }
            }
        }
        // If Api Key signature is verified
        if (isVerified) {
            if (log.isDebugEnabled()) {
                log.debug("Api Key signature is verified.");
            }
            if (isGatewayTokenCacheEnabled && payloadInfo != null) {
                // Api Key is found in the key cache
                payload = payloadInfo.getPayload();
                if (isJwtTokenExpired(payload)) {
                    getGatewayApiKeyCache().remove(tokenIdentifier);
                    getInvalidGatewayApiKeyCache().put(tokenIdentifier, tenantDomain);
                    log.error("Api Key is expired");
                    throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
                }
                validateAPIKeyRestrictions(payload, synCtx);
            } else {
                // Retrieve payload from ApiKey
                if (log.isDebugEnabled()) {
                    log.debug("ApiKey payload not found in the cache.");
                }
                if (payload == null) {
                    try {
                        signedJWT = (SignedJWT) JWTParser.parse(apiKey);
                        payload = signedJWT.getJWTClaimsSet();
                    } catch (JSONException | IllegalArgumentException | ParseException e) {
                        if (log.isDebugEnabled()) {
                            log.debug("Invalid ApiKey. ApiKey: " + GatewayUtils.getMaskedToken(splitToken[0]));
                        }
                        log.error("Invalid Api Key. Failed to decode the Api Key body.");
                        throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE, e);
                    }
                }
                if (isJwtTokenExpired(payload)) {
                    if (isGatewayTokenCacheEnabled) {
                        getGatewayApiKeyCache().remove(tokenIdentifier);
                        getInvalidGatewayApiKeyCache().put(tokenIdentifier, tenantDomain);
                    }
                    log.error("Api Key is expired");
                    throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
                }
                validateAPIKeyRestrictions(payload, synCtx);
                if (isGatewayTokenCacheEnabled) {
                    JWTTokenPayloadInfo jwtTokenPayloadInfo = new JWTTokenPayloadInfo();
                    jwtTokenPayloadInfo.setPayload(payload);
                    jwtTokenPayloadInfo.setAccessToken(apiKey);
                    getGatewayApiKeyDataCache().put(cacheKey, jwtTokenPayloadInfo);
                }
            }
            net.minidev.json.JSONObject api = GatewayUtils.validateAPISubscription(apiContext, apiVersion, payload, splitToken, false);
            if (log.isDebugEnabled()) {
                log.debug("Api Key authentication successful.");
            }
            String endUserToken = null;
            String contextHeader = null;
            if (jwtGenerationEnabled) {
                SignedJWTInfo signedJWTInfo = new SignedJWTInfo(apiKey, signedJWT, payload);
                JWTValidationInfo jwtValidationInfo = getJwtValidationInfo(signedJWTInfo);
                JWTInfoDto jwtInfoDto = GatewayUtils.generateJWTInfoDto(api, jwtValidationInfo, null, synCtx);
                endUserToken = generateAndRetrieveBackendJWTToken(tokenIdentifier, jwtInfoDto);
                contextHeader = getContextHeader();
            }
            AuthenticationContext authenticationContext;
            authenticationContext = GatewayUtils.generateAuthenticationContext(tokenIdentifier, payload, api, getApiLevelPolicy(), endUserToken, synCtx);
            APISecurityUtils.setAuthenticationContext(synCtx, authenticationContext, contextHeader);
            if (log.isDebugEnabled()) {
                log.debug("User is authorized to access the resource using Api Key.");
            }
            return new AuthenticationResponse(true, isMandatory, false, 0, null);
        }
        if (log.isDebugEnabled()) {
            log.debug("Api Key signature verification failure. Api Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
        }
        log.error("Invalid Api Key. Signature verification failed.");
        throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
    } catch (APISecurityException e) {
        return new AuthenticationResponse(false, isMandatory, true, e.getErrorCode(), e.getMessage());
    } catch (ParseException e) {
        log.error("Error while parsing API Key", e);
        return new AuthenticationResponse(false, isMandatory, true, APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
    }
}
Also used : APISecurityException(org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException) JWTTokenPayloadInfo(org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo) AuthenticationContext(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext) ArrayList(java.util.ArrayList) SignedJWT(com.nimbusds.jwt.SignedJWT) JWTValidationInfo(org.wso2.carbon.apimgt.common.gateway.dto.JWTValidationInfo) SignedJWTInfo(org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo) JWSHeader(com.nimbusds.jose.JWSHeader) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) JWTInfoDto(org.wso2.carbon.apimgt.common.gateway.dto.JWTInfoDto) JSONException(org.json.JSONException) AuthenticationResponse(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationResponse) VerbInfoDTO(org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) ParseException(java.text.ParseException) OpenAPI(io.swagger.v3.oas.models.OpenAPI)

Example 3 with JWTTokenPayloadInfo

use of org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo in project carbon-apimgt by wso2.

the class InternalAPIKeyAuthenticatorTest method testAuthenticate.

@Test
public void testAuthenticate() throws Exception {
    PowerMockito.when(GatewayUtils.isInternalKey(Mockito.any(JWTClaimsSet.class))).thenReturn(true);
    InternalAPIKeyAuthenticator internalAPIKeyAuthenticator = new InternalAPIKeyAuthenticator(APIMgtGatewayConstants.INTERNAL_KEY);
    MessageContext messageContext = Mockito.mock(Axis2MessageContext.class);
    Mockito.when(messageContext.getProperty(RESTConstants.REST_API_CONTEXT)).thenReturn("/api1/1.0.0");
    Mockito.when(messageContext.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION)).thenReturn("1.0.0");
    API api = new API();
    PowerMockito.when(GatewayUtils.getAPI(messageContext)).thenReturn(api);
    TreeMap transportHeaders = new TreeMap();
    transportHeaders.put(APIMgtGatewayConstants.INTERNAL_KEY, internalKey);
    org.apache.axis2.context.MessageContext axis2MsgCntxt = Mockito.mock(org.apache.axis2.context.MessageContext.class);
    Mockito.when(axis2MsgCntxt.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS)).thenReturn(transportHeaders);
    Mockito.when(((Axis2MessageContext) messageContext).getAxis2MessageContext()).thenReturn(axis2MsgCntxt);
    Mockito.when(axis2MsgCntxt.getProperty(Constants.Configuration.HTTP_METHOD)).thenReturn("GET");
    Mockito.when(messageContext.getProperty(APIConstants.API_ELECTED_RESOURCE)).thenReturn("/resource");
    OpenAPI openAPI = Mockito.mock(OpenAPI.class);
    Mockito.when(messageContext.getProperty(APIMgtGatewayConstants.OPEN_API_OBJECT)).thenReturn(openAPI);
    PowerMockito.when(OpenAPIUtils.getResourceThrottlingTier(openAPI, messageContext)).thenReturn("GOLD");
    PowerMockito.when(GatewayUtils.getTenantDomain()).thenReturn("carbon.super");
    Cache internalKeyCache = Mockito.mock(Cache.class);
    PowerMockito.when(CacheProvider.getGatewayInternalKeyCache()).thenReturn(internalKeyCache);
    Mockito.when(internalKeyCache.get("28f8d7b0-9e62-4341-bf17-094453d5ffa4")).thenReturn("carbon.super");
    Cache internalKeyDataCache = Mockito.mock(Cache.class);
    PowerMockito.when(CacheProvider.getGatewayInternalKeyDataCache()).thenReturn(internalKeyDataCache);
    JWTTokenPayloadInfo jwtTokenPayloadInfo = new JWTTokenPayloadInfo();
    jwtTokenPayloadInfo.setPayload(signedJWT.getJWTClaimsSet());
    jwtTokenPayloadInfo.setAccessToken(internalKey);
    String cacheKey = GatewayUtils.getAccessTokenCacheKey("28f8d7b0-9e62-4341-bf17-094453d5ffa4", "/api1/1.0.0", "1.0.0", "/resource", "GET");
    JSONObject subscribedAPI = Mockito.mock(JSONObject.class);
    Mockito.when(internalKeyDataCache.get(cacheKey)).thenReturn(jwtTokenPayloadInfo);
    PowerMockito.when(GatewayUtils.isJwtTokenExpired(signedJWT.getJWTClaimsSet())).thenReturn(false);
    PowerMockito.when(GatewayUtils.validateAPISubscription("/api1/1.0.0", "1.0.0", signedJWT.getJWTClaimsSet(), internalKey.split("\\."), false)).thenReturn(subscribedAPI);
    AuthenticationContext authenticationContext = Mockito.mock(AuthenticationContext.class);
    PowerMockito.when(GatewayUtils.generateAuthenticationContext("28f8d7b0-9e62-4341-bf17-094453d5ffa4", signedJWT.getJWTClaimsSet(), subscribedAPI, api.getApiTier())).thenReturn(authenticationContext);
    PowerMockito.doNothing().when(APISecurityUtils.class, "setAuthenticationContext", messageContext, authenticationContext);
    AuthenticationResponse authenticate = internalAPIKeyAuthenticator.authenticate(messageContext);
    Assert.assertNotNull(authenticate);
    Assert.assertTrue(authenticate.isMandatoryAuthentication());
    Assert.assertTrue(authenticate.isAuthenticated());
    Assert.assertFalse(authenticate.isContinueToNextAuthenticator());
    Assert.assertEquals(authenticate.getErrorCode(), 0);
    Assert.assertNull(authenticate.getErrorMessage());
}
Also used : JWTTokenPayloadInfo(org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo) AuthenticationContext(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext) TreeMap(java.util.TreeMap) AuthenticationResponse(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationResponse) JSONObject(net.minidev.json.JSONObject) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) OpenAPI(io.swagger.v3.oas.models.OpenAPI) API(org.wso2.carbon.apimgt.keymgt.model.entity.API) MessageContext(org.apache.synapse.MessageContext) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) OpenAPI(io.swagger.v3.oas.models.OpenAPI) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) Cache(javax.cache.Cache) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 4 with JWTTokenPayloadInfo

use of org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo in project carbon-apimgt by wso2.

the class InternalAPIKeyAuthenticator method authenticate.

@Override
public AuthenticationResponse authenticate(MessageContext synCtx) {
    API retrievedApi = GatewayUtils.getAPI(synCtx);
    if (retrievedApi != null) {
        if (log.isDebugEnabled()) {
            log.info("Internal Key Authentication initialized");
        }
        try {
            // Extract internal from the request while removing it from the msg context.
            String internalKey = extractInternalKey(synCtx);
            if (StringUtils.isEmpty(internalKey)) {
                return new AuthenticationResponse(false, false, true, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
            }
            OpenAPI openAPI = (OpenAPI) synCtx.getProperty(APIMgtGatewayConstants.OPEN_API_OBJECT);
            if (openAPI == null && !APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
                log.error("Swagger is missing in the gateway. " + "Therefore, Internal Key authentication cannot be performed.");
                return new AuthenticationResponse(false, true, false, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF, APISecurityConstants.API_AUTH_MISSING_OPEN_API_DEF_ERROR_MESSAGE);
            }
            JWTTokenPayloadInfo payloadInfo = null;
            String[] splitToken = internalKey.split("\\.");
            JWTClaimsSet payload;
            SignedJWT signedJWT;
            String tokenIdentifier;
            JWSHeader jwsHeader;
            String alias;
            if (splitToken.length != 3) {
                log.error("Internal Key does not have the format {header}.{payload}.{signature} ");
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
            }
            signedJWT = SignedJWT.parse(internalKey);
            payload = signedJWT.getJWTClaimsSet();
            tokenIdentifier = payload.getJWTID();
            jwsHeader = signedJWT.getHeader();
            if (jwsHeader != null && StringUtils.isNotEmpty(jwsHeader.getKeyID())) {
                alias = jwsHeader.getKeyID();
            } else {
                alias = APIUtil.getInternalApiKeyAlias();
            }
            // Check if the decoded header contains type as 'InternalKey'.
            if (!GatewayUtils.isInternalKey(payload)) {
                if (log.isDebugEnabled()) {
                    log.debug("Invalid Internal Key token type. Internal Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
                }
                log.error("Invalid Internal Key token type.");
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
            }
            String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
            String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
            String httpMethod = (String) ((Axis2MessageContext) synCtx).getAxis2MessageContext().getProperty(Constants.Configuration.HTTP_METHOD);
            String matchingResource = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
            String resourceCacheKey = APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, matchingResource, httpMethod);
            VerbInfoDTO verbInfoDTO = new VerbInfoDTO();
            verbInfoDTO.setHttpVerb(httpMethod);
            // Not doing resource level authentication
            verbInfoDTO.setAuthType(APIConstants.AUTH_NO_AUTHENTICATION);
            verbInfoDTO.setRequestKey(resourceCacheKey);
            verbInfoDTO.setThrottling(OpenAPIUtils.getResourceThrottlingTier(openAPI, synCtx));
            List<VerbInfoDTO> verbInfoList = new ArrayList<>();
            verbInfoList.add(verbInfoDTO);
            synCtx.setProperty(APIConstants.VERB_INFO_DTO, verbInfoList);
            String cacheKey = GatewayUtils.getAccessTokenCacheKey(tokenIdentifier, apiContext, apiVersion, matchingResource, httpMethod);
            String tenantDomain = GatewayUtils.getTenantDomain();
            boolean isVerified = false;
            String cacheToken = (String) getGatewayInternalKeyCache().get(tokenIdentifier);
            if (cacheToken != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Internal Key retrieved from the Internal Key cache.");
                }
                if (getGatewayInternalKeyDataCache().get(cacheKey) != null) {
                    // Token is found in the key cache
                    payloadInfo = (JWTTokenPayloadInfo) getGatewayInternalKeyDataCache().get(cacheKey);
                    String accessToken = payloadInfo.getAccessToken();
                    isVerified = accessToken.equals(internalKey);
                }
            } else if (getInvalidGatewayInternalKeyCache().get(tokenIdentifier) != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Internal Key retrieved from the invalid Internal Key cache. Internal Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
                }
                log.error("Invalid Internal Key." + GatewayUtils.getMaskedToken(splitToken[0]));
                throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
            }
            // Not found in cache or caching disabled
            if (!isVerified) {
                if (log.isDebugEnabled()) {
                    log.debug("Internal Key not found in the cache.");
                }
                isVerified = GatewayUtils.verifyTokenSignature(signedJWT, alias) && !GatewayUtils.isJwtTokenExpired(payload);
                // Add token to tenant token cache
                if (isVerified) {
                    getGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
                } else {
                    getInvalidGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
                }
                if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                    try {
                        // Start super tenant flow
                        PrivilegedCarbonContext.startTenantFlow();
                        PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, true);
                        // Add token to super tenant token cache
                        if (isVerified) {
                            getGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
                        }
                    } finally {
                        PrivilegedCarbonContext.endTenantFlow();
                    }
                }
            }
            // If Internal Key signature is verified
            if (isVerified) {
                if (log.isDebugEnabled()) {
                    log.debug("Internal Key signature is verified.");
                }
                if (payloadInfo != null) {
                    // Internal Key is found in the key cache
                    payload = payloadInfo.getPayload();
                    if (GatewayUtils.isJwtTokenExpired(payload)) {
                        getGatewayInternalKeyCache().remove(tokenIdentifier);
                        getInvalidGatewayInternalKeyCache().put(tokenIdentifier, tenantDomain);
                        log.error("Internal Key is expired");
                        throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
                    }
                } else {
                    // Retrieve payload from InternalKey
                    if (log.isDebugEnabled()) {
                        log.debug("InternalKey payload not found in the cache.");
                    }
                    JWTTokenPayloadInfo jwtTokenPayloadInfo = new JWTTokenPayloadInfo();
                    jwtTokenPayloadInfo.setPayload(payload);
                    jwtTokenPayloadInfo.setAccessToken(internalKey);
                    getGatewayInternalKeyDataCache().put(cacheKey, jwtTokenPayloadInfo);
                }
                JSONObject api = GatewayUtils.validateAPISubscription(apiContext, apiVersion, payload, splitToken, false);
                if (log.isDebugEnabled()) {
                    log.debug("Internal Key authentication successful.");
                }
                AuthenticationContext authenticationContext = GatewayUtils.generateAuthenticationContext(tokenIdentifier, payload, api, retrievedApi.getApiTier());
                APISecurityUtils.setAuthenticationContext(synCtx, authenticationContext);
                if (log.isDebugEnabled()) {
                    log.debug("User is authorized to access the resource using Internal Key.");
                }
                return new AuthenticationResponse(true, true, false, 0, null);
            }
            if (log.isDebugEnabled()) {
                log.debug("Internal Key signature verification failure. Internal Key: " + GatewayUtils.getMaskedToken(splitToken[0]));
            }
            log.error("Invalid Internal Key. Signature verification failed.");
            throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, APISecurityConstants.API_AUTH_INVALID_CREDENTIALS_MESSAGE);
        } catch (APISecurityException e) {
            return new AuthenticationResponse(false, true, false, e.getErrorCode(), e.getMessage());
        } catch (ParseException e) {
            log.error("Error while parsing Internal Key", e);
            return new AuthenticationResponse(false, true, false, APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
        }
    }
    return new AuthenticationResponse(false, true, false, APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
Also used : APISecurityException(org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException) JWTTokenPayloadInfo(org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo) AuthenticationContext(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext) ArrayList(java.util.ArrayList) SignedJWT(com.nimbusds.jwt.SignedJWT) AuthenticationResponse(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationResponse) JSONObject(net.minidev.json.JSONObject) VerbInfoDTO(org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) OpenAPI(io.swagger.v3.oas.models.OpenAPI) API(org.wso2.carbon.apimgt.keymgt.model.entity.API) ParseException(java.text.ParseException) OpenAPI(io.swagger.v3.oas.models.OpenAPI) JWSHeader(com.nimbusds.jose.JWSHeader) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext)

Aggregations

JWTClaimsSet (com.nimbusds.jwt.JWTClaimsSet)4 OpenAPI (io.swagger.v3.oas.models.OpenAPI)4 Axis2MessageContext (org.apache.synapse.core.axis2.Axis2MessageContext)4 JWTTokenPayloadInfo (org.wso2.carbon.apimgt.gateway.dto.JWTTokenPayloadInfo)4 AuthenticationContext (org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext)4 AuthenticationResponse (org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationResponse)4 JSONObject (net.minidev.json.JSONObject)3 API (org.wso2.carbon.apimgt.keymgt.model.entity.API)3 JWSHeader (com.nimbusds.jose.JWSHeader)2 SignedJWT (com.nimbusds.jwt.SignedJWT)2 ParseException (java.text.ParseException)2 ArrayList (java.util.ArrayList)2 TreeMap (java.util.TreeMap)2 Cache (javax.cache.Cache)2 MessageContext (org.apache.synapse.MessageContext)2 Test (org.junit.Test)2 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)2 APISecurityException (org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException)2 VerbInfoDTO (org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO)2 JSONException (org.json.JSONException)1