diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml b/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml
index 4f3e5f019..f0ceddf4f 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml
+++ b/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml
@@ -92,6 +92,10 @@
basyx.aasenvironment-feature-authorization
test
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasenvironment-feature-authorization
+
org.apache.httpcomponents.client5
httpclient5
diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/DummyAasEnvironmentConfiguration.java b/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/DummyAasEnvironmentConfiguration.java
index b8bdf7e4a..0a7a07f43 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/DummyAasEnvironmentConfiguration.java
+++ b/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/DummyAasEnvironmentConfiguration.java
@@ -31,9 +31,11 @@
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironmentFactory;
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.AasEnvironmentFeature;
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.DecoratedAasEnvironmentFactory;
+import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ResourceLoader;
/**
* Dummy configuration for testing the {@link AasEnvironment} authorization
@@ -51,4 +53,10 @@ public static AasEnvironment getAasEnvironment(AasEnvironmentFactory aasEnvironm
return new DecoratedAasEnvironmentFactory(aasEnvironmentFactory, features).create();
}
+ @Bean
+ @ConditionalOnMissingBean
+ public static AasEnvironmentPreconfigurationLoader getPreconfigurationLoaderForAasEnvironment(ResourceLoader resourceLoader, List pathsToLoad) {
+ return new AasEnvironmentPreconfigurationLoader(resourceLoader, pathsToLoad);
+ }
+
}
diff --git a/basyx.aasenvironment/basyx.aasenvironment-core/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/preconfiguration/AasEnvironmentPreconfigurationLoader.java b/basyx.aasenvironment/basyx.aasenvironment-core/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/preconfiguration/AasEnvironmentPreconfigurationLoader.java
index 559612d0d..0a19055c2 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-core/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/preconfiguration/AasEnvironmentPreconfigurationLoader.java
+++ b/basyx.aasenvironment/basyx.aasenvironment-core/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/preconfiguration/AasEnvironmentPreconfigurationLoader.java
@@ -26,8 +26,13 @@
package org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
+
import java.util.List;
import java.util.stream.Collectors;
@@ -36,10 +41,13 @@
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment.EnvironmentType;
+import org.eclipse.digitaltwin.basyx.authorization.CommonAuthorizationProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ResourceLoader;
import org.springframework.integration.file.RecursiveDirectoryScanner;
import org.springframework.stereotype.Component;
@@ -50,17 +58,15 @@
* @author fried, mateusmolina, despen, witt, jungjan, danish
*
*/
-@Component
public class AasEnvironmentPreconfigurationLoader {
-
+
private Logger logger = LoggerFactory.getLogger(AasEnvironmentPreconfigurationLoader.class);
@Value("${basyx.environment:#{null}}")
private List pathsToLoad;
private ResourceLoader resourceLoader;
-
- @Autowired
+
public AasEnvironmentPreconfigurationLoader(ResourceLoader resourceLoader, List pathsToLoad) {
this.resourceLoader = resourceLoader;
this.pathsToLoad = pathsToLoad;
@@ -134,4 +140,5 @@ private void logLoadingProcess(int current, int overall, String filename) {
logger.info("Loading AAS Environment ({}/{}) from file '{}'", current, overall, filename);
}
+
}
\ No newline at end of file
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/Readme.md b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/Readme.md
index 760078f1d..4ebbbfabf 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/Readme.md
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/Readme.md
@@ -11,6 +11,17 @@ basyx.feature.authorization.rbac.file =
```
+If you want to use a preconfigured environment with authorization, you need to set the following options as well:
+```
+basyx.aasenvironment.authorization.preconfiguration.token-endpoint =
+basyx.aasenvironment.authorization.preconfiguration.grant-type =
+basyx.aasenvironment.authorization.preconfiguration.client-id =
+basyx.aasenvironment.authorization.preconfiguration.client-secret=
+basyx.aasenvironment.authorization.preconfiguration.username =
+basyx.aasenvironment.authorization.preconfiguration.password =
+basyx.aasenvironment.authorization.preconfiguration.scopes =
+```
+
Note: Only Role Based Access Control (RBAC) is supported as authorization type as of now, also Keycloak is the only Jwt token provider supported now and it is also a default provider.
To know more about the RBAC, please refer [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/index.html)
@@ -26,6 +37,15 @@ basyx.feature.authorization.rbac.file = classpath:rbac_rules.json
spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9096/realms/BaSyx
```
+And for preconfiguration (Grant Type would be CLIENT_CREDENTIALS in this case):
+
+```
+basyx.aasenvironment.authorization.preconfiguration.token-endpoint = http://localhost:9096/realms/BaSyx/protocol/openid-connect/token
+basyx.aasenvironment.authorization.preconfiguration.grant-type = CLIENT_CREDENTIALS
+basyx.aasenvironment.authorization.preconfiguration.client-id = workstation-1
+basyx.aasenvironment.authorization.preconfiguration.client-secret = nY0mjyECF60DGzNmQUjL81XurSl8etom
+```
+
## RBAC rule configuration
For configuring RBAC rules, all the rbac rules should be configured inside a json file, the rules are defined as below:
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/pom.xml b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/pom.xml
index 9da9bb635..714cac31f 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/pom.xml
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/pom.xml
@@ -35,6 +35,10 @@
org.eclipse.digitaltwin.basyx
basyx.http
+
+ org.eclipse.digitaltwin.basyx
+ basyx.client
+
org.eclipse.digitaltwin.basyx
basyx.authorization
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAASEnvironmentPreconfigurationLoader.java b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAASEnvironmentPreconfigurationLoader.java
new file mode 100644
index 000000000..32ea360d3
--- /dev/null
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAASEnvironmentPreconfigurationLoader.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.aasenvironment.feature.authorization;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException;
+import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
+import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader;
+import org.eclipse.digitaltwin.basyx.authorization.jwt.JwtTokenDecoder;
+import org.eclipse.digitaltwin.basyx.authorization.jwt.PublicKeyUtils;
+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.core.io.ClassPathResource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collection;
+import java.util.List;
+
+public class AuthorizedAASEnvironmentPreconfigurationLoader extends AasEnvironmentPreconfigurationLoader {
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.token-endpoint:#{null}}")
+ private String authenticationServerTokenEndpoint;
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.client-id:#{null}}")
+ private String clientId;
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.client-secret:#{null}}")
+ private String clientSecret;
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.username:#{null}}")
+ private String username;
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.password:#{null}}")
+ private String password;
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.grant-type:#{null}}")
+ private String grantType;
+
+ @Value("${basyx.aasenvironment.authorization.preconfiguration.scopes:#{null}}")
+ private Collection scopes;
+
+ @Value("${basyx.environment:#{null}}")
+ private String basyxEnvironment;
+
+ private AccessTokenProvider tokenProvider;
+
+ public AuthorizedAASEnvironmentPreconfigurationLoader(ResourceLoader resourceLoader, List pathsToLoad) {
+ super(resourceLoader, pathsToLoad);
+ }
+
+ @Override
+ public void loadPreconfiguredEnvironments(AasEnvironment aasEnvironment) throws IOException, InvalidFormatException, DeserializationException {
+ if(isEnvironmentSet()) {
+ setUpTokenProvider();
+ configureSecurityContext();
+ }
+ super.loadPreconfiguredEnvironments(aasEnvironment);
+ SecurityContextHolder.clearContext();
+ }
+
+
+ private void setUpTokenProvider() {
+ AccessTokenProviderFactory factory = new AccessTokenProviderFactory(GrantType.valueOf(grantType),scopes);
+ factory.setClientCredentials(clientId, clientSecret);
+ factory.setPasswordCredentials(username, password);
+ this.tokenProvider = factory.create();
+ }
+
+ private void configureSecurityContext() throws FileNotFoundException, IOException {
+ TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, tokenProvider);
+ String adminToken = tokenManager.getAccessToken();
+
+ String modulus = getStringFromFile("authorization/modulus.txt");
+ String exponent = "AQAB";
+
+ RSAPublicKey rsaPublicKey = PublicKeyUtils.buildPublicKey(modulus, exponent);
+
+ Jwt jwt = JwtTokenDecoder.decodeJwt(adminToken, rsaPublicKey);
+
+ SecurityContextHolder.getContext().setAuthentication(new JwtAuthenticationToken(jwt));
+ }
+
+
+ private String getStringFromFile(String fileName) throws FileNotFoundException, IOException {
+ ClassPathResource classPathResource = new ClassPathResource(fileName);
+ InputStream in = classPathResource.getInputStream();
+ return IOUtils.toString(in, StandardCharsets.UTF_8.name());
+ }
+
+ private boolean isEnvironmentSet() {
+ return basyxEnvironment != null;
+ }
+}
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAasEnvironmentConfiguration.java b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAasEnvironmentConfiguration.java
index d59defa8c..79475434a 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAasEnvironmentConfiguration.java
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAasEnvironmentConfiguration.java
@@ -27,6 +27,7 @@
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization.rbac.AasEnvironmentTargetPermissionVerifier;
+import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader;
import org.eclipse.digitaltwin.basyx.authorization.CommonAuthorizationProperties;
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacPermissionResolver;
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacStorage;
@@ -36,6 +37,10 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.io.ResourceLoader;
+
+import java.util.List;
/**
* Configuration for authorized {@link AasEnvironment}
@@ -57,4 +62,10 @@ public RbacPermissionResolver getAasEnvironment
return new SimpleRbacPermissionResolver<>(rbacStorage, roleProvider, targetPermissionVerifier);
}
+ @Bean
+ @Primary
+ public static AasEnvironmentPreconfigurationLoader getAuthorizedAasEnvironmentPreconfigurationLoader(ResourceLoader resourceLoader, List pathsToLoad) {
+ return new AuthorizedAASEnvironmentPreconfigurationLoader(resourceLoader, pathsToLoad);
+ }
+
}
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java
index 8ca6519c1..8f056bd58 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java
@@ -97,17 +97,6 @@ public static void tearDown() {
appContext.close();
}
- @Before
- public void initializeRepositories() throws FileNotFoundException, IOException {
- configureSecurityContext();
-
- createDummyShellsOnRepository(TestAASEnvironmentSerialization.createDummyShells(), aasRepo);
- createDummySubmodelsOnRepository(TestAASEnvironmentSerialization.createDummySubmodels(), submodelRepo);
- createDummyConceptDescriptionsOnRepository(TestAASEnvironmentSerialization.createDummyConceptDescriptions(), conceptDescriptionRepo);
-
- clearSecurityContext();
- }
-
@After
public void reset() throws FileNotFoundException, IOException {
configureSecurityContext();
@@ -119,7 +108,12 @@ public void reset() throws FileNotFoundException, IOException {
assetAdministrationShells.stream().forEach(aas -> aasRepo.deleteAas(aas.getId()));
submodels.stream().forEach(sm -> submodelRepo.deleteSubmodel(sm.getId()));
conceptDescriptions.stream().forEach(cd -> conceptDescriptionRepo.deleteConceptDescription(cd.getId()));
-
+
+
+ createDummyShellsOnRepository(TestAASEnvironmentSerialization.createDummyShells(), aasRepo);
+ createDummySubmodelsOnRepository(TestAASEnvironmentSerialization.createDummySubmodels(), submodelRepo);
+ createDummyConceptDescriptionsOnRepository(TestAASEnvironmentSerialization.createDummyConceptDescriptions(), conceptDescriptionRepo);
+
clearSecurityContext();
}
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java
index 4069daa3a..785ae35ad 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java
@@ -51,9 +51,7 @@
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.eclipse.digitaltwin.basyx.http.serialization.BaSyxHttpTestUtils;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.*;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpStatus;
@@ -80,8 +78,8 @@ public class TestAuthorizedAasEnvironmentUpload {
private static String healthEndpointUrl = "http://127.0.0.1:8081/actuator/health";
- @Before
- public void setUp() throws FileNotFoundException, IOException {
+ @BeforeClass
+ public static void setUp() throws FileNotFoundException, IOException {
tokenProvider = new AccessTokenProvider(authenticaltionServerTokenEndpoint, clientId);
appContext = new SpringApplication(DummyAasEnvironmentComponent.class).run(new String[] {});
@@ -91,7 +89,7 @@ public void setUp() throws FileNotFoundException, IOException {
conceptDescriptionRepo = appContext.getBean(ConceptDescriptionRepository.class);
}
- @After
+ @Before
public void reset() throws FileNotFoundException, IOException {
configureSecurityContext();
@@ -105,7 +103,10 @@ public void reset() throws FileNotFoundException, IOException {
conceptDescriptions.stream().forEach(cd -> conceptDescriptionRepo.deleteConceptDescription(cd.getId()));
clearSecurityContext();
-
+ }
+
+ @AfterClass
+ public static void shutDown(){
appContext.close();
}
diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/resources/application.properties b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/resources/application.properties
index fd56412cd..c2d23e91a 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/resources/application.properties
+++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/resources/application.properties
@@ -27,7 +27,7 @@ basyx.backend = InMemory
# To load from Classpath (src/main/resources) use classpath:path/to/file.end
# To load from Filesystem ( On your local machine ) use the prefix file:
#
-# basyx.environment = classpath:testEnvironment.json,classpath:testEnvironment.xml,file:C:\\Users\\Administrator\\Documents\\01_Festo.aasx,file:/var/www/html/01_Submodel.json
+basyx.environment = classpath:testEnvironment.aasx
#
####################################################################################
@@ -39,6 +39,10 @@ basyx.feature.authorization.jwtBearerTokenProvider = keycloak
basyx.feature.authorization.rbac.file = classpath:rbac_rules.json
spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9096/realms/BaSyx
+basyx.aasenvironment.authorization.preconfiguration.token-endpoint=http://localhost:9096/realms/BaSyx/protocol/openid-connect/token
+basyx.aasenvironment.authorization.preconfiguration.grant-type = CLIENT_CREDENTIALS
+basyx.aasenvironment.authorization.preconfiguration.client-id=workstation-1
+basyx.aasenvironment.authorization.preconfiguration.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom
####################################################################################
# Operation Delegation
####################################################################################
diff --git a/basyx.aasenvironment/basyx.aasenvironment-http/src/test/java/org/eclipse/basyx/digitaltwin/aasenvironment/http/DummyAASEnvironmentComponent.java b/basyx.aasenvironment/basyx.aasenvironment-http/src/test/java/org/eclipse/basyx/digitaltwin/aasenvironment/http/DummyAASEnvironmentComponent.java
index 2ced71b57..ec50e8040 100644
--- a/basyx.aasenvironment/basyx.aasenvironment-http/src/test/java/org/eclipse/basyx/digitaltwin/aasenvironment/http/DummyAASEnvironmentComponent.java
+++ b/basyx.aasenvironment/basyx.aasenvironment-http/src/test/java/org/eclipse/basyx/digitaltwin/aasenvironment/http/DummyAASEnvironmentComponent.java
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.AssetKind;
@@ -37,6 +38,7 @@
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultConceptDescription;
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.base.DefaultAASEnvironment;
+import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionRepository;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
@@ -44,6 +46,7 @@
import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceHelper;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
+import org.springframework.core.io.ResourceLoader;
@SpringBootApplication(scanBasePackages = "org.eclipse.digitaltwin.basyx")
public class DummyAASEnvironmentComponent {
@@ -59,6 +62,11 @@ public AasEnvironment createAasEnvironmentSerialization(AasRepository aasReposit
return new DefaultAASEnvironment(aasRepository, submodelRepository, conceptDescriptionRepository);
}
+ @Bean
+ public AasEnvironmentPreconfigurationLoader createAasEnvironmentPreconfigurationLoader(ResourceLoader resourceLoader, List pathsToLoad) {
+ return new AasEnvironmentPreconfigurationLoader(resourceLoader, pathsToLoad);
+ }
+
public void initRepositories(AasRepository aasRepository, SubmodelRepository submodelRepository, ConceptDescriptionRepository conceptDescriptionRepository) {
createDummySubmodels().forEach(submodelRepository::createSubmodel);
createDummyShells().forEach(aasRepository::createAas);
diff --git a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/component/AasEnvironmentConfiguration.java b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/component/AasEnvironmentConfiguration.java
index 547adea41..550d87430 100644
--- a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/component/AasEnvironmentConfiguration.java
+++ b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/component/AasEnvironmentConfiguration.java
@@ -31,9 +31,11 @@
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironmentFactory;
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.AasEnvironmentFeature;
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.DecoratedAasEnvironmentFactory;
+import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ResourceLoader;
/**
* Configuration for aas environment for dependency injection
@@ -43,11 +45,17 @@
*/
@Configuration
public class AasEnvironmentConfiguration {
-
+
@Bean
@ConditionalOnMissingBean
public static AasEnvironment getAasEnvironment(AasEnvironmentFactory aasEnvironmentFactory, List features) {
return new DecoratedAasEnvironmentFactory(aasEnvironmentFactory, features).create();
}
+ @Bean
+ @ConditionalOnMissingBean
+ public static AasEnvironmentPreconfigurationLoader getAasEnvironmentPreconfigurationLoader(ResourceLoader resourceLoader, List pathsToLoad) {
+ return new AasEnvironmentPreconfigurationLoader(resourceLoader, pathsToLoad);
+ }
+
}
diff --git a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/aas.aasx b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/aas.aasx
new file mode 100644
index 000000000..e1003d3ed
Binary files /dev/null and b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/aas.aasx differ
diff --git a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties
index a0531b2ad..aff37727d 100644
--- a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties
+++ b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties
@@ -4,13 +4,13 @@ spring.application.name=AAS Environment
basyx.backend = InMemory
#basyx.backend = MongoDB
-#spring.data.mongodb.host=mongo
+# spring.data.mongodb.host=mongo
# or spring.data.mongodb.host=127.0.0.1
-#spring.data.mongodb.port=27017
-#spring.data.mongodb.database=aasenvironments
-#spring.data.mongodb.authentication-database=admin
-#spring.data.mongodb.username=mongoAdmin
-#spring.data.mongodb.password=mongoPassword
+# spring.data.mongodb.port=27017
+# spring.data.mongodb.database=aasenvironments
+# spring.data.mongodb.authentication-database=admin
+# spring.data.mongodb.username=mongoAdmin
+# spring.data.mongodb.password=mongoPassword
# basyx.aasrepository.feature.mqtt.enabled = true
# mqtt.clientId=TestClient
@@ -27,18 +27,26 @@ basyx.backend = InMemory
# To load from Classpath (src/main/resources) use classpath:path/to/file.end
# To load from Filesystem ( On your local machine ) use the prefix file:
#
-# basyx.environment = classpath:testEnvironment.json,classpath:testEnvironment.xml,file:C:\\Users\\Administrator\\Documents\\01_Festo.aasx,file:/var/www/html/01_Submodel.json
+#basyx.environment = classpath:aas.aasx
#
####################################################################################
# Authorization
####################################################################################
-#basyx.feature.authorization.enabled = true
-#basyx.feature.authorization.type = rbac
-#basyx.feature.authorization.jwtBearerTokenProvider = keycloak
-#basyx.feature.authorization.rbac.file = classpath:rbac_rules.json
-#spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9096/realms/BaSyx
+# basyx.feature.authorization.enabled = true
+# basyx.feature.authorization.type = rbac
+# basyx.feature.authorization.jwtBearerTokenProvider = keycloak
+# basyx.feature.authorization.rbac.file = classpath:rbac_rules.json
+# spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9097/realms/BaSyx
+## This is for preconfiguration of a secured AAS Environment
+# basyx.aasenvironment.authorization.preconfiguration.token-endpoint=http://localhost:9097/realms/BaSyx/protocol/openid-connect/token
+# basyx.aasenvironment.authorization.preconfiguration.grant-type = CLIENT_CREDENTIALS
+# basyx.aasenvironment.authorization.preconfiguration.client-id=workstation-1
+# basyx.aasenvironment.authorization.preconfiguration.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom
+# basyx.aasenvironment.authorization.preconfiguration.username=username
+# basyx.aasenvironment.authorization.preconfiguration.password=password
+# basyx.aasenvironment.authorization.preconfiguration.scopes=
####################################################################################
# Operation Delegation
####################################################################################
diff --git a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/authorization/modulus.txt b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/authorization/modulus.txt
new file mode 100644
index 000000000..9def9d5fa
--- /dev/null
+++ b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/authorization/modulus.txt
@@ -0,0 +1 @@
+sQ4RUvlZXLjQpLizIMht46ASwpwUoPpUDTmUhxF_VV-ezHTHbTAdv_5RA1GgCyTjAQe_Ih6dLByZrJFaroyvqgIJdMRCb0MwajI1US0_NwHtVvo5dea_-GKeHGRzvYZjxVlooR_1xmskfAM_NR_NaOMUhr_TNV7n7LXEb06L55DYnqdqrUnhXLewBq1lo54GsMqxN4hlkc4nJ2uYUtWEkV4SlMyYRjXBlylpuWFO0-_FsmaqSx7CZWjNWmqKlxnvUgRrT5Vh-9ZgCAOmGtLuFYOVWzqmVjWtyiJ1pYfWjwc86XeWBFefVY1lkoNNoSYKV4AZIkeF2M_-FHNzNGhLOw
\ No newline at end of file
diff --git a/basyx.common/basyx.client/src/test/java/org/eclipse/digitaltwin/basyx/client/internal/authorization/TestAccessTokenProviderFactory.java b/basyx.common/basyx.client/src/test/java/org/eclipse/digitaltwin/basyx/client/internal/authorization/TestAccessTokenProviderFactory.java
new file mode 100644
index 000000000..3a821a505
--- /dev/null
+++ b/basyx.common/basyx.client/src/test/java/org/eclipse/digitaltwin/basyx/client/internal/authorization/TestAccessTokenProviderFactory.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.client.internal.authorization;
+
+import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.AccessTokenProvider;
+import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.ClientCredentialAccessTokenProvider;
+import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.GrantType;
+import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.PasswordCredentialAccessTokenProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test for the{@link AccessTokenProviderFactory}
+ *
+ * @author fried, zielstor
+ */
+public class TestAccessTokenProviderFactory {
+
+ private AccessTokenProviderFactory factory;
+ private Collection scopes;
+
+ @Before
+ public void setup() {
+ scopes = Arrays.asList("scope1", "scope2");
+ }
+
+ @Test
+ public void testCreateWithClientCredentials() {
+ factory = new AccessTokenProviderFactory(GrantType.CLIENT_CREDENTIALS, scopes);
+ factory.setClientCredentials("clientId", "clientSecret");
+
+ AccessTokenProvider provider = factory.create();
+
+ assertNotNull(provider);
+ assertTrue(provider instanceof ClientCredentialAccessTokenProvider);
+ }
+
+ @Test
+ public void testCreateWithPasswordCredentials() {
+ factory = new AccessTokenProviderFactory(GrantType.PASSWORD, scopes);
+ factory.setClientCredentials("clientId", "clientSecret");
+ factory.setPasswordCredentials("username", "password");
+
+ AccessTokenProvider provider = factory.create();
+
+ assertNotNull(provider);
+ assertTrue(provider instanceof PasswordCredentialAccessTokenProvider);
+ }
+
+ @Test
+ public void testCreateWithMissingClientCredentials() {
+ factory = new AccessTokenProviderFactory(GrantType.CLIENT_CREDENTIALS, scopes);
+
+ assertThrows(IllegalArgumentException.class, () -> factory.create());
+ }
+
+ @Test
+ public void testCreateWithMissingPasswordCredentials() {
+ factory = new AccessTokenProviderFactory(GrantType.PASSWORD, scopes);
+ factory.setClientCredentials("clientId", "clientSecret");
+
+ assertThrows(IllegalArgumentException.class, () -> factory.create());
+ }
+}
\ No newline at end of file
diff --git a/ci/keycloak/realm/BaSyx-realm.json b/ci/keycloak/realm/BaSyx-realm.json
index 36ee74513..b893decf7 100644
--- a/ci/keycloak/realm/BaSyx-realm.json
+++ b/ci/keycloak/realm/BaSyx-realm.json
@@ -1400,7 +1400,7 @@
"credentials" : [ ],
"disableableCredentialTypes" : [ ],
"requiredActions" : [ ],
- "realmRoles" : [ "basyx-reader", "basyx-deleter", "basyx-updater", "basyx-creator", "default-roles-basyx" ],
+ "realmRoles" : [ "basyx-reader", "basyx-deleter", "basyx-updater", "basyx-creator", "default-roles-basyx", "admin" ],
"clientRoles" : {
"workstation-1" : [ "uma_protection" ]
},