Search in sources :

Example 16 with APISecurityException

use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.

the class APIKeyValidator method getKeyValidationInfo.

/**
 * Get the API key validated against the specified API
 *
 * @param context    API context
 * @param apiKey     API key to be validated
 * @param apiVersion API version number
 * @param keyManagers list of key managers to authenticate the API
 * @return An APIKeyValidationInfoDTO object
 * @throws APISecurityException If an error occurs while accessing backend services
 */
public APIKeyValidationInfoDTO getKeyValidationInfo(String context, String apiKey, String apiVersion, String authenticationScheme, String matchingResource, String httpVerb, boolean defaultVersionInvoked, List<String> keyManagers) throws APISecurityException {
    String prefixedVersion = apiVersion;
    // Check if client has invoked the default version API.
    if (defaultVersionInvoked) {
        // Prefix the version so that it looks like _default_1.0 (_default_<version>)).
        // This is so that the Key Validator knows that this request is coming through a default api version
        prefixedVersion = APIConstants.DEFAULT_VERSION_PREFIX + prefixedVersion;
    }
    String cacheKey = APIUtil.getAccessTokenCacheKey(apiKey, context, prefixedVersion, matchingResource, httpVerb, authenticationScheme);
    // If Gateway key caching is enabled.
    if (gatewayKeyCacheEnabled) {
        // Get the access token from the first level cache.
        String cachedToken = (String) getGatewayTokenCache().get(apiKey);
        // If the access token exists in the first level cache.
        if (cachedToken != null) {
            APIKeyValidationInfoDTO info = (APIKeyValidationInfoDTO) getGatewayKeyCache().get(cacheKey);
            if (info != null) {
                if (APIUtil.isAccessTokenExpired(info)) {
                    log.info("Invalid OAuth Token : Access Token " + GatewayUtils.getMaskedToken(apiKey) + " " + "expired.");
                    info.setAuthorized(false);
                    // in cache, if token is expired  remove cache entry.
                    getGatewayKeyCache().remove(cacheKey);
                    // Remove from the first level token cache as well.
                    getGatewayTokenCache().remove(apiKey);
                    // Put into invalid token cache
                    getInvalidTokenCache().put(apiKey, cachedToken);
                }
                return info;
            }
        } else {
            // Check token available in invalidToken Cache
            String revokedCachedToken = (String) getInvalidTokenCache().get(apiKey);
            if (revokedCachedToken != null) {
                // Token is revoked/invalid or expired
                APIKeyValidationInfoDTO apiKeyValidationInfoDTO = new APIKeyValidationInfoDTO();
                apiKeyValidationInfoDTO.setAuthorized(false);
                apiKeyValidationInfoDTO.setValidationStatus(APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS);
                return apiKeyValidationInfoDTO;
            }
        }
    }
    String tenantDomain = getTenantDomain();
    APIKeyValidationInfoDTO info = doGetKeyValidationInfo(context, prefixedVersion, apiKey, authenticationScheme, matchingResource, httpVerb, tenantDomain, keyManagers);
    if (info != null) {
        if (gatewayKeyCacheEnabled) {
            if (info.getValidationStatus() == APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS) {
                // if Token is not valid token (expired,invalid,revoked) put into invalid token cache
                getInvalidTokenCache().put(apiKey, tenantDomain);
            } else {
                // Add into 1st level cache and Key cache
                getGatewayTokenCache().put(apiKey, tenantDomain);
                getGatewayKeyCache().put(cacheKey, info);
            }
            // If this is NOT a super-tenant API that is being invoked
            if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                // to remove the entry when the need occurs to clear this particular cache entry.
                try {
                    startTenantFlow();
                    if (info.getValidationStatus() == APIConstants.KeyValidationStatus.API_AUTH_INVALID_CREDENTIALS) {
                        // if Token is not valid token (expired,invalid,revoked) put into invalid token cache in
                        // tenant cache
                        getInvalidTokenCache().put(apiKey, tenantDomain);
                    } else {
                        // add into to tenant token cache
                        getGatewayTokenCache().put(apiKey, tenantDomain);
                    }
                } finally {
                    endTenantFlow();
                }
            }
        }
        return info;
    } else {
        String warnMsg = "API key validation service returns null object";
        log.warn(warnMsg);
        throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, warnMsg);
    }
}
Also used : APIKeyValidationInfoDTO(org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO)

