Search in sources :

Example 6 with ServiceMethodInfo

use of org.wso2.msf4j.ServiceMethodInfo in project carbon-apimgt by wso2.

the class RESTAPISecurityInterceptor method preCall.

/**
 * preCall is run before a handler method call is made. If any of the preCalls throw exception or return false then
 * no other subsequent preCalls will be called and the request processing will be terminated,
 * also no postCall interceptors will be called.
 *
 * @param request           HttpRequest being processed.
 * @param response          HttpResponder to send response.
 * @param serviceMethodInfo Info on handler method that will be called.
 * @return true if the request processing can continue, otherwise the hook should send response and return false to
 * stop further processing.
 * @throws APIMgtSecurityException if error occurs while executing the preCall
 */
@Override
public boolean preCall(Request request, Response response, ServiceMethodInfo serviceMethodInfo) throws APIMgtSecurityException {
    ErrorHandler errorHandler = null;
    boolean isAuthenticated = false;
    // CORS for Environments - Add allowed Origin when User-Agent sent 'Origin' header.
    String origin = request.getHeader(RestApiConstants.ORIGIN_HEADER);
    String allowedOrigin = EnvironmentUtils.getAllowedOrigin(origin);
    if (allowedOrigin != null) {
        response.setHeader(RestApiConstants.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, allowedOrigin).setHeader(RestApiConstants.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
    }
    // CORS for Environments - Add allowed Methods and Headers when 'OPTIONS' method is called.
    if (request.getHttpMethod().equalsIgnoreCase(APIConstants.HTTP_OPTIONS)) {
        try {
            String definedHttpMethods = RestApiUtil.getDefinedMethodHeadersInSwaggerContent(request, serviceMethodInfo);
            if (definedHttpMethods != null) {
                response.setHeader(RestApiConstants.ACCESS_CONTROL_ALLOW_METHODS_HEADER, definedHttpMethods).setHeader(RestApiConstants.ACCESS_CONTROL_ALLOW_HEADERS_HEADER, RestApiConstants.ACCESS_CONTROL_ALLOW_HEADERS_LIST).setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).send();
                return false;
            }
        } catch (APIManagementException e) {
            String msg = "Couldn't find declared HTTP methods in swagger.yaml";
            ErrorDTO errorDTO = RestApiUtil.getErrorDTO(e.getErrorHandler());
            log.error(msg, e);
            response.setStatus(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).setEntity(errorDTO).send();
            return false;
        }
    }
    /* TODO: Following string contains check is done to avoid checking security headers in non API requests.
         * Consider this as a temporary fix until MSF4J support context based interceptor registration */
    String requestURI = request.getUri().toLowerCase(Locale.ENGLISH);
    if (!requestURI.contains("/api/am/")) {
        return true;
    }
    if (requestURI.contains("/login/token")) {
        return true;
    }
    String yamlContent = null;
    String protocol = (String) request.getProperty(PROTOCOL);
    Swagger swagger = null;
    if (requestURI.contains("/api/am/publisher")) {
        if (requestURI.contains("swagger.yaml")) {
            try {
                yamlContent = RestApiUtil.getPublisherRestAPIResource();
                response.setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).setEntity(yamlContent).setMediaType("text/x-yaml").send();
            } catch (APIManagementException e) {
                String msg = "Couldn't find swagger.yaml for publisher";
                ErrorDTO errorDTO = RestApiUtil.getErrorDTO(e.getErrorHandler());
                log.error(msg, e);
                response.setStatus(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).setEntity(errorDTO).send();
            }
            return false;
        }
    } else if (requestURI.contains("/api/am/store")) {
        if (requestURI.contains("swagger.json")) {
            try {
                yamlContent = RestApiUtil.getStoreRestAPIResource();
                swagger = new SwaggerParser().parse(yamlContent);
                swagger.setBasePath(RestApiUtil.getContext(RestApiConstants.APPType.STORE));
                swagger.setHost(RestApiUtil.getHost(protocol.toLowerCase(Locale.ENGLISH)));
                response.setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).setEntity(Json.pretty(swagger)).setMediaType(MediaType.APPLICATION_JSON).send();
            } catch (APIManagementException e) {
                String msg = "Couldn't find swagger.json for store";
                ErrorDTO errorDTO = RestApiUtil.getErrorDTO(e.getErrorHandler());
                log.error(msg, e);
                response.setStatus(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).setEntity(errorDTO).send();
            }
            return false;
        } else if (requestURI.contains("swagger.yaml")) {
            try {
                yamlContent = RestApiUtil.getStoreRestAPIResource();
                response.setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).setEntity(yamlContent).setMediaType("text/x-yaml").send();
            } catch (APIManagementException e) {
                String msg = "Couldn't find swagger.yaml for store";
                ErrorDTO errorDTO = RestApiUtil.getErrorDTO(e.getErrorHandler());
                log.error(msg, e);
                response.setStatus(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).setEntity(errorDTO).send();
            }
            return false;
        }
    } else if (requestURI.contains("/api/am/analytics")) {
        if (requestURI.contains("swagger.json")) {
            try {
                yamlContent = RestApiUtil.getAnalyticsRestAPIResource();
                swagger = new SwaggerParser().parse(yamlContent);
                swagger.setBasePath(RestApiUtil.getContext(RestApiConstants.APPType.ANALYTICS));
                swagger.setHost(RestApiUtil.getHost(protocol.toLowerCase(Locale.ENGLISH)));
            } catch (APIManagementException e) {
                log.error("Couldn't find swagger.json for analytics", e);
            }
            response.setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).setEntity(Json.pretty(swagger)).setMediaType(MediaType.APPLICATION_JSON).send();
            return false;
        }
    } else if (requestURI.contains("/editor") || requestURI.contains("keyserver") || requestURI.contains("core") || requestURI.contains("/api/am/config")) {
        return true;
    } else if (requestURI.contains("/api/am/admin")) {
        if (requestURI.contains("swagger.json")) {
            try {
                yamlContent = RestApiUtil.getAdminRestAPIResource();
                swagger = new SwaggerParser().parse(yamlContent);
                swagger.setBasePath(RestApiUtil.getContext(RestApiConstants.APPType.ADMIN));
                swagger.setHost(RestApiUtil.getHost(protocol.toLowerCase(Locale.ENGLISH)));
                response.setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).setEntity(Json.pretty(swagger)).setMediaType(MediaType.APPLICATION_JSON).send();
            } catch (APIManagementException e) {
                String msg = "Couldn't find swagger.yaml for admin";
                ErrorDTO errorDTO = RestApiUtil.getErrorDTO(e.getErrorHandler());
                log.error(msg, e);
                response.setStatus(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).setEntity(errorDTO).send();
            }
            return false;
        } else if (requestURI.contains("swagger.yaml")) {
            try {
                yamlContent = RestApiUtil.getAdminRestAPIResource();
                response.setStatus(javax.ws.rs.core.Response.Status.OK.getStatusCode()).setEntity(yamlContent).setMediaType("text/x-yaml").send();
            } catch (APIManagementException e) {
                String msg = "Couldn't find swagger.yaml for admin";
                ErrorDTO errorDTO = RestApiUtil.getErrorDTO(e.getErrorHandler());
                log.error(msg, e);
                response.setStatus(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).setEntity(errorDTO).send();
            }
            return false;
        }
    }
    try {
        if (authenticatorImplClass == null) {
            Class<?> implClass = null;
            try {
                implClass = Class.forName(authenticatorName);
            } catch (ClassNotFoundException e) {
                throw new APIMgtSecurityException("Error while loading class " + authenticatorName, e);
            }
            authenticatorImplClass = (RESTAPIAuthenticator) implClass.newInstance();
        }
        isAuthenticated = authenticatorImplClass.authenticate(request, response, serviceMethodInfo);
    } catch (APIMgtSecurityException e) {
        errorHandler = e.getErrorHandler();
        log.error(e.getMessage() + " Requested Path: " + request.getUri());
    } catch (InstantiationException e) {
        log.error(e.getMessage() + " Error while instantiating authenticator: " + authenticatorName);
        isAuthenticated = false;
        errorHandler = ExceptionCodes.AUTH_GENERAL_ERROR;
    } catch (IllegalAccessException e) {
        log.error(e.getMessage() + " Error while accessing resource : " + authenticatorName);
        isAuthenticated = false;
        errorHandler = ExceptionCodes.AUTH_GENERAL_ERROR;
    }
    if (!isAuthenticated) {
        handleSecurityError(errorHandler, response);
    }
    return isAuthenticated;
}
Also used : SwaggerParser(io.swagger.parser.SwaggerParser) ErrorHandler(org.wso2.carbon.apimgt.core.exception.ErrorHandler) APIManagementException(org.wso2.carbon.apimgt.core.exception.APIManagementException) APIMgtSecurityException(org.wso2.carbon.apimgt.rest.api.common.exception.APIMgtSecurityException) ErrorDTO(org.wso2.carbon.apimgt.rest.api.common.dto.ErrorDTO) Swagger(io.swagger.models.Swagger)

