diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dao/entity/WalletKey.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dao/entity/WalletKey.java index dd6b59019..3fcbbb7de 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dao/entity/WalletKey.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dao/entity/WalletKey.java @@ -21,6 +21,7 @@ package org.eclipse.tractusx.managedidentitywallets.dao.entity; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -69,6 +70,7 @@ public class WalletKey extends MIWBaseEntity { @ManyToOne @MapsId @JoinColumn(name = "walletId", columnDefinition = "bigint") + @JsonBackReference private Wallet wallet; private String keyId; diff --git a/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestConfig.java b/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestConfig.java new file mode 100644 index 000000000..a41c0ddee --- /dev/null +++ b/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestConfig.java @@ -0,0 +1,36 @@ +/* + * ******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ****************************************************************************** + */ + +package org.eclipse.tractusx.managedidentitywallets.config; + +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("test") +public class TestConfig { + @Bean + public TestRestTemplate testRestTemplate() { + return new TestRestTemplate(); + } +} diff --git a/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java b/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java new file mode 100644 index 000000000..14f3df1df --- /dev/null +++ b/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java @@ -0,0 +1,93 @@ +/* + * ******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ****************************************************************************** + */ + +package org.eclipse.tractusx.managedidentitywallets.controller; + +import org.eclipse.tractusx.managedidentitywallets.ManagedIdentityWalletsApplication; +import org.eclipse.tractusx.managedidentitywallets.config.MIWSettings; +import org.eclipse.tractusx.managedidentitywallets.config.TestContextInitializer; +import org.eclipse.tractusx.managedidentitywallets.utils.AuthenticationUtils; +import org.eclipse.tractusx.managedidentitywallets.utils.TestUtils; +import org.eclipse.tractusx.ssi.lib.did.web.DidWebFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; + +import java.util.List; +import java.util.Map; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, classes = { ManagedIdentityWalletsApplication.class }) +@ContextConfiguration(initializers = { TestContextInitializer.class }) +class SecureTokenControllerTest { + + @Autowired + private MIWSettings miwSettings; + + @Autowired + private TestRestTemplate testTemplate; + + @Test + void token() { + // given + String bpn = TestUtils.getRandomBpmNumber(); + String partnerBpn = TestUtils.getRandomBpmNumber(); + String clientId = "main"; + String clientSecret = "main"; + AuthenticationUtils.setupKeycloakClient(clientId, clientSecret, bpn); + AuthenticationUtils.setupKeycloakClient("partner", "partner", partnerBpn); + String did = DidWebFactory.fromHostnameAndPath(miwSettings.host(), bpn).toString(); + String didPartner = DidWebFactory.fromHostnameAndPath(miwSettings.host(), partnerBpn).toString(); + TestUtils.createWallet(bpn, did, testTemplate, miwSettings.authorityWalletBpn()); + TestUtils.createWallet(partnerBpn, didPartner, testTemplate, miwSettings.authorityWalletBpn()); + + // when + // String requestBody = "{\"audience\": \"" + bpn + "\", \"client_id\": \"" + clientId + "\", \"client_secret\": \"" + clientSecret + "\", \"grant_type\": \"client_credentials\", \"bearer_access_scope\": \"org.eclipse.tractusx.vc.type:BpnCredential:read\"}"; + + String body = """ + { + "audience": "%s", + "client_id": "%s", + "client_secret": "%s", + "grant_type": "client_credentials", + "bearer_access_scope": "org.eclipse.tractusx.vc.type:BpnCredential:read" + } + """; + String requestBody = String.format(body, bpn, clientId, clientSecret); + // then + HttpHeaders headers = new HttpHeaders(); + headers.put(HttpHeaders.CONTENT_TYPE, List.of(MediaType.APPLICATION_JSON_VALUE)); + HttpEntity entity = new HttpEntity<>(requestBody, headers); + ResponseEntity response = testTemplate.exchange("/token", HttpMethod.POST, entity, Map.class); + Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED); + Assertions.assertEquals(response.getHeaders().getContentType().toString(), MediaType.APPLICATION_JSON_VALUE); + Assertions.assertNotNull(response.getBody().getOrDefault("token", null)); + Assertions.assertNotNull(response.getBody().getOrDefault("expiresAt", null)); + } +} diff --git a/src/test/java/org/eclipse/tractusx/managedidentitywallets/utils/AuthenticationUtils.java b/src/test/java/org/eclipse/tractusx/managedidentitywallets/utils/AuthenticationUtils.java index dd99e720d..1f4be3d36 100644 --- a/src/test/java/org/eclipse/tractusx/managedidentitywallets/utils/AuthenticationUtils.java +++ b/src/test/java/org/eclipse/tractusx/managedidentitywallets/utils/AuthenticationUtils.java @@ -28,9 +28,12 @@ import org.keycloak.admin.client.KeycloakBuilder; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.springframework.http.HttpHeaders; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; @@ -107,6 +110,45 @@ private static String getJwtToken(String username, String bpn) { return getJwtToken(username); } + public static void setupKeycloakClient(String clientId, String clientSecret, String bpn) { + Keycloak keycloakAdmin = KeycloakBuilder.builder() + .serverUrl(TestContextInitializer.getAuthServerUrl()) + .realm("master") // Use the master realm for admin operations + .clientId("admin-cli") + .username("admin") + .password("admin") + .build(); + + Map attributes = new HashMap<>(); + attributes.put("BPN", bpn); + + ClientRepresentation clientRepresentation = new ClientRepresentation(); + clientRepresentation.setEnabled(true); + clientRepresentation.setServiceAccountsEnabled(true); + clientRepresentation.setClientId(clientId); + clientRepresentation.setSecret(clientSecret); + clientRepresentation.setConsentRequired(false); + clientRepresentation.setAttributes(attributes); + + ProtocolMapperRepresentation propertyMapper = new ProtocolMapperRepresentation(); + propertyMapper.setName("BPN mapper"); + propertyMapper.setProtocol("openid-connect"); + propertyMapper.setProtocolMapper("oidc-hardcoded-claim-mapper"); + propertyMapper.setConfig(Map.of( + "claim.name", "BPN", + "user.attribute", "BPN", + "claim.value", bpn, + "id.token.claim", "true", + "access.token.claim", "true", + "jsonType.label", "String", + "userinfo.token.claim", "true" + )); + + // Set the updated list of protocol mappers back to the client representation + clientRepresentation.setProtocolMappers(List.of(propertyMapper)); + keycloakAdmin.realm(StringPool.REALM).clients().create(clientRepresentation); + } + private static String getJwtToken(String username) { Keycloak keycloakAdminClient = KeycloakBuilder.builder()