Example 17 with APISecurityException

use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.

the class APIKeyValidator method getVerbInfoDTOFromAPIData.

/**
 * @param messageContext     The message context
 * @param context     API context of API
 * @param apiVersion  Version of API
 * @param requestPath Incoming request path
 * @param httpMethod  http method of request
 * @return verbInfoDTO which contains throttling tier for given resource and verb+resource key
 */
public VerbInfoDTO getVerbInfoDTOFromAPIData(MessageContext messageContext, String context, String apiVersion, String requestPath, String httpMethod) throws APISecurityException {
    String cacheKey = context + ':' + apiVersion;
    APIInfoDTO apiInfoDTO = null;
    if (isGatewayAPIResourceValidationEnabled) {
        apiInfoDTO = (APIInfoDTO) getResourceCache().get(cacheKey);
    }
    if (apiInfoDTO == null) {
        apiInfoDTO = doGetAPIInfo(messageContext, context, apiVersion);
        if (isGatewayAPIResourceValidationEnabled) {
            getResourceCache().put(cacheKey, apiInfoDTO);
        }
    }
    // Match the case where the direct api context is matched
    if ("/".equals(requestPath)) {
        String requestCacheKey = context + '/' + apiVersion + requestPath + ':' + httpMethod;
        // Get decision from cache.
        VerbInfoDTO matchingVerb = null;
        if (isGatewayAPIResourceValidationEnabled) {
            matchingVerb = (VerbInfoDTO) getResourceCache().get(requestCacheKey);
        }
        // On a cache hit
        if (matchingVerb != null) {
            matchingVerb.setRequestKey(requestCacheKey);
            return matchingVerb;
        } else {
            if (apiInfoDTO.getResources() != null) {
                for (ResourceInfoDTO resourceInfoDTO : apiInfoDTO.getResources()) {
                    String urlPattern = resourceInfoDTO.getUrlPattern();
                    // If the request patch is '/', it can only be matched with a resource whose url-context is '/*'
                    if ("/*".equals(urlPattern)) {
                        for (VerbInfoDTO verbDTO : resourceInfoDTO.getHttpVerbs()) {
                            if (verbDTO.getHttpVerb().equals(httpMethod)) {
                                // Store verb in cache
                                if (isGatewayAPIResourceValidationEnabled) {
                                    getResourceCache().put(requestCacheKey, verbDTO);
                                }
                                verbDTO.setRequestKey(requestCacheKey);
                                return verbDTO;
                            }
                        }
                    }
                }
            }
        }
    }
    // Remove the ending '/' from request
    requestPath = RESTUtils.trimTrailingSlashes(requestPath);
    while (requestPath.length() > 1) {
        String requestCacheKey = context + '/' + apiVersion + requestPath + ':' + httpMethod;
        // Get decision from cache.
        VerbInfoDTO matchingVerb = null;
        if (isGatewayAPIResourceValidationEnabled) {
            matchingVerb = (VerbInfoDTO) getResourceCache().get(requestCacheKey);
        }
        // On a cache hit
        if (matchingVerb != null) {
            matchingVerb.setRequestKey(requestCacheKey);
            return matchingVerb;
        } else // On a cache miss
        {
            for (ResourceInfoDTO resourceInfoDTO : apiInfoDTO.getResources()) {
                String urlPattern = resourceInfoDTO.getUrlPattern();
                if (urlPattern.endsWith("/*")) {
                    // Remove the ending '/*'
                    urlPattern = urlPattern.substring(0, urlPattern.length() - 2);
                }
                // If the urlPattern ends with a '/', remove that as well.
                urlPattern = RESTUtils.trimTrailingSlashes(urlPattern);
                if (requestPath.endsWith(urlPattern)) {
                    for (VerbInfoDTO verbDTO : resourceInfoDTO.getHttpVerbs()) {
                        if (verbDTO.getHttpVerb().equals(httpMethod)) {
                            // Store verb in cache
                            if (isGatewayAPIResourceValidationEnabled) {
                                getResourceCache().put(requestCacheKey, verbDTO);
                            }
                            verbDTO.setRequestKey(requestCacheKey);
                            return verbDTO;
                        }
                    }
                }
            }
        }
        // Remove the section after the last occurrence of the '/' character
        int index = requestPath.lastIndexOf('/');
        requestPath = requestPath.substring(0, index <= 0 ? 0 : index);
    }
    // nothing found. return the highest level of security
    return null;
}
Also used : VerbInfoDTO(org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO) APIInfoDTO(org.wso2.carbon.apimgt.impl.dto.APIInfoDTO) ResourceInfoDTO(org.wso2.carbon.apimgt.impl.dto.ResourceInfoDTO)

