Skip to content

Commit

Permalink
Implements RBAC Authorization for AAS/Submodel Registry (#249)
Browse files Browse the repository at this point in the history
* First development step aasregistry authorization feature

* Implements RBAC Authorization for AAS Registry

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>
Co-authored-by: Gerhard Sonnenberg 53293048+geso02@users.noreply.github.com

* Deletes test files

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Fixes docker build issue

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Implements RBAC Authorization for Submodel Registry

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Addresses review remarks

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Adds RegistryExceptionHandler

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Removes unnecessary files

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Updates ControllerAdvice

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Refactors code

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

* Addresses review remarks

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>

---------

Signed-off-by: Mohammad Ghazanfar Ali Danish <ghazanfar.danish@iese.fraunhofer.de>
Co-authored-by: geso02 <gerhard.sonnenberg@dfki.de>
  • Loading branch information
mdanish98 and geso02 committed Apr 5, 2024
1 parent 7863c28 commit 3ba7d60
Show file tree
Hide file tree
Showing 127 changed files with 6,374 additions and 28 deletions.
6 changes: 3 additions & 3 deletions basyx.aasregistry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ Install maven generate jars:
mvn clean install
```

In order to build the docker images, you need to specify *docker.username* and *docker.password* properties (here without running tests):
In order to build the docker images, you need to specify *docker.namespace* and *docker.password* properties (here without running tests):

``` shell
MAVEN_OPS='-Xmx2048 -Xms1024' mvn clean install -DskipTests -Ddocker.username=eclipsebasyx -Ddocker.password=""
MAVEN_OPS='-Xmx2048 -Xms1024' mvn clean install -DskipTests -Ddocker.namespace=eclipsebasyx -Ddocker.password=""
```

You can now check your images from command-line and push the images:
Expand All @@ -58,7 +58,7 @@ docker images ...
Or you can directly push them from maven.

``` shell
MAVEN_OPS='-Xmx2048 -Xms1024' mvn deploy -Ddocker.registry=docker.io -Ddocker.username=eclipsebasyx -Ddocker.password=pwd
MAVEN_OPS='-Xmx2048 -Xms1024' mvn deploy -Ddocker.registry=docker.io -Ddocker.namespace=eclipsebasyx -Ddocker.password=pwd
```
In addition, maven deploy will also deploy your maven artifacts, so you can do everything in one step.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# AssetAdministrationShell Registry - Authorization
This feature enables authorized access to the AssetAdministrationShell Registry.

To enable this feature, the following properties should be configured:

```
basyx.feature.authorization.enabled = true
basyx.feature.authorization.type = <The type of authorization to enable>
basyx.feature.authorization.jwtBearerTokenProvider = <The Jwt token provider>
basyx.feature.authorization.rbac.file = <Class path of the Rbac rules file if authorization type is rbac>
spring.security.oauth2.resourceserver.jwt.issuer-uri= <URI of the resource server>
```

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)
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)

An example valid configuration:

```
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
```

## RBAC rule configuration

For configuring RBAC rules, all the rbac rules should be configured inside a json file, the rules are defined as below:

```
[
{
"role": "basyx-reader",
"action": "READ",
"targetInformation": {
"@type": "aas-registry",
"aasId": "*"
}
},
{
"role": "admin",
"action": ["CREATE", "READ", "UPDATE", "DELETE"],
"targetInformation": {
"@type": "aas-registry",
"aasId": "*"
}
},
{
"role": "basyx-deleter",
"action": "DELETE",
"targetInformation": {
"@type": "aas-registry",
"aasId": "specificAasId"
}
}
]
```

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).

The targetInformation defines coarse-grained control over the resource, you may define the aasId with a wildcard (\*), it means the defined role x with action y can access any Asset Administration Shell Descriptors on the registry. You can also define a specific AAS Identifier in place of the wildcard (\*), then the role x with action y could be performed only on that particular AAS Descriptor.

Note: 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.

## Action table for RBAC

Below is a reference table that shows which actions are used in what endpoints of the AAS Registry:

| Action | Endpoint |
|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| READ | GET /shell-descriptors <br /> GET /shell-descriptors/{aasIdentifier} <br /> GET /shell-descriptors/{aasIdentifier}/submodel-descriptors <br /> GET /shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier} <br /> GET /search |
| CREATE | POST /shell-descriptors <br /> |
| UPDATE | PUT /shell-descriptors/{aasIdentifier} <br /> PUT /shell-descriptors/{aasIdentifier}/submodel-descriptors <br /> PUT /shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier} <br /> DELETE /shell-descriptors/{aasIdentifier}/submodel-descriptors/{submodelIdentifier} |
| DELETE | DELETE /shell-descriptors/{aasIdentifier} <br /> DELETE /shell-descriptors |
| EXECUTE | - |


60 changes: 60 additions & 0 deletions basyx.aasregistry/basyx.aasregistry-feature-authorization/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasregistry</artifactId>
<version>${revision}</version>
</parent>

<artifactId>basyx.aasregistry-feature-authorization</artifactId>

<dependencies>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasregistry-service</artifactId>
</dependency>

<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasregistry-service-basemodel</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.http</artifactId>
<scope>test</scope>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.http</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.authorization</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.authorization</artifactId>
<scope>test</scope>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>

<dependency>
<groupId>org.eclipse.digitaltwin.basyx</groupId>
<artifactId>basyx.aasregistry-service-inmemory-storage</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*******************************************************************************
* 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.aasregistry.feature.authorization;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetInformation;
import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetInformationSubtype;

/**
* Specialization of {@link TargetInformation} for Aas Registry target information
*
* @author geso02, danish
*
*/
@TargetInformationSubtype(getValue = "aas-registry")
public class AasRegistryTargetInformation implements TargetInformation {

private String aasId;

@JsonCreator
public AasRegistryTargetInformation(final @JsonProperty("aasId") String aasId) {
this.aasId = aasId;
}

@Override
public Map<String, Object> toMap() {
final Map<String, Object> map = new HashMap<>();
map.put("aasId", aasId);
return map;
}

@Override
public int hashCode() {
return Objects.hash(aasId);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AasRegistryTargetInformation other = (AasRegistryTargetInformation) obj;
return Objects.equals(aasId, other.aasId);
}

@Override
public String toString() {
return "AasTargetInformation [aasId=" + aasId + "]";
}

public String getAasId() {
return aasId;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*******************************************************************************
* Copyright (C) 2023 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.aasregistry.feature.authorization;

import org.eclipse.digitaltwin.basyx.aasregistry.feature.authorization.rbac.AasRegistryTargetPermissionVerifier;
import org.eclipse.digitaltwin.basyx.authorization.CommonAuthorizationProperties;
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacPermissionResolver;
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacStorage;
import org.eclipse.digitaltwin.basyx.authorization.rbac.RoleProvider;
import org.eclipse.digitaltwin.basyx.authorization.rbac.SimpleRbacPermissionResolver;
import org.eclipse.digitaltwin.basyx.authorization.rbac.TargetPermissionVerifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Configuration for authorized {@link AuthorizedAasRegistryStorage}
*
* @author geso02, danish
*/
@Configuration
@ConditionalOnExpression("#{${" + CommonAuthorizationProperties.ENABLED_PROPERTY_KEY + ":false}}")
public class AuthorizedAasRegistryConfiguration {

@Bean
public TargetPermissionVerifier<AasRegistryTargetInformation> getAasTargetPermissionVerifier() {
return new AasRegistryTargetPermissionVerifier();
}

@Bean
public RbacPermissionResolver<AasRegistryTargetInformation> getAasPermissionResolver(RbacStorage rbacStorage, RoleProvider roleProvider, TargetPermissionVerifier<AasRegistryTargetInformation> targetPermissionVerifier) {
return new SimpleRbacPermissionResolver<>(rbacStorage, roleProvider, targetPermissionVerifier);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*******************************************************************************
* 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.aasregistry.feature.authorization;

import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.AasRegistryStorage;
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.AasRegistryStorageFeature;
import org.eclipse.digitaltwin.basyx.authorization.CommonAuthorizationProperties;
import org.eclipse.digitaltwin.basyx.authorization.rbac.RbacPermissionResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
* Feature for authorized {@link AasRegistryStorage}
*
* @author geso02
*/
@Component
@ConditionalOnExpression("#{${" + CommonAuthorizationProperties.ENABLED_PROPERTY_KEY + ":false}}")
@Order(0)
public class AuthorizedAasRegistryFeature implements AasRegistryStorageFeature {

@Value("${" + CommonAuthorizationProperties.ENABLED_PROPERTY_KEY + ":}")
private boolean enabled;

private RbacPermissionResolver<AasRegistryTargetInformation> permissionResolver;

@Autowired
public AuthorizedAasRegistryFeature(RbacPermissionResolver<AasRegistryTargetInformation> permissionResolver) {
this.permissionResolver = permissionResolver;
}

@Override
public AasRegistryStorage decorate(AasRegistryStorage storage) {
return new AuthorizedAasRegistryStorage(storage, permissionResolver);
}

@Override
public String getName() {
return "AasRegistry Authorization";
}

@Override
public boolean isEnabled() {
return enabled;
}
}
Loading

0 comments on commit 3ba7d60

Please sign in to comment.