Skip to content

Commit

Permalink
Merge pull request #698 from catenax-ng/feature/259-new-auth-through-…
Browse files Browse the repository at this point in the history
…api-key

feat(impl):[#259] new authentication through api key impl
  • Loading branch information
ds-ext-kmassalski authored Jan 12, 2024
2 parents 104bcfb + 1284585 commit fc643dc
Show file tree
Hide file tree
Showing 64 changed files with 838 additions and 1,089 deletions.
4 changes: 2 additions & 2 deletions .config/spotbugs-excludes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
</Match>
<Match>
<!-- CSRF protection turned off on purpose. -->
<Class name="org.eclipse.tractusx.irs.configuration.SecurityConfiguration"/>
<Class name="org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration"/>
<Method name="securityFilterChain"/>
<Bug pattern="SPRING_CSRF_PROTECTION_DISABLED"/>
</Match>
<Match>
<!-- We want to explicitly throw Exception in this method. -->
<Class name="org.eclipse.tractusx.irs.configuration.SecurityConfiguration"/>
<Class name="org.eclipse.tractusx.irs.configuration.security.SecurityConfiguration"/>
<Method name="securityFilterChain"/>
<Bug pattern="THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION"/>
</Match>
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish-documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 16
node-version: 20

- name: Cache maven packages
uses: actions/cache@v3
Expand Down Expand Up @@ -105,8 +105,8 @@ jobs:
- name: MD linting
run: |
npm install markdownlint-cli2
npx markdownlint-cli2-config docs/.markdownlint.yaml docs/target/generated-docs/adminguide.md
npx markdownlint-cli2-config docs/.markdownlint.yaml docs/target/generated-docs/arc42.md
npx markdownlint-cli2 --config docs/.markdownlint.yaml docs/target/generated-docs/adminguide.md
npx markdownlint-cli2 --config docs/.markdownlint.yaml docs/target/generated-docs/arc42.md
- name: Move assets to target directory
run: |
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Added EDR token cache to reuse token after contract negotiation
- Added cache mechanism in DiscoveryFinderClientImpl for findDiscoveryEndpoints

### Changed
- Authentication was redesigned to use API keys, instead of OAuth2 protocol. The api key has to be sent as a X-API-KEY request header. IRS is supporting two types of API keys - one for admin and one for regular/view usage. Use new ``apiKeyAdmin`` and ``apiKeyRegular`` config entries to set up API keys.

### Removed
- Removed ``oauth.resourceClaim``, ``oauth.irsNamespace``,``oauth.roles``,``oauth2.jwkSetUri`` config entries

## [4.3.0] - 2023-12-08
### Added
- Added support for `hasAlternatives` property in SingleLevelBomAsBuilt aspect
Expand Down
8 changes: 4 additions & 4 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ maven/mavencentral/io.prometheus/simpleclient_common/0.16.0, Apache-2.0, approve
maven/mavencentral/io.prometheus/simpleclient_tracer_common/0.16.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.prometheus/simpleclient_tracer_otel/0.16.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.prometheus/simpleclient_tracer_otel_agent/0.16.0, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.rest-assured/json-path/5.3.0, Apache-2.0, approved, #9261
maven/mavencentral/io.rest-assured/json-path/5.3.2, Apache-2.0, approved, #9261
maven/mavencentral/io.rest-assured/rest-assured-common/5.3.0, Apache-2.0, approved, #9264
maven/mavencentral/io.rest-assured/json-path/5.4.0, Apache-2.0, approved, #12042
maven/mavencentral/io.rest-assured/rest-assured-common/5.3.2, Apache-2.0, approved, #9264
maven/mavencentral/io.rest-assured/rest-assured/5.3.0, Apache-2.0, approved, #9262
maven/mavencentral/io.rest-assured/xml-path/5.3.0, Apache-2.0, approved, #9267
maven/mavencentral/io.rest-assured/rest-assured-common/5.4.0, Apache-2.0, approved, #12039
maven/mavencentral/io.rest-assured/rest-assured/5.4.0, Apache-2.0, approved, #12040
maven/mavencentral/io.rest-assured/xml-path/5.3.2, Apache-2.0, approved, #9267
maven/mavencentral/io.rest-assured/xml-path/5.4.0, Apache-2.0, approved, #12038
maven/mavencentral/io.suzaku/boopickle_2.13/1.3.3, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-annotations-jakarta/2.2.15, Apache-2.0, approved, #5947
maven/mavencentral/io.swagger.core.v3/swagger-annotations/2.2.16, Apache-2.0, approved, #11362
Expand Down
13 changes: 5 additions & 8 deletions charts/irs-helm/templates/configmap-spring-app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ data:
irs:
apiUrl: {{ tpl (.Values.irsUrl | default "http://localhost") . | quote }}
security:
api:
keys:
admin: {{ tpl (.Values.apiKeyAdmin | default "") . | quote }}
regular: {{ tpl (.Values.apiKeyRegular | default "") . | quote }}
blobstore:
endpoint: {{ tpl (.Values.minioUrl | default "") . | quote }}
Expand Down Expand Up @@ -62,9 +67,6 @@ data:
token-uri: {{ tpl (.Values.oauth2.clientTokenUri | default "http://localhost") . | quote }}
portal:
token-uri: {{ tpl (.Values.oauth2.clientTokenUri | default "http://localhost") . | quote }}
resourceserver:
jwt:
jwk-set-uri: {{ tpl (.Values.oauth2.jwkSetUri | default "http://localhost") . | quote }}
digitalTwinRegistry:
descriptorEndpoint: {{ tpl (.Values.digitalTwinRegistry.descriptorEndpoint | default "") . | quote }}
Expand Down Expand Up @@ -147,11 +149,6 @@ data:
apiAllowedBpn: {{ tpl (.Values.bpn | default "") . | quote }}
oauth:
resourceClaim: {{ tpl (.Values.oauth.resourceClaim | default "resource_access") . | quote }}
irsNamespace: {{ tpl (.Values.oauth.irsNamespace | default "") . | quote }}
roles: {{ tpl (.Values.oauth.roles | default "roles") . | quote }}
{{- if .Values.config.content }}
{{- tpl (toYaml .Values.config.content) . | nindent 4 }}
{{- end }}
8 changes: 2 additions & 6 deletions charts/irs-helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ readinessProbe:
#####################
irsUrl: # "https://<irs-url>"
bpn: # BPN for this IRS instance; only users with this BPN are allowed to access the API
apiKeyAdmin: "password" # <api-key-admin> Admin auth key, Should be changed!
apiKeyRegular: "password" # <api-key-regular> View auth key, Should be changed!
ingress:
enabled: false

Expand Down Expand Up @@ -153,7 +155,6 @@ oauth2:
clientId: # <oauth2-client-id>
clientSecret: # <oauth2-client-secret>
clientTokenUri: # <oauth2-token-uri>
jwkSetUri: # <oauth2-jwkset-uri>
portal:
oauth2:
clientId: # <portal-client-id>
Expand Down Expand Up @@ -217,11 +218,6 @@ ess:
policydefinitionsPath: /management/v2/policydefinitions # EDC management API "policydefinitions" path - used for notification policy definition creation
contractdefinitionsPath: /management/v2/contractdefinitions # EDC management API "contractdefinitions" path - used for notification contract definitions creation

oauth:
resourceClaim: "resource_access" # Name of the JWT claim for roles
irsNamespace: "Cl20-CX-IRS" # Namespace for the IRS roles
roles: "roles" # Name of the list of roles within the IRS namespace

config:
# If true, the config provided below will completely replace the configmap.
# In this case, you need to provide all required config values defined above yourself!
Expand Down
9 changes: 0 additions & 9 deletions docs/src/api/irs-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,6 @@ components:
globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0
id: e5347c88-a921-11ec-b909-0242ac120002
lastModifiedOn: 2022-02-03T14:48:54.709Z
owner: ""
parameter:
aspects:
- SerialPart
Expand Down Expand Up @@ -1043,7 +1042,6 @@ components:
globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0
id: e5347c88-a921-11ec-b909-0242ac120002
lastModifiedOn: 2022-02-03T14:48:54.709Z
owner: ""
parameter:
aspects:
- SerialPart
Expand Down Expand Up @@ -1166,7 +1164,6 @@ components:
globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0
id: e5347c88-a921-11ec-b909-0242ac120002
lastModifiedOn: 2022-02-03T14:48:54.709Z
owner: ""
parameter:
aspects:
- SerialPart
Expand Down Expand Up @@ -1317,7 +1314,6 @@ components:
globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0
id: e5347c88-a921-11ec-b909-0242ac120002
lastModifiedOn: 2022-02-03T14:48:54.709Z
owner: ""
parameter:
aspects:
- SerialPart
Expand Down Expand Up @@ -1355,7 +1351,6 @@ components:
globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0
id: e5347c88-a921-11ec-b909-0242ac120002
lastModifiedOn: 2022-02-03T14:48:54.709Z
owner: ""
parameter:
aspects:
- SerialPart
Expand Down Expand Up @@ -1470,7 +1465,6 @@ components:
globalAssetId: urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0
id: e5347c88-a921-11ec-b909-0242ac120002
lastModifiedOn: 2022-02-03T14:48:54.709Z
owner: ""
parameter:
aspects:
- SerialPart
Expand Down Expand Up @@ -1918,9 +1912,6 @@ components:
type: string
format: date-time
example: 2022-02-03T14:48:54.709Z
owner:
type: string
description: The IRS api consumer.
parameter:
$ref: '#/components/schemas/JobParameter'
startedOn:
Expand Down
11 changes: 7 additions & 4 deletions docs/src/docs/administration/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ include::../../../../charts/irs-helm/values.yaml[lines=104..302]
==== <irs-url>
The hostname where the IRS will be made available.
==== <api-key-admin>
Api key to access API with admin role.
==== <api-key-regular>
Api key to access API with regular/view role.
=== <ingress>
To expose the IRS service, you need to add an ingress for the default port 8080.
You can do this by adding this to ingress:
Expand Down Expand Up @@ -64,9 +70,6 @@ The URL of the BPDM service. The IRS uses this service to fetch business partner
==== <oauth2-token-uri>
The URL of the OAuth2 token API. Used by the IRS for token creation to authenticate with other services.
==== <oauth2-jwkset-uri>
The URL of the OAuth2 JWK Set. Used by the IRS to validate tokens when the IRS API is called.
==== <grafana-url>
The hostname where Grafana will be made available.
Expand All @@ -86,7 +89,7 @@ When IRS calls EDC Discovery Service to fetch connector endpoints for BPNLs, the
This parameter define how long cache is maintained before it is cleared. Data is in ISO 8601.
== OAuth2 Configuration
OAuth2 protocol is used by IRS to protect the APIs and other resources. This means it is possible to configure and use any identity and access management tool that provides OAuth 2.0 functionality.
Previously, OAuth2 protocol was used by IRS to protect the APIs and other resources. As a reference, latest IRS version that supported OAuth2 protocol was 4.3.0, which can be found here: https://github.com/eclipse-tractusx/item-relationship-service/releases/tag/4.3.0.
=== Semantic Model Provisioning
The IRS can retrieve semantic models in two ways:
Expand Down
67 changes: 15 additions & 52 deletions docs/src/docs/arc42/cross-cutting/safety-security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@

=== IRS API

The IRS is secured using OAuth2.0 / Open ID Connect.
Every request to the IRS API requires a valid bearer token.
JWT token should also contain two claims:

- 'bpn' which is equal to the configuration value from `API_ALLOWED_BPN` property
- 'resource_access' with the specific 'Cl20-CX-IRS' key for C-X environments. (The keys are configurable. For more details see chapter "IRS OAuth2 JWT Token").
The list of values will be converted to roles by IRS.
Currently, IRS API handles two roles: *'admin_irs'* and *'view_irs'.* A valid token with the *'admin_irs'* role can access any endpoint exposed by the IRS API, while a token with the *'view_irs'* role does not have access to policies endpoints and can operate only on resources it owns.
That means that he only has access to the resources he has created, e.g. jobs and batches.
The IRS API is secured using API Keys (tokens that a client provides when invoking API calls). IRS identifies API clients based on the provided token inside 'X-API-KEY' request header, and then checks the token with configuration. API Keys can be configured with helm configuration entries - check Administration Guide to know how to do this. Every request to the IRS API requires a valid 'X-API-KEY' header to be successfully authenticated.

Currently, IRS API handles two roles: *'admin_irs'* and *'view_irs'.* A valid token with the *'admin_irs'* role can access any endpoint exposed by the IRS API, including Policies management API. A valid token with the *'view_irs'* role does not have access to policies endpoints.
This behavior is shown in the table below.

==== Rights and Roles Matrix of IRS
Expand All @@ -24,56 +18,25 @@ This behavior is shown in the table below.
| | Update policy | PUT /irs/policies/{policyId} | | x
| | Delete policy | DELETE /irs/policies/{policyId} | | x
| Aspect models | Get aspect models | GET /irs/aspectmodels | x | x
| Job processing | Register job | POST /irs/jobs | (x) | x
| | Get jobs | GET /irs/jobs | (x) | x
| | Get job | GET /irs/jobs/{jobId} | (x) | x
| | Cancel job | PUT /irs/jobs/{jobId} | (x) | x
| Batch processing | Register order | POST /irs/orders | (x) | x
| | Get order | GET /irs/orders/{orderId} | (x) | x
| | Cancel order | PUT /irs/orders/{orderId} | (x) | x
| | Get batch | GET /irs/orders/{orderId}/batches/{batchId} | (x) | x
| Job processing | Register job | POST /irs/jobs | x | x
| | Get jobs | GET /irs/jobs | x | x
| | Get job | GET /irs/jobs/{jobId} | x | x
| | Cancel job | PUT /irs/jobs/{jobId} | x | x
| Batch processing | Register order | POST /irs/orders | x | x
| | Get order | GET /irs/orders/{orderId} | x | x
| | Cancel order | PUT /irs/orders/{orderId} | x | x
| | Get batch | GET /irs/orders/{orderId}/batches/{batchId} | x | x
| Environmental- and
Social Standards | Register investigation job | POST /ess/bpn/investigations | (x) | x
| | Get investigation job | GET /ess/bpn/investigations{id} | (x) | x
Social Standards | Register investigation job | POST /ess/bpn/investigations | x | x
| | Get investigation job | GET /ess/bpn/investigations{id} | x | x
| | Accept notifications | POST /ess/notification/receive | x | x
|===

Legend: x = full access to all resources, (x) = access to the resources he owns

=== IRS OAuth2 JWT Token

IRS expects the JWT access token to have the following structure to be able to extract role information:

[source,json]
----
{
...
"resource_access": {
"Cl20-CX-IRS": {
"roles": [
"view_irs",
"admin_irs"
]
}
},
...
}
----

The field names can be configured via application.yaml:

[source,yaml]
----
# OAuth2 JWT token parse config. This configures the structure IRS expects when parsing the IRS role of an access token.
oauth:
resourceClaim: "resource_access" # Name of the JWT claim for roles
irsNamespace: "Cl20-CX-IRS" # Namespace for the IRS roles
roles: "roles" # Name of the list of roles within the IRS namespace
----
Legend: x = full access to all resources

=== IRS as DTR client

The IRS acts as a client for the Digital Twin Registry (DTR), which is also secured using OAuth2.0 / Open ID Connect.
The IRS acts as a client for the Digital Twin Registry (DTR), which is secured using OAuth2.0 / Open ID Connect.
The IRS uses client credentials to authenticate requests to the DTR.
Due to this, the IRS account needs to have access to every item in the DTR, unrelated to the permissions of the account calling the IRS API.

Expand Down
10 changes: 6 additions & 4 deletions irs-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
Expand Down Expand Up @@ -207,6 +203,12 @@
<version>${wiremock-standalone.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.cache.annotation.EnableCaching;
Expand All @@ -37,7 +39,7 @@
/**
* Application entry point.
*/
@SpringBootApplication(exclude = WebSocketServletAutoConfiguration.class)
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class, WebSocketServletAutoConfiguration.class })
@EnableScheduling
@EnableCaching
@EnableAsync
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private void registerOverallHealthMetric(final MeterRegistry registry,
log.debug("Registering metric '{}'", metricDescriptor.name);

final ToDoubleFunction<DependenciesHealthIndicator> statusProvider = //
healthIndicator -> HealthStatusHelper.healthStatustoNumeric(overallStatus(healthIndicator));
healthIndicator -> HealthStatusHelper.healthStatusToNumeric(overallStatus(healthIndicator));

Gauge.builder(metricDescriptor.name, dependenciesHealthIndicator, statusProvider)
.description(metricDescriptor.description())
Expand Down Expand Up @@ -103,7 +103,7 @@ private void registerIrsDependencyHealthMetric(final MeterRegistry registry,
log.debug("Registering metric '{}' tag '{}'", metricDescriptor.name, dependencyName);

final ToDoubleFunction<DependenciesHealthIndicator> statusProvider = //
healthIndicator -> HealthStatusHelper.healthStatustoNumeric(
healthIndicator -> HealthStatusHelper.healthStatusToNumeric(
getIrsDependencyStatus(healthIndicator, dependencyName));

Gauge.builder(metricDescriptor.name, dependenciesHealthIndicator, statusProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private void registerIrsHealthMetrics(final MeterRegistry registry, final Health
log.debug("Registering metric '{}'", metricName);

final ToDoubleFunction<? super HealthEndpoint> statusProvider = //
healthEndpoint -> HealthStatusHelper.healthStatustoNumeric(getIrsStatus(healthEndpoint));
healthEndpoint -> HealthStatusHelper.healthStatusToNumeric(getIrsStatus(healthEndpoint));

Gauge.builder(metricName, irsHealthEndpoint, statusProvider)
.description("The IRS health status.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class HealthStatusHelper {
* @param status the health status
* @return the numeric representation of the health status
*/
public static int healthStatustoNumeric(final Status status) {
public static int healthStatusToNumeric(final Status status) {

// see Spring documentation - map health indicators to metrics:
// https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
Expand Down
Loading

0 comments on commit fc643dc

Please sign in to comment.