Example 18 with APISecurityException

use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.

the class BasicAuthCredentialValidator method validateScopes.

/**
 * Validates the roles of the given user against the roles of the scopes of the API resource.
 *
 * @param username     given username
 * @param openAPI      OpenAPI of the API
 * @param synCtx       The message to be authenticated
 * @param userRoleList The list of roles of the user
 * @return true if the validation passed
 * @throws APISecurityException If an authentication failure or some other error occurs
 */
@MethodStats
public boolean validateScopes(String username, OpenAPI openAPI, MessageContext synCtx, BasicAuthValidationInfoDTO basicAuthValidationInfoDTO) throws APISecurityException {
    String[] userRoleList = basicAuthValidationInfoDTO.getUserRoleList();
    String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
    String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
    String apiElectedResource = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
    String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
    org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) synCtx).getAxis2MessageContext();
    String httpMethod = (String) axis2MessageContext.getProperty(APIConstants.DigestAuthConstants.HTTP_METHOD);
    String resourceKey = apiContext + ":" + apiVersion + ":" + apiElectedResource + ":" + httpMethod;
    Map<String, Scope> scopeMap = apiKeyValidator.retrieveScopes(tenantDomain);
    String resourceCacheKey = resourceKey + ":" + username;
    if (gatewayKeyCacheEnabled && getGatewayBasicAuthResourceCache().get(resourceCacheKey) != null && basicAuthValidationInfoDTO.isCached()) {
        return true;
    }
    if (openAPI != null) {
        // retrieve the user roles related to the scope of the API resource
        List<String> resourceScopes = OpenAPIUtils.getScopesOfResource(openAPI, synCtx);
        if (resourceScopes != null && resourceScopes.size() > 0) {
            for (String resourceScope : resourceScopes) {
                Scope scope = scopeMap.get(resourceScope);
                if (scope != null) {
                    if (scope.getRoles().isEmpty()) {
                        log.debug("Scope " + resourceScope + " didn't have roles");
                        if (gatewayKeyCacheEnabled) {
                            getGatewayBasicAuthResourceCache().put(resourceCacheKey, resourceKey);
                        }
                        return true;
                    } else {
                        // any of the role of the user
                        if (validateInternalUserRoles(scope.getRoles(), userRoleList)) {
                            if (gatewayKeyCacheEnabled) {
                                getGatewayBasicAuthResourceCache().put(resourceCacheKey, resourceKey);
                            }
                            return true;
                        }
                        // check if the roles related to the API resource contains any of the role of the user
                        for (String role : userRoleList) {
                            if (scope.getRoles().contains(role)) {
                                if (gatewayKeyCacheEnabled) {
                                    getGatewayBasicAuthResourceCache().put(resourceCacheKey, resourceKey);
                                }
                                return true;
                            }
                        }
                    }
                }
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Basic Authentication: No scopes for the API resource: ".concat(resourceKey));
            }
            return true;
        }
    } else if (APIConstants.GRAPHQL_API.equals(synCtx.getProperty(APIConstants.API_TYPE))) {
        HashMap<String, String> operationScopeMappingList = (HashMap<String, String>) synCtx.getProperty(APIConstants.SCOPE_OPERATION_MAPPING);
        String[] operationList = ((String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE)).split(",");
        for (String operation : operationList) {
            String operationScope = operationScopeMappingList.get(operation);
            if (operationScope != null) {
                if (scopeMap.containsKey(operationScope)) {
                    List<String> operationRoles = scopeMap.get(operationScope).getRoles();
                    boolean userHasOperationRole = false;
                    if (operationRoles.isEmpty()) {
                        userHasOperationRole = true;
                    } else {
                        for (String role : userRoleList) {
                            if (operationRoles.contains(role)) {
                                userHasOperationRole = true;
                                break;
                            }
                        }
                    }
                    if (!userHasOperationRole) {
                        throw new APISecurityException(APISecurityConstants.INVALID_SCOPE, "Scope validation failed");
                    }
                } else {
                    throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
                }
            }
        }
        if (gatewayKeyCacheEnabled) {
            getGatewayBasicAuthResourceCache().put(resourceCacheKey, resourceKey);
        }
        return true;
    } else {
        if (log.isDebugEnabled()) {
            log.debug("Basic Authentication: No OpenAPI found in the gateway for the API: ".concat(apiContext).concat(":").concat(apiVersion));
        }
        return true;
    }
    if (log.isDebugEnabled()) {
        log.debug("Basic Authentication: Scope validation failed for the API resource: ".concat(apiElectedResource));
    }
    throw new APISecurityException(APISecurityConstants.INVALID_SCOPE, "Scope validation failed");
}
Also used : APISecurityException(org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException) Scope(org.wso2.carbon.apimgt.keymgt.model.entity.Scope) HashMap(java.util.HashMap) List(java.util.List) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) MethodStats(org.wso2.carbon.apimgt.gateway.MethodStats)

