diff --git a/pom.xml b/pom.xml index 6d0e63a..d5d5715 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,29 @@ + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + true + + + false + + + + ossrh-snapshot + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + diff --git a/storeroom/pom.xml b/storeroom/pom.xml index 32968d5..0de50f0 100644 --- a/storeroom/pom.xml +++ b/storeroom/pom.xml @@ -55,6 +55,13 @@ modelmapper 2.3.0 + + + uk.ac.ebi.tsc.aap.client + security + 2.0.1-SNAPSHOT + + org.springframework.boot spring-boot-starter-test @@ -66,6 +73,11 @@ + + org.springframework.security + spring-security-test + test + org.springframework.restdocs spring-restdocs-mockmvc diff --git a/storeroom/src/main/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/auth/BioSamplesAAPWebSecurityConfig.java b/storeroom/src/main/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/auth/BioSamplesAAPWebSecurityConfig.java new file mode 100644 index 0000000..dd8059d --- /dev/null +++ b/storeroom/src/main/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/auth/BioSamplesAAPWebSecurityConfig.java @@ -0,0 +1,70 @@ +package uk.ac.ebi.biosamples.jsonschema.jsonschemastore.auth; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.stereotype.Component; +import uk.ac.ebi.tsc.aap.client.security.AAPWebSecurityAutoConfiguration.AAPWebSecurityConfig; +import uk.ac.ebi.tsc.aap.client.security.StatelessAuthenticationEntryPoint; +import uk.ac.ebi.tsc.aap.client.security.StatelessAuthenticationFilter; +import uk.ac.ebi.tsc.aap.client.security.TokenAuthenticationService; + +@Slf4j +@Component +@Order(99) +public class BioSamplesAAPWebSecurityConfig extends AAPWebSecurityConfig { + + // private static final String ROLE_SELF_JSON_SCHEMA_STORE = "ROLE_self.json-schema-store"; + private final StatelessAuthenticationEntryPoint unauthorizedHandler; + + private final TokenAuthenticationService tokenAuthenticationService; + + @Value("${aap.schemaAuthority}") + private String schemaAuthority; + + public BioSamplesAAPWebSecurityConfig( + StatelessAuthenticationEntryPoint unauthorizedHandler, + TokenAuthenticationService tokenAuthenticationService) { + this.unauthorizedHandler = unauthorizedHandler; + this.tokenAuthenticationService = tokenAuthenticationService; + } + + private StatelessAuthenticationFilter statelessAuthenticationFilterBean() throws Exception { + return new StatelessAuthenticationFilter(this.tokenAuthenticationService); + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + httpSecurity + // we don't need CSRF because our token is invulnerable + .csrf() + .disable() + .exceptionHandling() + .authenticationEntryPoint(unauthorizedHandler) + .and() + .authorizeRequests() + .antMatchers("/api/v1/schemas", "/api/v1/schemas/**") + // adding Authority to request for schema + .hasAuthority(schemaAuthority) + .and() + // don't create session + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + httpSecurity.addFilterBefore( + statelessAuthenticationFilterBean(), UsernamePasswordAuthenticationFilter.class); + + // disable the no-cache header injectection, we'll manage this ourselves + httpSecurity.headers().cacheControl().disable(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService()); + } +} diff --git a/storeroom/src/main/resources/application-dev.yml b/storeroom/src/main/resources/application-dev.yml index bfdc847..cf11fa9 100644 --- a/storeroom/src/main/resources/application-dev.yml +++ b/storeroom/src/main/resources/application-dev.yml @@ -17,3 +17,13 @@ management: # Elixir Validator elixirValidator: hostUrl: http://localhost:3000/validate + +# BioSample AAP Conf +aap: + url: https://explore.api.aai.ebi.ac.uk + schemaAuthority: ROLE_self.json-schema-store +jwt: + certificate: https://explore.api.aai.ebi.ac.uk/meta/public.der +#aap-client: +# cors: +# enabled: true \ No newline at end of file diff --git a/storeroom/src/main/resources/application-docker.yml b/storeroom/src/main/resources/application-docker.yml index 095d033..79ebf60 100644 --- a/storeroom/src/main/resources/application-docker.yml +++ b/storeroom/src/main/resources/application-docker.yml @@ -17,3 +17,10 @@ management: # Elixir Validator elixirValidator: hostUrl: http://validator:3020/validate + +# BioSample AAP Conf +aap: + url: https://explore.api.aai.ebi.ac.uk + schemaAuthority: ROLE_self.json-schema-store +jwt: + certificate: https://explore.api.aai.ebi.ac.uk/meta/public.der diff --git a/storeroom/src/main/resources/application-test.yml b/storeroom/src/main/resources/application-test.yml index 1525079..72658f7 100644 --- a/storeroom/src/main/resources/application-test.yml +++ b/storeroom/src/main/resources/application-test.yml @@ -10,3 +10,10 @@ spring: # Elixir Validator elixirValidator: hostUrl: http://localhost:3000/validate + +# BioSample AAP Conf +aap: + url: https://explore.api.aai.ebi.ac.uk + schemaAuthority: ROLE_self.json-schema-store +jwt: + certificate: https://explore.api.aai.ebi.ac.uk/meta/public.der diff --git a/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateFastTest.java b/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateFastTest.java new file mode 100644 index 0000000..036e9e7 --- /dev/null +++ b/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateFastTest.java @@ -0,0 +1,101 @@ +package uk.ac.ebi.biosamples.jsonschema.jsonschemastore.integration.schema.resource; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.RequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.dto.SchemaBlockDocument; +import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.integration.util.AppClientHelper; +import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.integration.util.SchemaBlockFactoryUtil; +import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.schema.document.SchemaBlock; +import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.schema.repository.SchemaBlockRepository; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles(profiles = "test") +class SchemaBlockControllerIntegrateFastTest { + + private static final String jwt = AppClientHelper.getToken(); + + @Autowired private MockMvc mockMvc; + @Autowired private SchemaBlockRepository schemaBlockRepository; + @Autowired private ObjectMapper objectMapper; + @Autowired private ModelMapper modelMapper; + private SchemaBlock schemaBlock; + + @BeforeEach + public void init() throws JsonProcessingException { + schemaBlockRepository.deleteAll(); + schemaBlock = SchemaBlockFactoryUtil.getSchemaBlockObject(); + } + + @Test + public void testGetAllSchemaBlock() throws Exception { + schemaBlockRepository.save(schemaBlock); + RequestBuilder requestBuilder = + MockMvcRequestBuilders.get("/api/v1/schemas").header(AppClientHelper.AUTHORIZATION, jwt); + MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); + assertEquals(200, mvcResult.getResponse().getStatus(), "status code is not equal."); + assertEquals( + modelMapper.map(schemaBlock, SchemaBlockDocument.class), + objectMapper + .readValue(mvcResult.getResponse().getContentAsString(), SchemaBlockDocument[].class)[ + 0], + "schemaBlock is not equal."); + } + + @Test + public void testGetSchemaBlockById() throws Exception { + schemaBlockRepository.save(schemaBlock); + RequestBuilder requestBuilder = + MockMvcRequestBuilders.get("/api/v1/schemas/") + .param("id", schemaBlock.getId()) + .header(AppClientHelper.AUTHORIZATION, jwt); + MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); + assertEquals(200, mvcResult.getResponse().getStatus(), "status code is not equal."); + JsonNode jsonNode = objectMapper.readTree(mvcResult.getResponse().getContentAsString()); + assertEquals( + modelMapper.map(schemaBlock, SchemaBlockDocument.class), + objectMapper.readValue(jsonNode.toPrettyString(), SchemaBlockDocument.class), + "schemaBlockDocument ids are not equal."); + } + + @Test + public void testDeleteSchemaBlocks() throws Exception { + schemaBlockRepository.save(schemaBlock); + assertEquals(1, schemaBlockRepository.count()); + RequestBuilder requestBuilder = + MockMvcRequestBuilders.delete("/api/v1/schemas") + .header(AppClientHelper.AUTHORIZATION, jwt) + .contentType("application/json") + .content(SchemaBlockFactoryUtil.SCHEMA); + MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); + assertEquals(204, mvcResult.getResponse().getStatus(), "status code is not equal."); + assertEquals(0, schemaBlockRepository.count(), "count should be 0 after deleting"); + } + + @Test + public void testDeleteSchemaBlocksById() throws Exception { + schemaBlockRepository.save(schemaBlock); + assertEquals(1, schemaBlockRepository.count()); + RequestBuilder requestBuilder = + MockMvcRequestBuilders.delete("/api/v1/schemas/") + .param("id", schemaBlock.getId()) + .header(AppClientHelper.AUTHORIZATION, jwt); + MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); + assertEquals(204, mvcResult.getResponse().getStatus(), "status code is not equal."); + assertEquals(0, schemaBlockRepository.count(), "count should be 0 after deleting"); + } +} diff --git a/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateTest.java b/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateTest.java index da074aa..414c7f0 100644 --- a/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateTest.java +++ b/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/schema/resource/SchemaBlockControllerIntegrateTest.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.ClassRule; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.modelmapper.ModelMapper; @@ -19,6 +20,7 @@ import org.testcontainers.containers.DockerComposeContainer; import org.testcontainers.containers.wait.strategy.Wait; import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.dto.SchemaBlockDocument; +import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.integration.util.AppClientHelper; import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.integration.util.SchemaBlockFactoryUtil; import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.schema.document.SchemaBlock; import uk.ac.ebi.biosamples.jsonschema.jsonschemastore.schema.repository.SchemaBlockRepository; @@ -32,6 +34,8 @@ @ActiveProfiles(profiles = "test") class SchemaBlockControllerIntegrateTest { + private static final String jwt = AppClientHelper.getToken(); + @ClassRule private static final DockerComposeContainer environment = new DockerComposeContainer( @@ -46,68 +50,23 @@ class SchemaBlockControllerIntegrateTest { @Autowired private ModelMapper modelMapper; private SchemaBlock schemaBlock; + @BeforeAll + public static void setup() { + environment.start(); + } + @BeforeEach public void init() throws JsonProcessingException { schemaBlockRepository.deleteAll(); schemaBlock = SchemaBlockFactoryUtil.getSchemaBlockObject(); } - @Test - public void testGetAllSchemaBlock() throws Exception { - schemaBlockRepository.save(schemaBlock); - RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/api/v1/schemas"); - MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); - assertEquals(200, mvcResult.getResponse().getStatus(), "status code is not equal."); - assertEquals( - modelMapper.map(schemaBlock, SchemaBlockDocument.class), - objectMapper - .readValue(mvcResult.getResponse().getContentAsString(), SchemaBlockDocument[].class)[0], - "schemaBlock is not equal."); - } - - @Test - public void testGetSchemaBlockById() throws Exception { - schemaBlockRepository.save(schemaBlock); - RequestBuilder requestBuilder = - MockMvcRequestBuilders.get("/api/v1/schemas/").param("id", schemaBlock.getId()); - MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); - assertEquals(200, mvcResult.getResponse().getStatus(), "status code is not equal."); - JsonNode jsonNode = objectMapper.readTree(mvcResult.getResponse().getContentAsString()); - assertEquals( - modelMapper.map(schemaBlock, SchemaBlockDocument.class), - objectMapper.readValue(jsonNode.toPrettyString(), SchemaBlockDocument.class), - "schemaBlockDocument ids are not equal."); - } - - @Test - public void testDeleteSchemaBlocks() throws Exception { - schemaBlockRepository.save(schemaBlock); - assertEquals(1, schemaBlockRepository.count()); - RequestBuilder requestBuilder = MockMvcRequestBuilders.delete("/api/v1/schemas") - .contentType("application/json") - .content(SchemaBlockFactoryUtil.SCHEMA); - MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); - assertEquals(204, mvcResult.getResponse().getStatus(), "status code is not equal."); - assertEquals(0, schemaBlockRepository.count(), "count should be 0 after deleting"); - } - - @Test - public void testDeleteSchemaBlocksById() throws Exception { - schemaBlockRepository.save(schemaBlock); - assertEquals(1, schemaBlockRepository.count()); - RequestBuilder requestBuilder = MockMvcRequestBuilders.delete("/api/v1/schemas/").param("id", schemaBlock.getId()); - MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); - assertEquals(204, mvcResult.getResponse().getStatus(), "status code is not equal."); - assertEquals(0, schemaBlockRepository.count(), "count should be 0 after deleting"); - } - @Test public void testCreateSchemaBlock() throws Exception { - try { - environment.start(); assertEquals(0L, schemaBlockRepository.count()); RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/api/v1/schemas") + .header(AppClientHelper.AUTHORIZATION, jwt) .contentType("application/json") .content(SchemaBlockFactoryUtil.SCHEMA); MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); @@ -120,25 +79,23 @@ public void testCreateSchemaBlock() throws Exception { modelMapper.map(schemaBlock, SchemaBlockDocument.class), objectMapper.readValue(jsonNode.toPrettyString(), SchemaBlockDocument.class), "schemaBlockDocument ids are not equal."); - } finally { - environment.stop(); - } } @Test public void testUpdateSchemaBlocks() throws Exception { - try { schemaBlockRepository.save(schemaBlock); assertEquals(1, schemaBlockRepository.count()); - environment.start(); - SchemaBlockDocument schemaBlockDocument = objectMapper.readValue(SchemaBlockFactoryUtil.SCHEMA, SchemaBlockDocument.class); - ObjectNode objectNode = (ObjectNode) objectMapper.readTree(schemaBlockDocument.getJsonSchema()); + SchemaBlockDocument schemaBlockDocument = + objectMapper.readValue(SchemaBlockFactoryUtil.SCHEMA, SchemaBlockDocument.class); + ObjectNode objectNode = + (ObjectNode) objectMapper.readTree(schemaBlockDocument.getJsonSchema()); String newTitle = "Disease new"; objectNode.put("title", newTitle); RequestBuilder requestBuilder = - MockMvcRequestBuilders.put("/api/v1/schemas") - .contentType("application/json") - .content(objectNode.toPrettyString()); + MockMvcRequestBuilders.put("/api/v1/schemas") + .header(AppClientHelper.AUTHORIZATION, jwt) + .contentType("application/json") + .content(objectNode.toPrettyString()); MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn(); assertEquals(201, mvcResult.getResponse().getStatus(), "Response status was not 201."); assertEquals(1L, schemaBlockRepository.count()); @@ -147,8 +104,5 @@ public void testUpdateSchemaBlocks() throws Exception { JsonNode jsonNode = objectMapper.readTree(mvcResult.getResponse().getContentAsString()); assertEquals(schemaBlock.getId(), jsonNode.get("$id").asText()); assertEquals(newTitle, jsonNode.get("title").asText()); - } finally { - environment.stop(); - } } } diff --git a/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/util/AppClientHelper.java b/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/util/AppClientHelper.java new file mode 100644 index 0000000..d5c9ae2 --- /dev/null +++ b/storeroom/src/test/java/uk/ac/ebi/biosamples/jsonschema/jsonschemastore/integration/util/AppClientHelper.java @@ -0,0 +1,27 @@ +package uk.ac.ebi.biosamples.jsonschema.jsonschemastore.integration.util; + +import org.junit.jupiter.api.Assertions; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +public class AppClientHelper { + + public static final String AUTHORIZATION = "Authorization"; + private static final String BEARER = "Bearer "; + + private static final String appUrl = "https://explore.api.aai.ebi.ac.uk"; + private static final String userName = "hrashmi"; + private static final String password = "Tester123!"; + + public static String getToken() { + TestRestTemplate testRestTemplate = new TestRestTemplate(); + ResponseEntity response = + testRestTemplate + .withBasicAuth(userName, password) + .getForEntity(appUrl + "/auth", String.class); + Assertions.assertEquals( + HttpStatus.OK, response.getStatusCode(), "Getting Jwt was not succeed!"); + return BEARER + response.getBody(); + } +}