Example 7 with ServiceMethodInfo

use of org.wso2.msf4j.ServiceMethodInfo in project carbon-apimgt by wso2.

the class RestApiUtil method getDefinedMethodHeadersInSwaggerContent.

/**
 * Get defined HTTP methods in the swagger definition as a comma separated string
 *
 * @param request           Request
 * @param serviceMethodInfo Method information for the request
 * @return Http Methods as a comma separated string
 * @throws APIManagementException if failed to get defined http methods
 */
public static String getDefinedMethodHeadersInSwaggerContent(Request request, ServiceMethodInfo serviceMethodInfo) throws APIManagementException {
    String requestURI = request.getUri().toLowerCase(Locale.ENGLISH);
    Swagger swagger = null;
    Method resourceMethod;
    if (requestURI.contains("/api/am/publisher")) {
        swagger = swaggerRestAPIDefinitions.get(RestApiConstants.APPType.PUBLISHER);
    } else if (requestURI.contains("/api/am/store")) {
        swagger = swaggerRestAPIDefinitions.get(RestApiConstants.APPType.STORE);
    } else if (requestURI.contains("/api/am/analytics")) {
        swagger = swaggerRestAPIDefinitions.get(RestApiConstants.APPType.ANALYTICS);
    } else if (requestURI.contains("/api/am/admin")) {
        swagger = swaggerRestAPIDefinitions.get(RestApiConstants.APPType.ADMIN);
    } else {
        return null;
    }
    if (swagger == null) {
        throw new APIManagementException("Error while parsing the swagger definition", ExceptionCodes.SWAGGER_URL_MALFORMED);
    }
    resourceMethod = serviceMethodInfo.getMethod();
    if (resourceMethod == null) {
        throw new APIManagementException("Could not read required properties from HTTP Request.", ExceptionCodes.SWAGGER_URL_MALFORMED);
    }
    String apiPath = resourceMethod.getDeclaringClass().getAnnotation(javax.ws.rs.ApplicationPath.class).value();
    javax.ws.rs.Path apiPathAnnotation = resourceMethod.getAnnotation(javax.ws.rs.Path.class);
    if (apiPathAnnotation != null) {
        apiPath += apiPathAnnotation.value();
    }
    Path swaggerAPIPath = swagger.getPath(apiPath);
    if (swaggerAPIPath == null) {
        throw new APIManagementException("Could not read API path from the swagger definition", ExceptionCodes.SWAGGER_URL_MALFORMED);
    }
    return swaggerAPIPath.getOperationMap().keySet().stream().map(Enum::toString).collect(Collectors.joining(", "));
}
Also used : Path(io.swagger.models.Path) Collectors(java.util.stream.Collectors) APIManagementException(org.wso2.carbon.apimgt.core.exception.APIManagementException) Swagger(io.swagger.models.Swagger) Method(java.lang.reflect.Method)

