Skip to content

Commit 1737a3f

Browse files
authored
Implement RBAC-based authorization for Submodel Service (eclipse-basyx#682)
* Implement RBAC-based authorization for Submodel Service This commit introduces support for rule-based (RBAC) authorization in the Submodel Service component, following the mechanism used in other parts of the BaSyx stack. Key aspects: - New module: basyx.submodelservice-feature-authorization - Integration of Spring Security to evaluate access control using rbac_rule expressions - Fine-grained access evaluation per submodel element (e.g., operations) - Shared classes moved from Submodel Repository to Submodel Service for better reuse and separation - Integration tests added to validate authorization behavior - Example script (run-security-test.sh) included to demonstrate secured API usage with Keycloak See also: - Issue eclipse-basyx#505 - Design considerations in Issue eclipse-basyx#674 * Reset keycloak version * Fix missing modules * Add section to Readme.md * Remove sm events test events are fired before test start / sometimes on teststart. could be problematic for tests and break the ci process * Update Readme.md * Rename to submodelservice * Remove decoration for submodelservice with id * Update copyright year in header * Update version in copyright header
1 parent ffb9d42 commit 1737a3f

File tree

36 files changed

+1868
-137
lines changed

36 files changed

+1868
-137
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
<groupId>org.eclipse.digitaltwin.basyx</groupId>
6464
<artifactId>basyx.aasenvironment-http</artifactId>
6565
</dependency>
66+
<dependency>
67+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
68+
<artifactId>basyx.submodelservice-feature-authorization</artifactId>
69+
</dependency>
6670
<dependency>
6771
<groupId>org.eclipse.digitaltwin.basyx</groupId>
6872
<artifactId>basyx.aasenvironment-http</artifactId>

basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/rbac/backend/submodel/AasEnvironmentTargetInformationAdapter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.feature.authorization.ConceptDescriptionTargetInformation;
4545
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.feature.authorization.rbac.backend.submodel.CDTargetInformationAdapter;
4646
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;
47+
import org.eclipse.digitaltwin.basyx.submodelservice.feature.authorization.SubmodelTargetInformation;
48+
import org.eclipse.digitaltwin.basyx.submodelservice.feature.authorization.rbac.backend.submodel.SubmodelTargetInformationAdapter;
4949

5050
/**
5151
* An implementation of the {@link TargetInformationAdapter} to adapt with Aas

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

6-
<parent>
6+
<parent>
77
<groupId>org.eclipse.digitaltwin.basyx</groupId>
88
<artifactId>basyx.submodelrepository</artifactId>
99
<version>${revision}</version>
@@ -86,6 +86,10 @@
8686
</exclusion>
8787
</exclusions>
8888
</dependency>
89+
<dependency>
90+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
91+
<artifactId>basyx.submodelservice-feature-authorization</artifactId>
92+
</dependency>
8993
<dependency>
9094
<groupId>org.apache.httpcomponents.client5</groupId>
9195
<artifactId>httpclient5</artifactId>

basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
5050
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationSupport;
5151
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
52+
import org.eclipse.digitaltwin.basyx.submodelservice.feature.authorization.SubmodelTargetInformation;
5253
import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue;
5354
import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelValueOnly;
5455
import org.slf4j.Logger;

basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepositoryFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacPermissionResolver;
2929
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
3030
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepositoryFactory;
31+
import org.eclipse.digitaltwin.basyx.submodelservice.feature.authorization.SubmodelTargetInformation;
3132

3233
/**
3334
* Factory for creating {@link AuthorizedSubmodelRepository}

basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepositoryFeature.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
3131
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepositoryFactory;
3232
import org.eclipse.digitaltwin.basyx.submodelrepository.feature.SubmodelRepositoryFeature;
33+
import org.eclipse.digitaltwin.basyx.submodelservice.feature.authorization.SubmodelTargetInformation;
3334
import org.springframework.beans.factory.annotation.Autowired;
3435
import org.springframework.beans.factory.annotation.Value;
3536
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Submodel Service - Authorization
2+
This feature enables authorized access to the Submodel Service.
3+
4+
To enable this feature, the following properties should be configured:
5+
6+
```
7+
basyx.feature.authorization.enabled = true
8+
basyx.feature.authorization.type = <The type of authorization to enable>
9+
basyx.feature.authorization.jwtBearerTokenProvider = <The Jwt token provider>
10+
basyx.feature.authorization.rbac.file = <Class path of the Rbac rules file if authorization type is rbac>
11+
spring.security.oauth2.resourceserver.jwt.issuer-uri= <URI of the resource server>
12+
```
13+
14+
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.
15+
16+
To know more about the RBAC, please refer [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/index.html)
17+
To know more about the Keycloak server administration, please refer [Server Administration Guide](https://www.keycloak.org/docs/latest/server_admin/#keycloak-features-and-concepts)
18+
19+
An example valid configuration:
20+
21+
```
22+
basyx.feature.authorization.enabled = true
23+
basyx.feature.authorization.type = rbac
24+
basyx.feature.authorization.jwtBearerTokenProvider = keycloak
25+
basyx.feature.authorization.rbac.file = classpath:rbac_rules.json
26+
spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9096/realms/BaSyx
27+
```
28+
29+
## RBAC rule configuration
30+
31+
For configuring RBAC rules, all the rbac rules should be configured inside a json file, the rules are defined as below:
32+
33+
```
34+
[
35+
{
36+
"role": "basyx-reader",
37+
"action": "READ",
38+
"targetInformation": {
39+
"@type": "submodel",
40+
"submodelIds": "*",
41+
"submodelElementIdShortPaths": "*"
42+
}
43+
},
44+
{
45+
"role": "admin",
46+
"action": ["CREATE", "READ", "UPDATE", "DELETE", "EXECUTE"],
47+
"targetInformation": {
48+
"@type": "submodel",
49+
"submodelIds": "*",
50+
"submodelElementIdShortPaths": "*"
51+
}
52+
},
53+
{
54+
"role": "basyx-reader-two",
55+
"action": "READ",
56+
"targetInformation": {
57+
"@type": "submodel",
58+
"submodelIds": "specificSubmodelId",
59+
"submodelElementIdShortPaths": "*"
60+
}
61+
},
62+
{
63+
"role": "basyx-sme-reader",
64+
"action": "READ",
65+
"targetInformation": {
66+
"@type": "submodel",
67+
"submodelIds": ["specificSubmodelId", "testSMId1", "testSMId2"],
68+
"submodelElementIdShortPaths": ["testSMEIdShortPath1","smc2.specificSubmodelElementIdShort","testSMEIdShortPath2"]
69+
}
70+
}
71+
]
72+
```
73+
74+
The role defines which role is allowed to perform the defined actions. The role is as per the configuration of identity providers or based on the organization. Action could be CREATE, READ, UPDATE, DELETE, and EXECUTE, there could be a single action or multiple actions as a list (cf. admin configuration above).
75+
76+
The targetInformation defines coarse-grained control over the resource, you may define the submodelIds and submodelElementIdShortPaths with a wildcard (\*), it means the defined role x with action y can access any Submodel and any SubmodelElement on the repository. You can also define a specific Submodel Identifier in place of the wildcard (\*), then the role x with action y could be performed only on that particular Submodel. Similarly, you can define a specific SubmodelElement IdShort path, then you can only access the SubmodelElement corresponding to that IdShort path. It means that the whole Submodel GET request would not be possible if the IdShort path for a specific SubmodelElement is provided, because the requestor only has access for a specific SubmodelElement.
77+
There could be a single submodelId/submodelElementIdShortPath or multiple submodelIds/submodelElementIdShortPaths as a list (cf. basyx-sme-reader).
78+
79+
Note:
80+
* The Action are fixed as of now and limited to (CREATE, READ, UPDATE, DELETE and EXECUTE) but later user configurable mapping of these actions would be provided.
81+
* Each rule should be unique in combination of role + action + target information
82+
83+
## Action table for RBAC
84+
85+
Below is a reference table that shows which actions are used in what endpoints of the Submodel Repository:
86+
87+
88+
| Action | Operation| Endpoint |
89+
|---------------|----------|----------------|
90+
| READ | GET | /submodel |
91+
| | GET | /submodel/$value |
92+
| | GET | /submodel/$metadata |
93+
| | GET | /submodel/submodel-elements |
94+
| | GET | /submodel/submodel-elements/{idShortPath} |
95+
| | GET | /submodel/submodel-elements/{idShortPath}/$value |
96+
| | GET | /submodel/submodel-elements/{idShortPath}/attachment |
97+
| CREATE | POST | /submodel/submodel-elements |
98+
| | POST | /submodel/submodel-elements/{idShortPath} |
99+
| UPDATE | PATCH | /submodel/submodel-elements/{idShortPath}/$value |
100+
| | PATCH | /submodel/$value |
101+
| | PUT | /submodel/submodel-elements/{idShortPath} |
102+
| | PUT | /submodel/submodel-elements/{idShortPath}/attachment |
103+
| | DELETE | /submodel/submodel-elements/{idShortPath}/attachment |
104+
| DELETE | DELETE | /submodel/submodel-elements/{idShortPath} |
105+
| EXECUTE | POST | /submodel/submodel-elements/{idShortPath}/invoke |
106+
107+
108+
109+
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
8+
<artifactId>basyx.submodelservice</artifactId>
9+
<version>${revision}</version>
10+
</parent>
11+
12+
<artifactId>basyx.submodelservice-feature-authorization</artifactId>
13+
14+
<name>BaSyx submodelservice-feature-authorization</name>
15+
<description>BaSyx submodelservice-feature-authorization</description>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
20+
<artifactId>basyx.submodelservice-core</artifactId>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
24+
<artifactId>basyx.http</artifactId>
25+
<scope>test</scope>
26+
<classifier>tests</classifier>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
30+
<artifactId>basyx.authorization</artifactId>
31+
<scope>test</scope>
32+
<classifier>tests</classifier>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
36+
<artifactId>basyx.http</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
40+
<artifactId>basyx.authorization</artifactId>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
44+
<artifactId>basyx.submodelservice-http</artifactId>
45+
<scope>test</scope>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
49+
<artifactId>basyx.submodelservice-backend</artifactId>
50+
<scope>test</scope>
51+
</dependency>
52+
<dependency>
53+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
54+
<artifactId>basyx.submodelservice-backend-inmemory</artifactId>
55+
<scope>test</scope>
56+
</dependency>
57+
<dependency>
58+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
59+
<artifactId>basyx.authorization.rules.rbac.backend.inmemory</artifactId>
60+
</dependency>
61+
<dependency>
62+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
63+
<artifactId>basyx.authorization.rules.rbac.backend.submodel</artifactId>
64+
<exclusions>
65+
<exclusion>
66+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
67+
<artifactId>basyx.submodelservice-core</artifactId>
68+
</exclusion>
69+
<exclusion>
70+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
71+
<artifactId>basyx.submodelrepository-core</artifactId>
72+
</exclusion>
73+
<exclusion>
74+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
75+
<artifactId>basyx.submodelservice-client</artifactId>
76+
</exclusion>
77+
<exclusion>
78+
<groupId>org.eclipse.digitaltwin.basyx</groupId>
79+
<artifactId>basyx.submodelrepository-client</artifactId>
80+
</exclusion>
81+
</exclusions>
82+
</dependency>
83+
<dependency>
84+
<groupId>org.apache.httpcomponents.client5</groupId>
85+
<artifactId>httpclient5</artifactId>
86+
<scope>test</scope>
87+
</dependency>
88+
<dependency>
89+
<groupId>commons-io</groupId>
90+
<artifactId>commons-io</artifactId>
91+
</dependency>
92+
<dependency>
93+
<groupId>org.springframework.boot</groupId>
94+
<artifactId>spring-boot-starter-test</artifactId>
95+
<scope>test</scope>
96+
</dependency>
97+
<dependency>
98+
<groupId>org.springframework.security</groupId>
99+
<artifactId>spring-security-test</artifactId>
100+
<scope>test</scope>
101+
</dependency>
102+
</dependencies>
103+
</project>

0 commit comments

Comments
 (0)