Example 19 with APISecurityException

use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.

the class BasicAuthCredentialValidator method validate.

/**
 * Validates the given username and password against the users in the user store.
 *
 * @param username given username
 * @param password given password
 * @return true if the validation passed
 * @throws APISecurityException If an authentication failure or some other error occurs
 */
@MethodStats
public BasicAuthValidationInfoDTO validate(String username, String password) throws APISecurityException {
    boolean isAuthenticated;
    String cachedPasswordHash = null;
    String providedPasswordHash = null;
    String invalidCachedPasswordHash;
    if (gatewayKeyCacheEnabled) {
        providedPasswordHash = GatewayUtils.hashString(password.getBytes(StandardCharsets.UTF_8));
        BasicAuthValidationInfoDTO cachedValidationInfoObj = (BasicAuthValidationInfoDTO) getGatewayUsernameCache().get(username);
        if (cachedValidationInfoObj != null) {
            cachedPasswordHash = cachedValidationInfoObj.getHashedPassword();
            cachedValidationInfoObj.setCached(true);
        }
        if (cachedPasswordHash != null && cachedPasswordHash.equals(providedPasswordHash)) {
            log.debug("Basic Authentication: <Valid Username Cache> Username & password authenticated");
            return cachedValidationInfoObj;
        } else {
            BasicAuthValidationInfoDTO invalidCacheValidationInfoObj = (BasicAuthValidationInfoDTO) getInvalidUsernameCache().get(username);
            if (invalidCacheValidationInfoObj != null) {
                invalidCacheValidationInfoObj.setCached(true);
                invalidCachedPasswordHash = invalidCacheValidationInfoObj.getHashedPassword();
                if (invalidCachedPasswordHash != null && invalidCachedPasswordHash.equals(providedPasswordHash)) {
                    log.debug("Basic Authentication: <Invalid Username Cache> Username & password authentication failed");
                    invalidCacheValidationInfoObj.setAuthenticated(// If (username->password) is in the invalid cache
                    false);
                    return invalidCacheValidationInfoObj;
                }
            }
        }
    }
    BasicAuthValidationInfoDTO basicAuthValidationInfoDTO;
    try {
        org.wso2.carbon.apimgt.impl.dto.xsd.BasicAuthValidationInfoDTO generatedInfoDTO = apiKeyMgtRemoteUserStoreMgtServiceStub.getUserAuthenticationInfo(username, password);
        basicAuthValidationInfoDTO = convertToDTO(generatedInfoDTO);
        isAuthenticated = basicAuthValidationInfoDTO.isAuthenticated();
    } catch (APIKeyMgtRemoteUserStoreMgtServiceAPIManagementException | RemoteException e) {
        log.error("Basic Authentication: Error while accessing backend services to validate user authentication for user : " + username);
        throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, e.getMessage(), e);
    }
    if (gatewayKeyCacheEnabled) {
        basicAuthValidationInfoDTO.setHashedPassword(providedPasswordHash);
        if (isAuthenticated) {
            // put (username->password) into the valid cache
            getGatewayUsernameCache().put(username, basicAuthValidationInfoDTO);
        } else {
            // put (username->password) into the invalid cache
            getInvalidUsernameCache().put(username, basicAuthValidationInfoDTO);
        }
    }
    return basicAuthValidationInfoDTO;
}
Also used : APISecurityException(org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException) BasicAuthValidationInfoDTO(org.wso2.carbon.apimgt.impl.dto.BasicAuthValidationInfoDTO) RemoteException(java.rmi.RemoteException) APIKeyMgtRemoteUserStoreMgtServiceAPIManagementException(org.wso2.carbon.apimgt.keymgt.stub.usermanager.APIKeyMgtRemoteUserStoreMgtServiceAPIManagementException) MethodStats(org.wso2.carbon.apimgt.gateway.MethodStats)

