Skip to content

Commit d5f9b24

Browse files
authored
Implements a feature to support the Submodel-based RBAC rules backend for the remaining components (#574)
* Adds dynamic RBAC to SM/CD Rep, SM Reg, and AAS Environment Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Reverts GitHub CI Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Attempts CI fix Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Reverts GitHub CI Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Reverts GitHub CI Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Adds shading plugin Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Adds dependency to parent pom Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Excludes SM dependencies Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Fixes the TargetInfoAdapter Bean in Aas Env Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Adds filtering options in Authorization Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Fixes Keycloak issues Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Reverts BaSyx Realm Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Fixes import issues in SM Registry Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Fixes app.prop of aas env Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Fixes CI Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Fixes AAS and SM Reg tests Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Allows swagger ui api endpoint without auth Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Allows swagger ui api endpoint without auth Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Allows Swagger API without authorization Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Refactors classes Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Addresses review remarks Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> * Addresses review remarks Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]> --------- Signed-off-by: Mohammad Ghazanfar Ali Danish <[email protected]>
1 parent 59a71dc commit d5f9b24

File tree

24 files changed

+1458
-29
lines changed

24 files changed

+1458
-29
lines changed

basyx.aasenvironment/basyx.aasenvironment-feature-authorization/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@
8181
<dependency>
8282
<groupId>org.eclipse.digitaltwin.basyx</groupId>
8383
<artifactId>basyx.authorization.rules.rbac.backend.inmemory</artifactId>
84+
</dependency>
85+
<dependency>
86+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
87+
<artifactId>basyx.authorization.rules.rbac.backend.submodel</artifactId>
8488
</dependency>
8589
</dependencies>
8690
</project>

basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/AuthorizedAasEnvironmentConfiguration.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@
2727

2828
import org.eclipse.digitaltwin.basyx.aasenvironment.AasEnvironment;
2929
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization.rbac.AasEnvironmentTargetPermissionVerifier;
30+
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization.rbac.backend.submodel.AasEnvironmentTargetInformationAdapter;
3031
import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader;
3132
import org.eclipse.digitaltwin.basyx.authorization.CommonAuthorizationProperties;
3233
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacPermissionResolver;
3334
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacStorage;
3435
import org.eclipse.digitaltwin.basyx.authorization.rbac.SimpleRbacPermissionResolver;
3536
import org.eclipse.digitaltwin.basyx.authorization.rbac.RoleProvider;
3637
import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetPermissionVerifier;
38+
import org.eclipse.digitaltwin.basyx.authorization.rules.rbac.backend.submodel.TargetInformationAdapter;
39+
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.feature.authorization.rbac.backend.submodel.CDTargetInformationAdapter;
3740
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
3841
import org.springframework.context.annotation.Bean;
3942
import org.springframework.context.annotation.Configuration;
@@ -67,5 +70,12 @@ public RbacPermissionResolver<AasEnvironmentTargetInformation> getAasEnvironment
6770
public static AasEnvironmentPreconfigurationLoader getAuthorizedAasEnvironmentPreconfigurationLoader(ResourceLoader resourceLoader, List<String> pathsToLoad) {
6871
return new AuthorizedAASEnvironmentPreconfigurationLoader(resourceLoader, pathsToLoad);
6972
}
73+
74+
@Bean
75+
@Primary
76+
public TargetInformationAdapter getAasEnvInformationAdapter() {
77+
78+
return new AasEnvironmentTargetInformationAdapter();
79+
}
7080