Example 8 with ServiceMethodInfo

use of org.wso2.msf4j.ServiceMethodInfo in project carbon-apimgt by wso2.

the class OAuth2Authenticator method authenticate.

/*
    * This method performs authentication and authorization
    * @param Request
    * @param Response
    * @param ServiceMethodInfo
    * throws Exception
    * */
@Override
public boolean authenticate(Request request, Response responder, ServiceMethodInfo serviceMethodInfo) throws APIMgtSecurityException {
    ErrorHandler errorHandler = null;
    boolean isTokenValid = false;
    HttpHeaders headers = request.getHeaders();
    boolean isCookieHeaderPresent = false;
    boolean isAuthorizationHeaderPresent = false;
    if (request.getHeader(RestApiConstants.COOKIE_HEADER) != null) {
        isCookieHeaderPresent = true;
    }
    if (request.getHeader(RestApiConstants.AUTHORIZATION_HTTP_HEADER) != null) {
        isAuthorizationHeaderPresent = true;
    }
    if (headers != null && isCookieHeaderPresent && isCookieExists(request, APIConstants.AccessTokenConstants.AM_TOKEN_MSF4J)) {
        String accessToken = null;
        String cookies = request.getHeader(RestApiConstants.COOKIE_HEADER);
        String partialTokenFromCookie = extractPartialAccessTokenFromCookie(cookies);
        if (partialTokenFromCookie != null && isAuthorizationHeaderPresent) {
            String authHeader = request.getHeader(RestApiConstants.AUTHORIZATION_HTTP_HEADER);
            String partialTokenFromHeader = extractAccessToken(authHeader);
            accessToken = (partialTokenFromHeader != null) ? partialTokenFromHeader + partialTokenFromCookie : partialTokenFromCookie;
        }
        isTokenValid = validateTokenAndScopes(request, serviceMethodInfo, accessToken);
        request.setProperty(LOGGED_IN_USER, getEndUserName(accessToken));
    } else if (headers != null && isAuthorizationHeaderPresent) {
        String authHeader = request.getHeader(RestApiConstants.AUTHORIZATION_HTTP_HEADER);
        String accessToken = extractAccessToken(authHeader);
        if (accessToken != null) {
            isTokenValid = validateTokenAndScopes(request, serviceMethodInfo, accessToken);
            request.setProperty(LOGGED_IN_USER, getEndUserName(accessToken));
        }
    } else {
        throw new APIMgtSecurityException("Missing Authorization header in the request.`", ExceptionCodes.MALFORMED_AUTHORIZATION_HEADER_OAUTH);
    }
    return isTokenValid;
}
Also used : ErrorHandler(org.wso2.carbon.apimgt.core.exception.ErrorHandler) HttpHeaders(javax.ws.rs.core.HttpHeaders) APIMgtSecurityException(org.wso2.carbon.apimgt.rest.api.common.exception.APIMgtSecurityException)