Example 20 with APISecurityException

use of org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException in project carbon-apimgt by wso2.

the class JWTValidator method authenticateForGraphQLSubscription.

/**
 * Authenticate for GraphQL subscriptions API requests. This method validates the token signature, expire time and
 * subscription. The token request scopes are added to the AuthenticationContxt to validate later.
 *
 * @param signedJWTInfo SignedJWTInfo
 * @param apiContext    API context
 * @param apiVersion    API version
 * @return AuthenticationContext
 * @throws APISecurityException if an error occurs
 */
public AuthenticationContext authenticateForGraphQLSubscription(SignedJWTInfo signedJWTInfo, String apiContext, String apiVersion) throws APISecurityException {
    String tokenSignature = signedJWTInfo.getSignedJWT().getSignature().toString();
    JWTClaimsSet jwtClaimsSet = signedJWTInfo.getJwtClaimsSet();
    String jti = jwtClaimsSet.getJWTID();
    JWTValidationInfo jwtValidationInfo = validateTokenForWS(signedJWTInfo, tokenSignature, jti);
    if (jwtValidationInfo != null && jwtValidationInfo.isValid()) {
        APIKeyValidationInfoDTO apiKeyValidationInfoDTO = validateSubscriptionsForWS(jwtValidationInfo, apiContext, apiVersion);
        if (apiKeyValidationInfoDTO.isAuthorized()) {
            if (log.isDebugEnabled()) {
                log.debug("JWT authentication successful. user: " + apiKeyValidationInfoDTO.getEndUserName());
            }
            String endUserToken = generateBackendJWTForWS(jwtValidationInfo, apiKeyValidationInfoDTO, apiContext, apiVersion, tokenSignature);
            return generateAuthenticationContextForWS(jti, jwtValidationInfo, apiKeyValidationInfoDTO, endUserToken, apiVersion);
        } else {
            String message = "User is NOT authorized to access the Resource. API Subscription validation failed.";
            log.error(message);
            throw new APISecurityException(apiKeyValidationInfoDTO.getValidationStatus(), message);
        }
    } else if (!jwtValidationInfo.isValid()) {
        throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
    }
    throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, APISecurityConstants.API_AUTH_GENERAL_ERROR_MESSAGE);
}
Also used : APISecurityException(org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException) JWTClaimsSet(com.nimbusds.jwt.JWTClaimsSet) APIKeyValidationInfoDTO(org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO) JWTValidationInfo(org.wso2.carbon.apimgt.common.gateway.dto.JWTValidationInfo)

Aggregations

APISecurityException (org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException)34 Test (org.junit.Test)28 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)28 APIKeyValidationInfoDTO (org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO)28 Axis2MessageContext (org.apache.synapse.core.axis2.Axis2MessageContext)26 Cache (javax.cache.Cache)22 AuthenticationContext (org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext)16 JWTValidationInfo (org.wso2.carbon.apimgt.common.gateway.dto.JWTValidationInfo)15 APIKeyValidator (org.wso2.carbon.apimgt.gateway.handlers.security.APIKeyValidator)15 MessageContext (org.apache.synapse.MessageContext)14 APIManagerConfiguration (org.wso2.carbon.apimgt.impl.APIManagerConfiguration)14 SignedJWTInfo (org.wso2.carbon.apimgt.impl.jwt.SignedJWTInfo)12 SignedJWT (com.nimbusds.jwt.SignedJWT)11 HashMap (java.util.HashMap)11 VerbInfoDTO (org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO)11 ArrayList (java.util.ArrayList)10 APIManagementException (org.wso2.carbon.apimgt.api.APIManagementException)10 ExtendedJWTConfigurationDto (org.wso2.carbon.apimgt.impl.dto.ExtendedJWTConfigurationDto)10 JWTValidationService (org.wso2.carbon.apimgt.impl.jwt.JWTValidationService)10 TokenValidationContext (org.wso2.carbon.apimgt.keymgt.service.TokenValidationContext)10