7181
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*******************************************************************************
2+
* Copyright (C) 2025 the Eclipse BaSyx Authors
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the
6+
* "Software"), to deal in the Software without restriction, including
7+
* without limitation the rights to use, copy, modify, merge, publish,
8+
* distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so, subject to
10+
* the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be
13+
* included in all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*
23+
* SPDX-License-Identifier: MIT
24+
******************************************************************************/
25+
26+
package org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization.rbac.backend.submodel;
27+
28+
import java.util.Arrays;
29+
import java.util.List;
30+
import java.util.stream.Collectors;
31+
32+
import org.eclipse.digitaltwin.aas4j.v3.model.Property;
33+
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement;
34+
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElementCollection;
35+
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElementList;
36+
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultProperty;
37+
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodelElementCollection;
38+
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodelElementList;
39+
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization.AasEnvironmentTargetInformation;
40+
import org.eclipse.digitaltwin.basyx.aasrepository.feature.authorization.AasTargetInformation;
41+
import org.eclipse.digitaltwin.basyx.aasrepository.feature.authorization.rbac.backend.submodel.AasTargetInformationAdapter;
42+
import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetInformation;
43+
import org.eclipse.digitaltwin.basyx.authorization.rules.rbac.backend.submodel.TargetInformationAdapter;
44+
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.feature.authorization.ConceptDescriptionTargetInformation;
45+
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.feature.authorization.rbac.backend.submodel.CDTargetInformationAdapter;
46+
import org.eclipse.digitaltwin.basyx.core.exceptions.InvalidTargetInformationException;
47+
import org.eclipse.digitaltwin.basyx.submodelrepository.feature.authorization.SubmodelTargetInformation;
48+
import org.eclipse.digitaltwin.basyx.submodelrepository.feature.authorization.rbac.backend.submodel.SubmodelTargetInformationAdapter;
49+
50+
/**
51+
* An implementation of the {@link TargetInformationAdapter} to adapt with Aas
52+
* {@link TargetInformation}
53+
*
54+
* @author danish
55+
*/
56+
public class AasEnvironmentTargetInformationAdapter implements TargetInformationAdapter {
57+
58+
@Override
59+
public SubmodelElementCollection adapt(TargetInformation targetInformation) {
60+
61+
if (targetInformation instanceof AasTargetInformation)
62+
return new AasTargetInformationAdapter().adapt(targetInformation);
63+
64+
if (targetInformation instanceof SubmodelTargetInformation)
65+
return new SubmodelTargetInformationAdapter().adapt(targetInformation);
66+
67+
if (targetInformation instanceof ConceptDescriptionTargetInformation)
68+
return new CDTargetInformationAdapter().adapt(targetInformation);
69+
70+
SubmodelElementCollection targetInformationSMC = new DefaultSubmodelElementCollection.Builder().idShort("targetInformation").build();
71+
72+
SubmodelElementList aasId = new DefaultSubmodelElementList.Builder().idShort("aasIds").build();
73+
SubmodelElementList submodelId = new DefaultSubmodelElementList.Builder().idShort("submodelIds").build();
74+
Property typeProperty = new DefaultProperty.Builder().idShort("@type").value("aas-environment").build();
75+
76+
List<SubmodelElement> aasIds = ((AasEnvironmentTargetInformation) targetInformation).getAasIds().stream().map(this::transform).collect(Collectors.toList());
77+
List<SubmodelElement> submodelIds = ((AasEnvironmentTargetInformation) targetInformation).getSubmodelIds().stream().map(this::transform).collect(Collectors.toList());
78+
aasId.setValue(aasIds);
79+
submodelId.setValue(submodelIds);
80+
81+
targetInformationSMC.setValue(Arrays.asList(aasId, submodelId, typeProperty));
82+
83+
return targetInformationSMC;
84+
}
85+
86+
@Override
87+
public TargetInformation adapt(SubmodelElementCollection targetInformation) {
88+
89+
String targetInformationType = getTargetInformationType(targetInformation);
90+
91+
if (targetInformationType.equals("aas"))
92+
return new AasTargetInformationAdapter().adapt(targetInformation);
93+
94+
if (targetInformationType.equals("submodel"))
95+
return new SubmodelTargetInformationAdapter().adapt(targetInformation);
96+
97+
if (targetInformationType.equals("concept-description"))
98+
return new CDTargetInformationAdapter().adapt(targetInformation);
99+
100+
if (!targetInformationType.equals("aas-environment"))
101+
throw new InvalidTargetInformationException(
102+
"The TargetInformation @type: " + targetInformationType + " is not compatible with "
103+
+ getClass().getName() + ".");
104+
105+
SubmodelElement aasIdSubmodelElement = targetInformation.getValue().stream().filter(sme -> sme.getIdShort().equals("aasIds")).findAny().orElseThrow(
106+
() -> new InvalidTargetInformationException("The TargetInformation defined in the SubmodelElementCollection Rule with id: " + targetInformation.getIdShort() + " is not compatible with the " + getClass().getName()));
107+
108+
SubmodelElement submodelIdSubmodelElement = targetInformation.getValue().stream().filter(sme -> sme.getIdShort().equals("submodelIds")).findAny().orElseThrow(
109+
() -> new InvalidTargetInformationException("The TargetInformation defined in the SubmodelElementCollection Rule with id: " + targetInformation.getIdShort() + " is not compatible with the " + getClass().getName()));
110+
111+
if (!(aasIdSubmodelElement instanceof SubmodelElementList) || !(submodelIdSubmodelElement instanceof SubmodelElementList))
112+
throw new InvalidTargetInformationException("The TargetInformation defined in the SubmodelElementCollection Rule with id: " + targetInformation.getIdShort() + " is not compatible with the " + getClass().getName());
113+
114+
SubmodelElementList aasIdList = (SubmodelElementList) aasIdSubmodelElement;
115+
SubmodelElementList submodelIdList = (SubmodelElementList) submodelIdSubmodelElement;
116+
117+
List<String> aasIds = aasIdList.getValue().stream().map(Property.class::cast).map(Property::getValue).collect(Collectors.toList());
118+
List<String> submodelIds = submodelIdList.getValue().stream().map(Property.class::cast).map(Property::getValue).collect(Collectors.toList());
119+
120+
return new AasEnvironmentTargetInformation(aasIds, submodelIds);
121+
}
122+
123+
private String getTargetInformationType(SubmodelElementCollection targetInformation) {
124+
125+
Property typeProperty = (Property) targetInformation.getValue().stream().filter(sme -> sme.getIdShort().equals("@type")).findAny().orElseThrow(() -> new InvalidTargetInformationException("The TargetInformation defined in the SubmodelElementCollection Rule with id: " + targetInformation.getIdShort() + " does not have @type definition"));
126+
127+
return typeProperty.getValue();
128+
}
129+
130+
private Property transform(String aasId) {
131+
return new DefaultProperty.Builder().value(aasId).build();
132+
}
133+
134+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*******************************************************************************
2+
* Copyright (C) 2025 the Eclipse BaSyx Authors
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining
5+
* a copy of this software and associated documentation files (the
6+
* "Software"), to deal in the Software without restriction, including
7+
* without limitation the rights to use, copy, modify, merge, publish,
8+
* distribute, sublicense, and/or sell copies of the Software, and to
9+
* permit persons to whom the Software is furnished to do so, subject to
10+
* the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be
13+
* included in all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19+
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21+
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
*
23+
* SPDX-License-Identifier: MIT
24+
******************************************************************************/
25+
26+
package org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization;
27+
28+
import static org.junit.Assert.*;
29+
import org.eclipse.digitaltwin.aas4j.v3.model.Property;
30+
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement;
31+
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElementCollection;
32+
import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElementList;
33+
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultProperty;
34+
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodelElementCollection;
35+
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodelElementList;
36+
import org.junit.Before;
37+
import org.junit.Test;
38+
39+
import java.util.Arrays;
40+
import java.util.Collections;
41+
import java.util.List;
42+
import java.util.stream.Collectors;
43+
44+
import org.eclipse.digitaltwin.basyx.aasenvironment.feature.authorization.rbac.backend.submodel.AasEnvironmentTargetInformationAdapter;
45+
import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetInformation;
46+
import org.eclipse.digitaltwin.basyx.core.exceptions.InvalidTargetInformationException;
47+
48+
/**
49+
* Tests {@link AasEnvironmentTargetInformationAdapter}
50+
*
51+
* @author danish
52+
*/
53+
public class AasEnvironmentTargetInformationAdapterTest {
54+
55+
private AasEnvironmentTargetInformationAdapter aasEnvironmentTargetInformationAdapter;
56+
57+
@Before
58+
public void setUp() {
59+
aasEnvironmentTargetInformationAdapter = new AasEnvironmentTargetInformationAdapter();
60+
}
61+
62+
@Test
63+
public void testAdaptTargetInformationToSubmodelElementCollection() {
64+
65+
List<String> aasIds = Arrays.asList("aasId1", "aasId2");
66+
List<String> submodelIds = Arrays.asList("smId1", "smId2");
67+
TargetInformation targetInformation = new AasEnvironmentTargetInformation(aasIds, submodelIds);
68+
69+
SubmodelElementCollection result = aasEnvironmentTargetInformationAdapter.adapt(targetInformation);
70+
71+
assertEquals("targetInformation", result.getIdShort());
72+
73+
List<SubmodelElement> elements = result.getValue();
74+
assertEquals(3, elements.size());
75+
76+
SubmodelElementList aasIdList = (SubmodelElementList) elements.get(0);
77+
assertEquals("aasIds", aasIdList.getIdShort());
78+
79+
SubmodelElementList submodelIdList = (SubmodelElementList) elements.get(1);
80+
assertEquals("submodelIds", submodelIdList.getIdShort());
81+
82+
Property typeProperty = (Property) elements.get(2);
83+
assertEquals("@type", typeProperty.getIdShort());
84+
85+
List<String> actualAasIds = aasIdList.getValue().stream().map(Property.class::cast).map(Property::getValue).map(String::valueOf).collect(Collectors.toList());
86+
assertEquals(aasIds, actualAasIds);
87+
88+
List<String> actualSubmodelIds = submodelIdList.getValue().stream().map(Property.class::cast).map(Property::getValue).map(String::valueOf).collect(Collectors.toList());
89+
assertEquals(submodelIds, actualSubmodelIds);
90+
91+
String actualType = typeProperty.getValue();
92+
assertTrue(actualType.equals("aas-environment"));
93+
}
94+
95+
@Test
96+
public void testAdaptSubmodelElementCollectionToTargetInformation() {
97+
98+
List<String> expectedAasIds = Arrays.asList("aasId1", "aasId2");
99+
List<String> expectedSubmodelIds = Arrays.asList("smId1", "smId2");
100+
String type = "aas-environment";
101+
102+
List<SubmodelElement> aasIdProperties = expectedAasIds.stream().map(aasId -> new DefaultProperty.Builder().value(aasId).build()).collect(Collectors.toList());
103+
List<SubmodelElement> submodelIdProperties = expectedSubmodelIds.stream().map(submodelId -> new DefaultProperty.Builder().value(submodelId).build()).collect(Collectors.toList());
104+
105+
SubmodelElementList aasIdList = new DefaultSubmodelElementList.Builder().idShort("aasIds").value(aasIdProperties).build();
106+
SubmodelElementList submodelIdList = new DefaultSubmodelElementList.Builder().idShort("submodelIds").value(submodelIdProperties).build();
107+
SubmodelElement typeProperty = createTypeProperty(type);
108+
109+
SubmodelElementCollection targetInformationSMC = new DefaultSubmodelElementCollection.Builder().idShort("targetInformation").value(Arrays.asList(aasIdList, submodelIdList, typeProperty)).build();
110+
111+
TargetInformation result = aasEnvironmentTargetInformationAdapter.adapt(targetInformationSMC);
112+
113+
assertTrue(result instanceof AasEnvironmentTargetInformation);
114+
assertEquals(expectedAasIds, ((AasEnvironmentTargetInformation) result).getAasIds());
115+
assertEquals(expectedSubmodelIds, ((AasEnvironmentTargetInformation) result).getSubmodelIds());
116+
}
117+
118+
@Test
119+
public void testAdaptTargetInformationWithEmptyAasIds() {
120+
121+
List<String> aasIds = Collections.emptyList();
122+
List<String> submodelIds = Collections.emptyList();
123+
124+
TargetInformation targetInformation = new AasEnvironmentTargetInformation(aasIds, submodelIds);
125+
126+
SubmodelElementCollection result = aasEnvironmentTargetInformationAdapter.adapt(targetInformation);
127+
128+
assertEquals("targetInformation", result.getIdShort());
129+
130+
List<SubmodelElement> elements = result.getValue();
131+
assertEquals(3, elements.size());
132+
133+
SubmodelElementList aasIdList = (SubmodelElementList) elements.get(0);
134+
assertEquals("aasIds", aasIdList.getIdShort());
135+
136+
SubmodelElementList submodelIdList = (SubmodelElementList) elements.get(1);
137+
assertEquals("submodelIds", submodelIdList.getIdShort());
138+
139+
Property typeProperty = (Property) elements.get(2);
140+
assertEquals("@type", typeProperty.getIdShort());
141+
142+
List<String> actualAasIds = aasIdList.getValue().stream()
143+
.map(Property.class::cast)
144+
.map(Property::getValue)
145+
.map(String::valueOf)
146+
.collect(Collectors.toList());
147+
assertTrue(actualAasIds.isEmpty());
148+
149+
List<String> actualSubmodelIds = submodelIdList.getValue().stream()
150+
.map(Property.class::cast)
151+
.map(Property::getValue)
152+
.map(String::valueOf)
153+
.collect(Collectors.toList());
154+
assertTrue(actualSubmodelIds.isEmpty());
155+
156+
String actualType = typeProperty.getValue();
157+
assertTrue(actualType.equals("aas-environment"));
158+
}
159+
160+
@Test(expected = InvalidTargetInformationException.class)
161+
public void testAdaptSubmodelElementCollectionWithInvalidStructure() {
162+
163+
SubmodelElementCollection targetInformationSMC = new DefaultSubmodelElementCollection.Builder().idShort("targetInformation")
164+
.value(Collections.singletonList(new DefaultProperty.Builder().idShort("invalidElement").value("value").build()))
165+
.build();
166+
167+
aasEnvironmentTargetInformationAdapter.adapt(targetInformationSMC);
168+
}
169+
170+
@Test(expected = InvalidTargetInformationException.class)
171+
public void testAdaptSubmodelElementCollectionWithoutAasIds() {
172+
173+
SubmodelElementCollection targetInformationSMC = new DefaultSubmodelElementCollection.Builder().idShort("targetInformation")
174+
.value(Collections.emptyList())
175+
.build();
176+
177+
aasEnvironmentTargetInformationAdapter.adapt(targetInformationSMC);
178+
}
179+
180+
private SubmodelElement createTypeProperty(String type) {
181+
return new DefaultProperty.Builder().idShort("@type").value(type).build();
182+
}
183+
184+
}

0 commit comments

Comments
 (0)