Example 9 with ServiceMethodInfo

use of org.wso2.msf4j.ServiceMethodInfo in project carbon-apimgt by wso2.

the class OAuth2Authenticator method validateScopes.

/*
    * This method validates the given scope against scopes defined in the api resource
    * @param Request
    * @param ServiceMethodInfo
    * @param scopesToValidate scopes extracted from the access token
    * @return true if scope validation successful
    * */
@SuppressFBWarnings({ "DLS_DEAD_LOCAL_STORE" })
private boolean validateScopes(Request request, ServiceMethodInfo serviceMethodInfo, String scopesToValidate, String restAPIResource) throws APIMgtSecurityException {
    final boolean[] authorized = { false };
    String path = (String) request.getProperty(APIConstants.REQUEST_URL);
    String verb = (String) request.getProperty(APIConstants.HTTP_METHOD);
    if (log.isDebugEnabled()) {
        log.debug("Invoking rest api resource path " + verb + " " + path + " ");
        log.debug("LoggedIn user scopes " + scopesToValidate);
    }
    String[] scopesArr = new String[0];
    if (scopesToValidate != null) {
        scopesArr = scopesToValidate.split(" ");
    }
    if (scopesToValidate != null && scopesArr.length > 0) {
        final List<String> scopes = Arrays.asList(scopesArr);
        if (restAPIResource != null) {
            APIDefinition apiDefinition = new APIDefinitionFromSwagger20();
            try {
                String apiResourceDefinitionScopes = apiDefinition.getScopeOfResourcePath(restAPIResource, request, serviceMethodInfo);
                if (StringUtils.isEmpty(apiResourceDefinitionScopes)) {
                    if (log.isDebugEnabled()) {
                        log.debug("Scope not defined in swagger for matching resource " + path + " and verb " + verb + " . Hence consider as anonymous permission and let request to continue.");
                    }
                    // scope validation gets through if no scopes found in the api definition
                    authorized[0] = true;
                } else {
                    Arrays.stream(apiResourceDefinitionScopes.split(" ")).forEach(scopeKey -> {
                        Optional<String> key = scopes.stream().filter(scp -> {
                            return scp.equalsIgnoreCase(scopeKey);
                        }).findAny();
                        if (key.isPresent()) {
                            // scope validation success if one of the
                            authorized[0] = true;
                        // apiResourceDefinitionScopes found.
                        }
                    });
                }
            } catch (APIManagementException e) {
                String message = "Error while validating scopes";
                log.error(message, e);
                throw new APIMgtSecurityException(message, ExceptionCodes.INVALID_SCOPE);
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Rest API resource could not be found for request path '" + path + "'");
            }
        }
    } else {
        // scope validation gets through if access token does not contain scopes to validate
        authorized[0] = true;
    }
    if (!authorized[0]) {
        String message = "Scope validation fails for the scopes " + scopesToValidate;
        throw new APIMgtSecurityException(message, ExceptionCodes.INVALID_SCOPE);
    }
    return authorized[0];
}
Also used : Arrays(java.util.Arrays) TypeToken(com.google.gson.reflect.TypeToken) ErrorHandler(org.wso2.carbon.apimgt.core.exception.ErrorHandler) RESTAPIAuthenticator(org.wso2.carbon.apimgt.rest.api.common.api.RESTAPIAuthenticator) LoggerFactory(org.slf4j.LoggerFactory) Request(org.wso2.msf4j.Request) APIMConfigurationService(org.wso2.carbon.apimgt.core.configuration.APIMConfigurationService) APIManagerFactory(org.wso2.carbon.apimgt.core.impl.APIManagerFactory) APIDefinitionFromSwagger20(org.wso2.carbon.apimgt.core.impl.APIDefinitionFromSwagger20) StringUtils(org.apache.commons.lang3.StringUtils) APIManagementException(org.wso2.carbon.apimgt.core.exception.APIManagementException) AccessTokenInfo(org.wso2.carbon.apimgt.core.models.AccessTokenInfo) RestApiUtil(org.wso2.carbon.apimgt.rest.api.common.util.RestApiUtil) RestApiConstants(org.wso2.carbon.apimgt.rest.api.common.RestApiConstants) Response(org.wso2.msf4j.Response) Locale(java.util.Locale) APIDefinition(org.wso2.carbon.apimgt.core.api.APIDefinition) ServiceMethodInfo(org.wso2.msf4j.ServiceMethodInfo) Logger(org.slf4j.Logger) APIConstants(org.wso2.carbon.apimgt.rest.api.common.APIConstants) APIMgtSecurityException(org.wso2.carbon.apimgt.rest.api.common.exception.APIMgtSecurityException) SystemVariableUtil(org.wso2.msf4j.util.SystemVariableUtil) ExceptionCodes(org.wso2.carbon.apimgt.core.exception.ExceptionCodes) List(java.util.List) HttpHeaders(javax.ws.rs.core.HttpHeaders) Optional(java.util.Optional) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings) APIManagementException(org.wso2.carbon.apimgt.core.exception.APIManagementException) APIMgtSecurityException(org.wso2.carbon.apimgt.rest.api.common.exception.APIMgtSecurityException) APIDefinition(org.wso2.carbon.apimgt.core.api.APIDefinition) APIDefinitionFromSwagger20(org.wso2.carbon.apimgt.core.impl.APIDefinitionFromSwagger20) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings)

