diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb10c56..36ef6609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Length for Column "SUB_PROTOCOL_BODY" has been extended to 2048. ## fixed - +- Fix done for encoding input parameter to get shell look up api. +- Fixed response for GetDescription api. ## 0.3.20 ### Added diff --git a/backend/src/main/java/org/eclipse/tractusx/semantics/registry/controller/AssetAdministrationShellApiDelegate.java b/backend/src/main/java/org/eclipse/tractusx/semantics/registry/controller/AssetAdministrationShellApiDelegate.java index 19293732..4973e82d 100644 --- a/backend/src/main/java/org/eclipse/tractusx/semantics/registry/controller/AssetAdministrationShellApiDelegate.java +++ b/backend/src/main/java/org/eclipse/tractusx/semantics/registry/controller/AssetAdministrationShellApiDelegate.java @@ -19,7 +19,9 @@ ********************************************************************************/ package org.eclipse.tractusx.semantics.registry.controller; +import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; import org.eclipse.tractusx.semantics.aas.registry.api.DescriptionApiDelegate; import org.eclipse.tractusx.semantics.aas.registry.api.LookupApiDelegate; @@ -39,6 +41,9 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.context.request.NativeWebRequest; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; + @Service public class AssetAdministrationShellApiDelegate implements DescriptionApiDelegate, ShellDescriptorsApiDelegate, LookupApiDelegate { @@ -62,8 +67,7 @@ public Optional getRequest() { @Override public ResponseEntity getDescription() { ServiceDescription serviceDescription = new ServiceDescription(); - serviceDescription.setProfiles( List.of( ServiceDescription.ProfilesEnum.ASSETADMINISTRATIONSHELLREPOSITORYSERVICESPECIFICATION_V3_0_MINIMALPROFILE, - ServiceDescription.ProfilesEnum.REGISTRYSERVICESPECIFICATION_V3_0) ); + serviceDescription.setProfiles( List.of( ServiceDescription.ProfilesEnum.ASSETADMINISTRATIONSHELLREGISTRYSERVICESPECIFICATION_SSP_001, ServiceDescription.ProfilesEnum.DISCOVERYSERVICESPECIFICATION_SSP_001) ); return new ResponseEntity<>( serviceDescription, HttpStatus.OK ); } @@ -149,16 +153,29 @@ public ResponseEntity putSubmodelDescriptorByIdThroughSuperpath( byte[] aa } @Override - public ResponseEntity getAllAssetAdministrationShellIdsByAssetLink(List assetIds, + public ResponseEntity getAllAssetAdministrationShellIdsByAssetLink(List assetIds, Integer limit, String cursor, @RequestHeader String externalSubjectId) { if (assetIds == null || assetIds.isEmpty()) { return new ResponseEntity<>(new GetAllAssetAdministrationShellIdsByAssetLink200Response(), HttpStatus.OK); } + + List listSpecificAssetId =assetIds.stream().map( this::decodeSAID).collect( Collectors.toList()); GetAllAssetAdministrationShellIdsByAssetLink200Response result = - shellService.findExternalShellIdsByIdentifiersByExactMatch(shellMapper.fromApiDto(assetIds), limit, cursor,getExternalSubjectIdOrEmpty(externalSubjectId)); + shellService.findExternalShellIdsByIdentifiersByExactMatch(shellMapper.fromApiDto(listSpecificAssetId), limit, cursor,getExternalSubjectIdOrEmpty(externalSubjectId)); return new ResponseEntity<>(result, HttpStatus.OK); } + private SpecificAssetId decodeSAID(byte[] encodedId){ + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion( JsonInclude.Include.NON_NULL); + try { + byte[] decodedBytes = Base64.getUrlDecoder().decode( encodedId ); + return mapper.readValue(decodedBytes, SpecificAssetId.class ); + } catch (Exception e ) { + throw new IllegalArgumentException("Incorrect Base64 encoded value provided as parameter"); + } + } + @Override public ResponseEntity> getAllAssetLinksById(byte[] aasIdentifier,@RequestHeader String externalSubjectId) { Set identifiers = shellService.findShellIdentifiersByExternalShellId(getDecodedId( aasIdentifier ),getExternalSubjectIdOrEmpty(externalSubjectId)); diff --git a/backend/src/main/java/org/eclipse/tractusx/semantics/registry/security/OAuthSecurityConfig.java b/backend/src/main/java/org/eclipse/tractusx/semantics/registry/security/OAuthSecurityConfig.java index cfb72159..ffe01b59 100644 --- a/backend/src/main/java/org/eclipse/tractusx/semantics/registry/security/OAuthSecurityConfig.java +++ b/backend/src/main/java/org/eclipse/tractusx/semantics/registry/security/OAuthSecurityConfig.java @@ -65,6 +65,9 @@ protected SecurityFilterChain configure(HttpSecurity http) throws Exception { .requestMatchers( HttpMethod.POST, "/**/lookup/**" ).access( "@authorizationEvaluator.hasRoleAddDigitalTwin()" ) .requestMatchers( HttpMethod.PUT, "/**/lookup/**" ).access( "@authorizationEvaluator.hasRoleUpdateDigitalTwin()" ) .requestMatchers( HttpMethod.DELETE, "/**/lookup/**" ).access( "@authorizationEvaluator.hasRoleDeleteDigitalTwin()" ) + + //getDescription allowed for reader + .requestMatchers( HttpMethod.GET, "/**/description" ).access( "@authorizationEvaluator.hasRoleViewDigitalTwin()" ) ) .csrf(CsrfConfigurer::disable) .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) diff --git a/backend/src/main/resources/static/aas-registry-openapi.yaml b/backend/src/main/resources/static/aas-registry-openapi.yaml index ca253579..e6ed5018 100644 --- a/backend/src/main/resources/static/aas-registry-openapi.yaml +++ b/backend/src/main/resources/static/aas-registry-openapi.yaml @@ -703,16 +703,12 @@ paths: # the "content" is the correct way to accept json encoded query parameters # style: form # explode: true - content: - application/json: - schema: - type: array - maxItems: 10000 - items: - $ref: '#/components/schemas/SpecificAssetId' - examples: - complete: - $ref: '#/components/examples/lookup-shells-by-aas-identifier-query' + schema: + type: array + items: + type: string + format: byte + example: '?assetIds=eyAibmFtZSI6ICJzb21lLWFzc2V0LWlkIiwgInZhbHVlIjogImh0dHA6Ly9leGFtcGxlLWNvbXBhbnkuY29tL215QXNzZXQiLCAiZXh0ZXJuYWxTdWJqZWN0SWQiOiB7ICJrZXlzIjogWyB7ICJ0eXBlIjogIkdsb2JhbFJlZmVyZW5jZSIsICJ2YWx1ZSI6ICJodHRwOi8vZXhhbXBsZS1jb21wYW55LmNvbS9leGFtcGxlLWNvbXBhbnlzLWFzc2V0LWtleXMiIH0gXSwgInR5cGUiOiAiR2xvYmFsUmVmZXJlbmNlIiB9IH0&assetIds=eyAibmFtZSI6ICJzb21lLW90aGVyLWFzc2V0LWlkIiwgInZhbHVlIjogIjEyMzQ1QUJDIiwgImV4dGVybmFsU3ViamVjdElkIjogeyAia2V5cyI6IFsgeyAidHlwZSI6ICJHbG9iYWxSZWZlcmVuY2UiLCAidmFsdWUiOiAiaHR0cDovL215LW93bi1jb21wYW55LmNvbS9rZXlzIiB9IF0sICJ0eXBlIjogIkdsb2JhbFJlZmVyZW5jZSIgfSB9' - name: limit in: query description: The maximum number of elements in the response array @@ -1505,29 +1501,30 @@ components: properties: profiles: minItems: 1 - maxItems: 10000 type: array items: type: string enum: - - AssetAdministrationShellServiceSpecification/V3.0 - - AssetAdministrationShellServiceSpecification/V3.0-MinimalProfile - - SubmodelServiceSpecification/V3.0 - - SubmodelServiceSpecification/V3.0-ValueProfile - - SubmodelServiceSpecification/V3.0-MinimalProfile - - AasxFileServerServiceSpecification/V3.0 - - RegistryServiceSpecification/V3.0 - - RegistryServiceSpecification/V3.0- AssetAdministrationShellRegistry - - RegistryServiceSpecification/V3.0-SubmodelRegistry - - RepositoryServiceSpecification/V3.0 - - RepositoryServiceSpecification/V3.0-MinimalProfile - - AssetAdministrationShellRepositoryServiceSpecification/V3.0 - - AssetAdministrationShellRepositoryServiceSpecification/V3.0-MinimalProfile - - SubmodelRepositoryServiceSpecification/V3.0 - - SubmodelRepositoryServiceSpecification/V3.0-MinimalProfile - - RegistryAndDiscoveryServiceSpecification/V3.0 + - https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/AssetAdministrationShellServiceSpecification/SSP-002 + - https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-002 + - https://admin-shell.io/aas/API/3/0/SubmodelServiceSpecification/SSP-003 + - https://admin-shell.io/aas/API/3/0/AasxFileServerServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-002 + - https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-002 + - https://admin-shell.io/aas/API/3/0/DiscoveryServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRepositoryServiceSpecification/SSP-002 + - https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-001 + - https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-002 + - https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-003 + - https://admin-shell.io/aas/API/3/0/SubmodelRepositoryServiceSpecification/SSP-004 + - https://admin-shell.io/aas/API/3/0/ConceptDescriptionServiceSpecification/SSP-001 description: "The Description object enables servers to present their capabilities to the clients, in particular which profiles they implement. At least one defined profile is required. Additional, proprietary attributes might be included. Nevertheless, the server must not expect that a regular client understands them." - example: { "profiles": [ "RepositoryServiceSpecification/V3.0-MinimalProfile", "RegistryServiceSpecification/V3.0" ] } + example: { "profiles": ["https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-002", "https://admin-shell.io/aas/API/3/0/SubmodelRegistryServiceSpecification/SSP-002"] } PagedResult_paging_metadata: type: object properties: diff --git a/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiSecurityTest.java b/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiSecurityTest.java index b0c06d85..3ce5802a 100644 --- a/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiSecurityTest.java +++ b/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiSecurityTest.java @@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.*; +import java.util.Base64; import java.util.List; import java.util.UUID; @@ -515,11 +516,12 @@ class LookupTest { public void testRbacForLookupByAssetIds() throws Exception { SpecificAssetId specificAssetId = TestUtil.createSpecificAssetId(); + String encodedObject = Base64.getUrlEncoder().encodeToString(serialize( specificAssetId)); mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) - .queryParam("assetIds", mapper.writeValueAsString(specificAssetId)) + .queryParam("assetIds", encodedObject) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.addTwin()) ) @@ -528,7 +530,7 @@ public void testRbacForLookupByAssetIds() throws Exception { mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) - .param("assetIds",mapper.writeValueAsString(specificAssetId)) + .param("assetIds",encodedObject) .contentType(MediaType.APPLICATION_JSON_VALUE) .queryParam("limit", "10") .accept(MediaType.APPLICATION_JSON_VALUE) @@ -809,11 +811,13 @@ public void testGetSpecificAssetIdsFilteredByTenantId() throws Exception { .andExpect(status().isCreated()) .andExpect(content().json(mapper.writeValueAsString(List.of(specificAssetId)))); - mvc.perform( + String encodedObject = Base64.getUrlEncoder().encodeToString(serialize( specificAssetId)); + + mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(specificAssetId))) + .queryParam("assetIds", encodedObject) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.allRoles()) ) @@ -827,7 +831,7 @@ public void testGetSpecificAssetIdsFilteredByTenantId() throws Exception { .get(LOOKUP_SHELL_BASE_PATH) .accept(MediaType.APPLICATION_JSON) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantTwo().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(specificAssetId))) + .queryParam("assetIds", encodedObject) .with(jwtTokenFactory.tenantTwo().allRoles()) ) .andDo(MockMvcResultHandlers.print()) @@ -854,11 +858,14 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityE SpecificAssetId sa1 = TestUtil.createSpecificAssetId(keyPrefix + "findExternal_2_1","value_2_1",List.of(jwtTokenFactory.tenantTwo().getTenantId())); SpecificAssetId sa2 = TestUtil.createSpecificAssetId(keyPrefix + "findExternal_2_2","value_2_2",List.of(jwtTokenFactory.tenantThree().getTenantId())); + String encodedSa1 = Base64.getUrlEncoder().encodeToString(serialize( sa1)); + String encodedSa2 = Base64.getUrlEncoder().encodeToString(serialize( sa2)); mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa1,sa2))) + .queryParam("assetIds", encodedSa1) + .queryParam("assetIds", encodedSa2) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.allRoles()) ) @@ -871,12 +878,12 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityE // test with tenantTwo assetId included SpecificAssetId specificAssetIdsWithTenantTwoIncluded = TestUtil.createSpecificAssetId(keyPrefix + "findExternal_2_2","value_2_2",null); - + String encodedSaWithTenantTwoIncluded = Base64.getUrlEncoder().encodeToString(serialize( specificAssetIdsWithTenantTwoIncluded)); mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantTwo().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(specificAssetIdsWithTenantTwoIncluded)) + .queryParam("assetIds", encodedSaWithTenantTwoIncluded) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.tenantTwo().allRoles()) ) @@ -890,7 +897,8 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityE MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa1,sa2))) + .queryParam("assetIds", encodedSa1) + .queryParam("assetIds", encodedSa2) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.tenantTwo().allRoles()) ) @@ -930,12 +938,22 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityA SpecificAssetId sa4 = TestUtil.createSpecificAssetId(keyPrefix + "tenantTwo_tenantThree","value_3",null); SpecificAssetId sa5 = TestUtil.createSpecificAssetId(keyPrefix + "tenantTwo","value_2",null); + String encodedSa1 = Base64.getUrlEncoder().encodeToString(serialize( sa1)); + String encodedSa2 = Base64.getUrlEncoder().encodeToString(serialize( sa2)); + String encodedSa3 = Base64.getUrlEncoder().encodeToString(serialize( sa3)); + String encodedSa4 = Base64.getUrlEncoder().encodeToString(serialize( sa4)); + String encodedSa5 = Base64.getUrlEncoder().encodeToString(serialize( sa5)); + // Make request with bpn of the owner mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa1,sa2,sa3,sa4,sa5))) + .queryParam("assetIds", encodedSa1) + .queryParam("assetIds", encodedSa2) + .queryParam("assetIds", encodedSa3) + .queryParam("assetIds", encodedSa4) + .queryParam("assetIds", encodedSa5) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.allRoles()) ) @@ -951,7 +969,8 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityA MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantTwo().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa2,sa5))) + .queryParam("assetIds", encodedSa2) + .queryParam("assetIds", encodedSa5) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.tenantTwo().allRoles()) ) @@ -968,7 +987,9 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityA MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantTwo().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa2,sa3,sa5))) + .queryParam("assetIds", encodedSa2) + .queryParam("assetIds", encodedSa3) + .queryParam("assetIds", encodedSa5) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.tenantTwo().allRoles()) ) @@ -981,7 +1002,8 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithTenantBasedVisibilityA MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantThree().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa2,sa5))) + .queryParam("assetIds", encodedSa2) + .queryParam("assetIds", encodedSa5) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.tenantTwo().allRoles()) ) @@ -1009,11 +1031,15 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithDefaultClosedTenantBas SpecificAssetId sa1 = TestUtil.createSpecificAssetId(keyPrefix + "defaultClosed","value_1",null); SpecificAssetId sa2 = TestUtil.createSpecificAssetId(keyPrefix + "public_visible","value_2",null); + String encodedSa1 = Base64.getUrlEncoder().encodeToString(serialize( sa1)); + String encodedSa2 = Base64.getUrlEncoder().encodeToString(serialize( sa2)); + mvc.perform( MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa1,sa2))) + .queryParam("assetIds", encodedSa1) + .queryParam("assetIds", encodedSa2) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.allRoles()) ) @@ -1027,7 +1053,8 @@ public void testFindExternalShellIdsBySpecificAssetIdsWithDefaultClosedTenantBas MockMvcRequestBuilders .get(LOOKUP_SHELL_BASE_PATH) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantTwo().getTenantId() ) - .queryParam("assetIds", mapper.writeValueAsString(List.of(sa1,sa2))) + .queryParam("assetIds", encodedSa1) + .queryParam("assetIds", encodedSa2) .accept(MediaType.APPLICATION_JSON) .with(jwtTokenFactory.tenantTwo().allRoles()) ) @@ -1243,4 +1270,55 @@ public void testGetAllShellByExternalIdWithPublicAccessByTenantId() throws Excep .andExpect(jsonPath("$.specificAssetIds[*]").exists()); } } + @Nested + @DisplayName( "Description Authentication Tests" ) + class DescriptionApiTest { + + @Test + public void testGetDescriptionOnlyDeleteRoleExpectForbidden() throws Exception { + mvc.perform( + MockMvcRequestBuilders + .get( "/api/v3.0/description" ) + .accept( MediaType.APPLICATION_JSON ) + .with( jwtTokenFactory.deleteTwin() ) + ) + .andDo( MockMvcResultHandlers.print() ) + .andExpect(status().isForbidden()); + } + + @Test + public void testGetDescriptionNoRoleExpectForbidden() throws Exception { + mvc.perform( + MockMvcRequestBuilders + .get( "/api/v3.0/description" ) + .accept( MediaType.APPLICATION_JSON ) + .with( jwtTokenFactory.withoutRoles() ) + ) + .andDo( MockMvcResultHandlers.print() ) + .andExpect(status().isForbidden()); + } + + @Test + public void testGetDescriptionReadRoleExpectSuccess() throws Exception { + mvc.perform( + MockMvcRequestBuilders + .get( "/api/v3.0/description" ) + .accept( MediaType.APPLICATION_JSON ) + .with( jwtTokenFactory.readTwin() ) + ) + .andDo( MockMvcResultHandlers.print() ) + .andExpect(status().isOk()); + } + + @Test + public void testGetDescriptionReadRoleExpectUnauthorized() throws Exception { + mvc.perform( + MockMvcRequestBuilders + .get( "/api/v3.0/description" ) + .accept( MediaType.APPLICATION_JSON ) + ) + .andDo( MockMvcResultHandlers.print() ) + .andExpect(status().isUnauthorized()); + } + } } diff --git a/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiTest.java b/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiTest.java index 23311341..115cb596 100644 --- a/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiTest.java +++ b/backend/src/test/java/org/eclipse/tractusx/semantics/registry/AssetAdministrationShellApiTest.java @@ -19,10 +19,11 @@ ********************************************************************************/ package org.eclipse.tractusx.semantics.registry; -import static org.eclipse.tractusx.semantics.registry.TestUtil.getEncodedValue; +import static org.eclipse.tractusx.semantics.registry.TestUtil.*; import static org.hamcrest.Matchers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.util.Base64; import java.util.List; import java.util.UUID; @@ -678,7 +679,7 @@ public void testLookUpApiWithInvalidQueryParameterExpectFailure() throws Excepti ) .andDo( MockMvcResultHandlers.print() ) .andExpect( status().isBadRequest() ) - .andExpect( jsonPath( "$.messages[0].text", is( "The provided parameters are invalid. assetIds={ invalid }" ) ) ); + .andExpect( jsonPath( "$.messages[0].text", is( "Incorrect Base64 encoded value provided as parameter" ) ) ); } @Test @@ -725,11 +726,12 @@ public void testFindExternalShellIdsBySpecificAssetIdsExpectSuccess() throws Exc performShellCreateRequest( mapper.writeValueAsString( shellPayload2 ) ); SpecificAssetId specificAssetId1 = TestUtil.createSpecificAssetId(); + String encodedSa1 = Base64.getUrlEncoder().encodeToString(serialize( specificAssetId1)); mvc.perform( MockMvcRequestBuilders .get( LOOKUP_SHELL_BASE_PATH ) - .queryParam( "assetIds", mapper.writeValueAsString( specificAssetId1 ) ) + .queryParam( "assetIds", encodedSa1 ) .queryParam( "limit", "1" ) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) .accept( MediaType.APPLICATION_JSON ) @@ -742,10 +744,11 @@ public void testFindExternalShellIdsBySpecificAssetIdsExpectSuccess() throws Exc // Test first shell match with single assetId SpecificAssetId specificAssetId2 = TestUtil.createSpecificAssetId( "identifier99KeyExample", "identifier99ValueExample", null ); + String encodedSa2 = Base64.getUrlEncoder().encodeToString(serialize( specificAssetId2)); mvc.perform( MockMvcRequestBuilders .get( LOOKUP_SHELL_BASE_PATH ) - .queryParam( "assetIds", mapper.writeValueAsString( specificAssetId2 ) ) + .queryParam( "assetIds", encodedSa2) .queryParam( "limit", "10" ) .accept( MediaType.APPLICATION_JSON ) .with( jwtTokenFactory.allRoles() ) @@ -757,11 +760,11 @@ public void testFindExternalShellIdsBySpecificAssetIdsExpectSuccess() throws Exc // // Test first and second shell match with common asssetId SpecificAssetId specificAssetId3 = TestUtil.createSpecificAssetId( "commonAssetIdKey", "commonAssetIdValue", null ); - + String encodedSa3 = Base64.getUrlEncoder().encodeToString(serialize( specificAssetId3)); mvc.perform( MockMvcRequestBuilders .get( LOOKUP_SHELL_BASE_PATH ) - .queryParam( "assetIds", mapper.writeValueAsString( specificAssetId3 ) ) + .queryParam( "assetIds", encodedSa3 ) .accept( MediaType.APPLICATION_JSON ) .with( jwtTokenFactory.allRoles() ) ) @@ -782,14 +785,15 @@ public void testFindExternalShellIdByGlobalAssetIdExpectSuccess() throws Excepti performShellCreateRequest(payload ); // for lookup global asset id is handled as specificAssetIds - ArrayNode globalAssetIdForSampleQuery = emptyArrayNode().add( - specificAssetId( "globalAssetId", globalAssetId ) - ); + SpecificAssetId SAGlobal = TestUtil.createSpecificAssetId("globalAssetId",globalAssetId,null); + String encodedSa1 = Base64.getUrlEncoder().encodeToString(serialize( SAGlobal)); + + mvc.perform( MockMvcRequestBuilders .get( LOOKUP_SHELL_BASE_PATH ) .header( EXTERNAL_SUBJECT_ID_HEADER, jwtTokenFactory.tenantOne().getTenantId() ) - .queryParam( "assetIds", toJson( globalAssetIdForSampleQuery ) ) + .queryParam( "assetIds", encodedSa1) .accept( MediaType.APPLICATION_JSON ) .with( jwtTokenFactory.allRoles() ) ) @@ -1147,4 +1151,22 @@ public void test_Creates_a_new_Submodel_Descriptor_with_duplicate_IdShort_in_sub .andExpect( jsonPath( "$.messages[0].text", is( ShellService.DUPLICATE_SUBMODEL_ID_SHORT_EXCEPTION ) ) ); } + + @Nested + @DisplayName( "Description Tests" ) + class DescriptionApiTest { + @Test + public void testGetDescriptionExpectSuccess() throws Exception { + mvc.perform( + MockMvcRequestBuilders + .get( "/api/v3.0/description" ) + .accept( MediaType.APPLICATION_JSON ) + .with( jwtTokenFactory.allRoles() ) + ) + .andDo( MockMvcResultHandlers.print() ) + .andExpect( status().isOk() ) + .andExpect( jsonPath( "$.profiles[0]", is( "https://admin-shell.io/aas/API/3/0/AssetAdministrationShellRegistryServiceSpecification/SSP-001" ) ) ); + } + } + } \ No newline at end of file diff --git a/backend/src/test/java/org/eclipse/tractusx/semantics/registry/TestUtil.java b/backend/src/test/java/org/eclipse/tractusx/semantics/registry/TestUtil.java index 8045b1a2..65caf284 100644 --- a/backend/src/test/java/org/eclipse/tractusx/semantics/registry/TestUtil.java +++ b/backend/src/test/java/org/eclipse/tractusx/semantics/registry/TestUtil.java @@ -22,12 +22,17 @@ import org.apache.commons.lang3.RandomStringUtils; import org.eclipse.tractusx.semantics.aas.registry.model.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + public class TestUtil { public static AssetAdministrationShellDescriptor createCompleteAasDescriptor() { @@ -246,4 +251,13 @@ public static SpecificAssetId createSpecificAssetId(String name, String value, L public static String getEncodedValue(String shellId){ return Base64.getUrlEncoder().encodeToString(shellId.getBytes()); } + + public static byte[] serialize(Object obj) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ObjectMapper mapper = new ObjectMapper(); + mapper.enable( SerializationFeature.INDENT_OUTPUT); + mapper.setSerializationInclusion( JsonInclude.Include.NON_NULL); + mapper.writeValue(os, obj); + return os.toByteArray(); + } } \ No newline at end of file