diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 95f3fe8718c125e5b50ac347ba860819d8283315..cff7fecdc8f8283f23fac1ecd0b464019778b817 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,10 @@ variables: AWS_SERVICE: crs-conversion AWS_ENVIRONMENT: dev AWS_INT_TEST_TYPE: python + + IBM_BUILD_SUBDIR: provider/crs-converter-ibm/crs-converter-ocp + IBM_INT_TEST_PY_SUBDIR: testing/crs_converter_test_ibm + IBM_INT_TEST_PY_FILE: run_test.py include: - project: "osdu/platform/ci-cd-pipelines" @@ -22,4 +26,7 @@ include: - project: "osdu/platform/ci-cd-pipelines" file: "cloud-providers/aws.yml" + + - project: "osdu/platform/ci-cd-pipelines" + file: "cloud-providers/ibm.yml" \ No newline at end of file diff --git a/pom.xml b/pom.xml index 05cbf5b181a86264df3b6676f1b4c36feb270390..c3fdf820d143698f2856caf45b28211ce647c6c9 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,7 @@ <module>provider/crs-converter-gcp/crs-converter-gae</module> <module>provider/crs-converter-gcp/crs-converter-gke</module> <module>provider/crs-converter-aws</module> + <module>provider/crs-converter-ibm/crs-converter-ocp</module> </modules> <repositories> diff --git a/provider/crs-converter-ibm/crs-converter-ocp/pom.xml b/provider/crs-converter-ibm/crs-converter-ocp/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e2b1e77178b6ba57804fc1318f58bd94e804d78 --- /dev/null +++ b/provider/crs-converter-ibm/crs-converter-ocp/pom.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <packaging>jar</packaging> + + <parent> + <groupId>org.opengroup.osdu.crs-converter-service</groupId> + <artifactId>crs-converter-service</artifactId> + <version>1.0.0</version> + <relativePath>../../../pom.xml</relativePath> + </parent> + + <properties> + <app.version>1</app.version> + <app.id>crs-converter-ocp</app.id> + <!--azure.version>2.3.2</azure.version--> + <os-core-lib-ibm.version>0.3.6-SNAPSHOT</os-core-lib-ibm.version> + </properties> + + <prerequisites> + <maven>3.1.0</maven> + </prerequisites> + + <artifactId>crs-converter-ocp</artifactId> + <version>1.0.0-SNAPSHOT</version> + <name>crs-converter-ocp</name> + <description>CRS converter service Openshift Container Platform deployment</description> + + <dependencies> + <dependency> + <groupId>org.opengroup.osdu.crs-converter-service</groupId> + <artifactId>crs-converter-core</artifactId> + <version>1.0.0</version> + </dependency> + + <!--dependency> + <groupId>com.microsoft.azure</groupId> + <artifactId>azure-active-directory-spring-boot-starter</artifactId> + <version>${azure.version}</version> + </dependency--> + + <!-- dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency--> + + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>os-core-lib-ibm</artifactId> + <version>${os-core-lib-ibm.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <configuration> + <classifier>spring-boot</classifier> + <mainClass> + org.opengroup.osdu.crs.CrsOcpApplication + </mainClass> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + </build> + +</project> diff --git a/provider/crs-converter-ibm/crs-converter-ocp/src/main/java/org/opengroup/osdu/crs/CrsOcpApplication.java b/provider/crs-converter-ibm/crs-converter-ocp/src/main/java/org/opengroup/osdu/crs/CrsOcpApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..fb23aec31c260098d1050a1741d1c81572cf7881 --- /dev/null +++ b/provider/crs-converter-ibm/crs-converter-ocp/src/main/java/org/opengroup/osdu/crs/CrsOcpApplication.java @@ -0,0 +1,13 @@ +package org.opengroup.osdu.crs; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CrsOcpApplication extends CRSApplicationBase { + + public static void main(String[] args) { + SpringApplication.run(CrsOcpApplication.class, args); + } + +} diff --git a/provider/crs-converter-ibm/crs-converter-ocp/src/main/java/org/opengroup/osdu/crs/security/SecurityConfig.java b/provider/crs-converter-ibm/crs-converter-ocp/src/main/java/org/opengroup/osdu/crs/security/SecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..e080e5951324aa9c71f990075d8684126d902d56 --- /dev/null +++ b/provider/crs-converter-ibm/crs-converter-ocp/src/main/java/org/opengroup/osdu/crs/security/SecurityConfig.java @@ -0,0 +1,103 @@ +package org.opengroup.osdu.crs.security; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.opengroup.osdu.crs.middleware.AuthenticationRequestFilter; +import org.opengroup.osdu.crs.util.AppError; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.AuthenticationException; +import org.springframework.web.servlet.HandlerExceptionResolver; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter implements AccessDeniedHandler, AuthenticationEntryPoint { + + private AuthenticationRequestFilter authFilter; + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + private static final String[] AUTH_WHITELIST = { + "/", + "/index.html", + "/_ah/*", + "/v2/api-docs", + "/configuration/ui", + "/swagger-resources/**", + "/configuration/security", + "/swagger", + "/swagger-ui.html", + "/webjars/**", + "/csrf" + }; + + @Override + protected void configure(HttpSecurity http) throws Exception { + + http.csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER) + .and() + .authorizeRequests() + .antMatchers(AUTH_WHITELIST).permitAll() + .anyRequest().authenticated() + .and() + .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class); + //.oauth2ResourceServer().jwt(); + + + } + + public SecurityConfig(@Value("${ENTITLEMENT_URL}") String entitlementsUrl, HandlerExceptionResolver handlerExceptionResolver) { + authFilter = new AuthenticationRequestFilter(entitlementsUrl, handlerExceptionResolver); + } + @Override + public void configure(WebSecurity web) { + web.ignoring().antMatchers(AUTH_WHITELIST); + } + + @Override + public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { + writeUnauthorizedError(httpServletResponse); + } + + @Override + public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException { + writeUnauthorizedError(httpServletResponse); + } + + private static void writeUnauthorizedError(HttpServletResponse response) throws IOException { + AppError appError = AppError.builder() + .code(HttpStatus.UNAUTHORIZED.value()) + .message("The user is not authorized to perform this action") + .reason("Unauthorized") + .build(); + String body = OBJECT_MAPPER.writeValueAsString(appError); + + PrintWriter out = response.getWriter(); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + out.print(body); + out.flush(); + } + + +} \ No newline at end of file diff --git a/provider/crs-converter-ibm/crs-converter-ocp/src/main/resources/application.yaml b/provider/crs-converter-ibm/crs-converter-ocp/src/main/resources/application.yaml new file mode 100644 index 0000000000000000000000000000000000000000..37dc12279934a09d87a59ce340bcf6918a823fc8 --- /dev/null +++ b/provider/crs-converter-ibm/crs-converter-ocp/src/main/resources/application.yaml @@ -0,0 +1,24 @@ +server: + port: 8080 + + servlet: + application-display-name: CRS Converter Service + contextPath: /api/crs/converter/ + + error.whitelabel.enabled: false + +spring.mvc.throw-exception-if-no-handler-found: true + +logging: + level: + org: + springframework: + web: INFO +LOG_PREFIX: converter + +spring: + security: + oauth2: + resourceserver: + jwt: + jwk-set-uri: "{{ spring.security.oauth2.resourceserver.jwt.jwk-set-uri }}" \ No newline at end of file diff --git a/testing/crs_converter_test_core/constants.py b/testing/crs_converter_test_core/constants.py index 465ad4468887643fa1d4e5d04a01c598b5870b8c..490b0c7ac3657b55bd0f7e9777841c88069954e5 100644 --- a/testing/crs_converter_test_core/constants.py +++ b/testing/crs_converter_test_core/constants.py @@ -1,8 +1,12 @@ -import os - -BASE_URL = os.getenv("BASE_URL", '/api/crs/converter/v2') -ROOT_URL = os.getenv("VIRTUAL_SERVICE_HOST_NAME") -DATA_DIR = os.getenv("DATA_DIR") -DATA_PATTERN = os.getenv("DATA_PATTERN") -REPORT_PATH = os.getenv("REPORT_PATH") -MY_TENANT = os.getenv("MY_TENANT") +import os + +VENDOR = os.getenv("VENDOR") +BASE_URL = os.getenv("BASE_URL", '/api/crs/converter/v2') +if VENDOR == 'ibm': + ROOT_URL = os.getenv("IBM_VIRTUAL_HOST_CRS_CONVERSION") +else: + ROOT_URL = os.getenv("VIRTUAL_SERVICE_HOST_NAME") +DATA_DIR = os.getenv("DATA_DIR") +DATA_PATTERN = os.getenv("DATA_PATTERN") +REPORT_PATH = os.getenv("REPORT_PATH") +MY_TENANT = os.getenv("MY_TENANT") diff --git a/testing/crs_converter_test_core/test_crs_converter.py b/testing/crs_converter_test_core/test_crs_converter.py index 14692fcca2c564d2a69c99972f85e1c460919941..659053c566232e8943433dfca4636f242464bd9d 100644 --- a/testing/crs_converter_test_core/test_crs_converter.py +++ b/testing/crs_converter_test_core/test_crs_converter.py @@ -519,7 +519,7 @@ class TestUnAuthorizedCrsConverterIntegration(unittest.TestCase): except ApiException as e: reason = json.loads(e.body)['reason'] self.assertTrue(403==e.status or 401==e.status) - self.assertTrue("Forbidden"==e.reason or "Unauthorized"==e.reason) + self.assertTrue("Forbidden"==reason or "Unauthorized"==reason) if __name__ == '__main__': diff --git a/testing/crs_converter_test_ibm/jwt_client.py b/testing/crs_converter_test_ibm/jwt_client.py new file mode 100644 index 0000000000000000000000000000000000000000..8cb2d09c65cfb5ba406c7e1455fb28b68cb4cd9b --- /dev/null +++ b/testing/crs_converter_test_ibm/jwt_client.py @@ -0,0 +1,56 @@ + +import os +from keycloak import KeycloakOpenID + +def get_id_token(): + + keycloak_host = os.getenv('KEYCLOAK_URL') + keycloak_realm = os.getenv('KEYCLOAK_REALM', "OSDU") + client_id = os.getenv('KEYCLOAK_CLIENT_ID') + client_secret = os.getenv('KEYCLOAK_CLIENT_SECRET') + + user = os.getenv('AUTH_USER_ACCESS') + password = os.getenv('AUTH_USER_ACCESS_PASSWORD') + + try: + # Configure client + keycloak_openid = KeycloakOpenID(server_url="https://"+keycloak_host+"/auth/", + client_id=client_id, + realm_name=keycloak_realm, + client_secret_key=client_secret) + + token = keycloak_openid.token(user, password) + return token['access_token'] + except Exception as e: + print(e) + + +def get_invalid_token(): + + ''' + This is dummy jwt + { + "sub": "dummy@dummy.com", + "iss": "dummy@dummy.com", + "aud": "dummy.dummy.com", + "iat": 1556137273, + "exp": 1556223673, + "provider": "dummy.com", + "client": "dummy.com", + "userid": "dummytester.com", + "email": "dummytester.com", + "authz": "", + "lastname": "dummy", + "firstname": "dummy", + "country": "", + "company": "", + "jobtitle": "", + "subid": "dummyid", + "idp": "dummy", + "hd": "dummy.com", + "desid": "dummyid", + "contact_email": "dummy@dummy.com" + } + ''' + + return "fake.token" \ No newline at end of file diff --git a/testing/crs_converter_test_ibm/requirements.txt b/testing/crs_converter_test_ibm/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..d33b7de4de3eafcbf07c26b0eae72c878939e579 --- /dev/null +++ b/testing/crs_converter_test_ibm/requirements.txt @@ -0,0 +1,13 @@ +certifi==2019.11.28 +cffi==1.14.0 +chardet==3.0.4 +cryptography==2.8 +idna==2.9 +pycparser==2.20 +PyJWT==1.7.1 +python-dateutil==2.8.1 +requests==2.23.0 +six==1.14.0 +urllib3==1.25.8 +python-keycloak==0.21.0 +python-dotenv==0.14.0 diff --git a/testing/crs_converter_test_ibm/run_test.py b/testing/crs_converter_test_ibm/run_test.py new file mode 100644 index 0000000000000000000000000000000000000000..7ad8ee9f8d1dad47f149fad54cf337c0c967e627 --- /dev/null +++ b/testing/crs_converter_test_ibm/run_test.py @@ -0,0 +1,7 @@ +import sys +sys.path.append("..") + +from crs_converter_test_core.test_crs_converter import * + +if __name__ == '__main__': + unittest.main()