Aggregations

APIManagementException (org.wso2.carbon.apimgt.core.exception.APIManagementException)5 APIMgtSecurityException (org.wso2.carbon.apimgt.rest.api.common.exception.APIMgtSecurityException)5 Request (org.wso2.msf4j.Request)4 Response (org.wso2.msf4j.Response)4 ServiceMethodInfo (org.wso2.msf4j.ServiceMethodInfo)4 Swagger (io.swagger.models.Swagger)3 ErrorHandler (org.wso2.carbon.apimgt.core.exception.ErrorHandler)3 AccessTokenInfo (org.wso2.carbon.apimgt.core.models.AccessTokenInfo)3 HTTPCarbonMessage (org.wso2.transport.http.netty.message.HTTPCarbonMessage)3 Path (io.swagger.models.Path)2 SwaggerParser (io.swagger.parser.SwaggerParser)2 Method (java.lang.reflect.Method)2 HttpHeaders (javax.ws.rs.core.HttpHeaders)2 Test (org.junit.Test)2 APIManagerFactory (org.wso2.carbon.apimgt.core.impl.APIManagerFactory)2 TypeToken (com.google.gson.reflect.TypeToken)1 SuppressFBWarnings (edu.umd.cs.findbugs.annotations.SuppressFBWarnings)1 HttpMethod (io.swagger.models.HttpMethod)1 Arrays (java.util.Arrays)1 List (java.util.List)1