Skip to content

Commit

Permalink
Implements Authorized Registry Integration in AAS/SM Repo (eclipse-ba…
Browse files Browse the repository at this point in the history
…syx#330)

* Implements Authorized Registry Integration in AAS/SM Repo

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Minor refactoring

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

* Fixes CI issue

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>

---------

Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>
  • Loading branch information
mdanish98 authored Jul 10, 2024
1 parent 4dd6827 commit 061b267
Show file tree
Hide file tree
Showing 25 changed files with 836 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,18 @@ An example valid configuration:
basyx.aasrepository.feature.registryintegration = http://localhost:8050
basyx.externalurl = http://localhost:8081
```

## AAS Repository Integration with Authorized AAS Registry

If the target AAS Registry has authorization enabled, then the following properties needs to be configured in order to successfully integrate the Descriptor:

```
basyx.aasrepository.feature.registryintegration.authorization.enabled=true
basyx.aasrepository.feature.registryintegration.authorization.token-endpoint=http://localhost:9096/realms/BaSyx/protocol/openid-connect/token
basyx.aasrepository.feature.registryintegration.authorization.grant-type = <CLIENT_CREDENTIALS> or <PASSWORD>
basyx.aasrepository.feature.registryintegration.authorization.client-id = <client-id>
basyx.aasrepository.feature.registryintegration.authorization.client-secret = <client-secret>
basyx.aasrepository.feature.registryintegration.authorization.username=test
basyx.aasrepository.feature.registryintegration.authorization.password=test
basyx.aasrepository.feature.registryintegration.authorization.scopes=[]
```
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.filerepository-backend-inmemory</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasrepository-http</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasservice-backend-inmemory</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasrepository-backend-inmemory</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@
* SPDX-License-Identifier: MIT
******************************************************************************/


package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;

import java.util.Collection;

import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
import org.eclipse.digitaltwin.basyx.aasregistry.main.client.AuthorizedConnectedAasRegistry;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
import org.eclipse.digitaltwin.basyx.client.internal.authorization.AccessTokenProviderFactory;
import org.eclipse.digitaltwin.basyx.client.internal.authorization.TokenManager;
import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.AccessTokenProvider;
import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.GrantType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand All @@ -46,18 +52,62 @@
@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.aasrepository.feature.registryintegration:}') && !T(org.springframework.util.StringUtils).isEmpty('${basyx.externalurl:}')")
public class RegistryIntegrationAasRepositoryConfiguration {

@Value("${basyx.aasrepository.feature.registryintegration:#{null}}")
private String registryBasePath;

@Value("${basyx.externalurl:#{null}}")
private String aasRepositoryBaseURL;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.enabled:false}")
private boolean isAuthorizationEnabledOnRegistry;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.token-endpoint:#{null}}")
private String authenticationServerTokenEndpoint;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.grant-type:#{null}}")
private String grantType;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.client-id:#{null}}")
private String clientId;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.client-secret:#{null}}")
private String clientSecret;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.username:#{null}}")
private String username;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.password:#{null}}")
private String password;

@Value("${basyx.aasrepository.feature.registryintegration.authorization.scopes:#{null}}")
private Collection<String> scopes;

@Bean
@ConditionalOnMissingBean
public AasRepositoryRegistryLink getAasRepositoryRegistryLink(@Value("${basyx.aasrepository.feature.registryintegration}") String registryBasePath, @Value("${basyx.externalurl}") String aasRepositoryBaseURL) {

return new AasRepositoryRegistryLink(new RegistryAndDiscoveryInterfaceApi(registryBasePath), aasRepositoryBaseURL);
public AasRepositoryRegistryLink getAasRepositoryRegistryLink() {

if (!isAuthorizationEnabledOnRegistry)
return new AasRepositoryRegistryLink(new RegistryAndDiscoveryInterfaceApi(registryBasePath), aasRepositoryBaseURL);

TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, createAccessTokenProvider());

return new AasRepositoryRegistryLink(new AuthorizedConnectedAasRegistry(registryBasePath, tokenManager), aasRepositoryBaseURL);
}

@Bean
@ConditionalOnMissingBean
public AttributeMapper getAasAttributeMapper(ObjectMapper objectMapper) {

return new AttributeMapper(objectMapper);
}

private AccessTokenProvider createAccessTokenProvider() {

AccessTokenProviderFactory factory = new AccessTokenProviderFactory(GrantType.valueOf(grantType), scopes);
factory.setClientCredentials(clientId, clientSecret);
factory.setPasswordCredentials(username, password);

return factory.create();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,56 @@
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;

import org.junit.internal.TextListener;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
* Application for testing the {@link RegistryIntegrationAasRepository} feature.
* The first argument is the AAS Repository Base URL, the second argument is the AAS
* Registry URL.
* Integration test for {@link RegistryIntegrationAasRepository} feature
*
* @author schnicke, danish
*
* @author danish
*/
public class AasRepositoryRegistryTestLinkApplication {

public static void main(String[] args) throws Exception {
String aasRepoBaseUrl = getAasRepositoryBaseUrl(args);
String aasRegUrl = getAasRegistryUrl(args);

Result result = runTests(aasRepoBaseUrl, aasRegUrl);
public class AasRepositoryRegistryLinkTest extends AasRepositoryRegistryLinkTestSuite {

printResults(result);
private static final String AAS_REPO_URL = "http://localhost:8081";
private static final String AAS_REGISTRY_BASE_URL = "http://localhost:8050";
private static ConfigurableApplicationContext appContext;
private static AasRepositoryRegistryLink aasRepositoryRegistryLink;

@BeforeClass
public static void setUp() throws FileNotFoundException, IOException {
appContext = new SpringApplication(DummyAasRepositoryIntegrationComponent.class).run(new String[] {});

aasRepositoryRegistryLink = appContext.getBean(AasRepositoryRegistryLink.class);
}

private static void printResults(Result result) {
System.out.println("Finished. Result: Failures: " + result.getFailureCount() + ". Ignored: " + result.getIgnoreCount() + ". Tests run: " + result.getRunCount() + ". Time: " + result.getRunTime() + "ms.");

@AfterClass
public static void tearDown() {
appContext.close();
}

private static Result runTests(String aasRepoBaseUrl, String aasRegUrl) {
AasRepositoryRegistryTestLink.aasRepoBaseUrl = aasRepoBaseUrl;
AasRepositoryRegistryTestLink.aasRegistryUrl = aasRegUrl;

JUnitCore junit = new JUnitCore();
junit.addListener(new TextListener(System.out));

return junit.run(AasRepositoryRegistryTestLink.class);
@Override
protected String getAasRepoBaseUrl() {
return AAS_REPO_URL;
}

private static String getAasRepositoryBaseUrl(String[] args) {
return args[0];
@Override
protected String getAasRegistryUrl() {
return AAS_REGISTRY_BASE_URL;
}

private static String getAasRegistryUrl(String[] args) {
return args[1];
@Override
protected RegistryAndDiscoveryInterfaceApi getAasRegistryApi() {

return aasRepositoryRegistryLink.getRegistryApi();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,22 @@
import org.springframework.http.HttpStatus;

/**
* Integration test for {@link RegistryIntegrationAasRepository} feature
* Test suite for {@link RegistryIntegrationAasRepository} feature
*
* @author danish
*/
public class AasRepositoryRegistryTestLink {
public abstract class AasRepositoryRegistryLinkTestSuite {

private static final String AAS_REPOSITORY_PATH = "/shells";
private static final String DUMMY_GLOBAL_ASSETID = "globalAssetId";
private static final String DUMMY_IDSHORT = "ExampleMotor";
private static final String DUMMY_AAS_ID = "customIdentifier";

public static String aasRepoBaseUrl = "http://localhost:8081";
public static String aasRegistryUrl = "http://localhost:8050";
protected abstract String getAasRepoBaseUrl();
protected abstract String getAasRegistryUrl();
protected abstract RegistryAndDiscoveryInterfaceApi getAasRegistryApi();

private static final AssetAdministrationShellDescriptor DUMMY_DESCRIPTOR = DummyAasDescriptorFactory.createDummyDescriptor(DUMMY_AAS_ID, DUMMY_IDSHORT, DUMMY_GLOBAL_ASSETID, aasRepoBaseUrl);
private final AssetAdministrationShellDescriptor DUMMY_DESCRIPTOR = DummyAasDescriptorFactory.createDummyDescriptor(DUMMY_AAS_ID, DUMMY_IDSHORT, DUMMY_GLOBAL_ASSETID, getAasRepoBaseUrl());

@Test
public void createAas() throws FileNotFoundException, IOException, ApiException {
Expand Down Expand Up @@ -89,7 +90,7 @@ public void deleteAas() throws FileNotFoundException, IOException, ApiException
}

private AssetAdministrationShellDescriptor retrieveDescriptorFromRegistry() throws ApiException {
RegistryAndDiscoveryInterfaceApi api = new RegistryAndDiscoveryInterfaceApi(aasRegistryUrl);
RegistryAndDiscoveryInterfaceApi api = getAasRegistryApi();

return api.getAssetAdministrationShellDescriptorById(DUMMY_AAS_ID);
}
Expand All @@ -105,7 +106,7 @@ private CloseableHttpResponse deleteAasFromRepo(String shellId) throws IOExcepti
}

private void assertDescriptionDeletionAtRegistry() throws ApiException {
RegistryAndDiscoveryInterfaceApi api = new RegistryAndDiscoveryInterfaceApi(aasRegistryUrl);
RegistryAndDiscoveryInterfaceApi api = getAasRegistryApi();

GetAssetAdministrationShellDescriptorsResult result = api.getAllAssetAdministrationShellDescriptors(null, null, null, null);

Expand All @@ -119,11 +120,11 @@ private String getAas1JSONString() throws FileNotFoundException, IOException {
}

private CloseableHttpResponse createAasOnRepo(String aasJsonContent) throws IOException {
return BaSyxHttpTestUtils.executePostOnURL(createAasRepositoryUrl(aasRepoBaseUrl), aasJsonContent);
return BaSyxHttpTestUtils.executePostOnURL(createAasRepositoryUrl(getAasRepoBaseUrl()), aasJsonContent);
}

private String getSpecificAasAccessURL(String aasId) {
return createAasRepositoryUrl(aasRepoBaseUrl) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(aasId);
return createAasRepositoryUrl(getAasRepoBaseUrl()) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(aasId);
}

private static String createAasRepositoryUrl(String aasRepositoryBaseURL) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;

import java.io.FileNotFoundException;
import java.io.IOException;
import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
* Integration test for Authorized Registry
*
* @author danish
*/
public class AuthorizedAasRepositoryRegistryLinkTest extends AasRepositoryRegistryLinkTestSuite {

private static final String AAS_REPO_URL = "http://localhost:8081";
private static final String AAS_REGISTRY_BASE_URL = "http://localhost:8051";
private static ConfigurableApplicationContext appContext;
private static AasRepositoryRegistryLink aasRepositoryRegistryLink;

@BeforeClass
public static void setUp() throws FileNotFoundException, IOException {
SpringApplication application = new SpringApplication(DummyAasRepositoryIntegrationComponent.class);
application.setAdditionalProfiles("authregistry");

appContext = application.run(new String[] {});

aasRepositoryRegistryLink = appContext.getBean(AasRepositoryRegistryLink.class);
}

@AfterClass
public static void tearDown() {
appContext.close();
}

@Override
protected String getAasRepoBaseUrl() {
return AAS_REPO_URL;
}

@Override
protected String getAasRegistryUrl() {
return AAS_REGISTRY_BASE_URL;
}

@Override
protected RegistryAndDiscoveryInterfaceApi getAasRegistryApi() {

return aasRepositoryRegistryLink.getRegistryApi();
}

}
Loading

0 comments on commit 061b267

Please sign in to comment.