Skip to content

Commit

Permalink
Merge pull request #88 from com-pas/develop
Browse files Browse the repository at this point in the history
Merge branch 'develop' into main
  • Loading branch information
Flurb authored Sep 7, 2021
2 parents f71cef5 + da25e8a commit bfa5366
Show file tree
Hide file tree
Showing 30 changed files with 868 additions and 222 deletions.
35 changes: 35 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# SPDX-FileCopyrightText: 2021 Alliander N.V.
#
# SPDX-License-Identifier: Apache-2.0

version: 2

registries:
maven-github:
type: maven-repository
url: https://maven.pkg.github.com/com-pas/*
username: OWNER
password: ${{ secrets.DB_GITHUB_PACKAGES }}

updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 5

# Maintain dependencies for Maven
- package-ecosystem: "maven"
directory: "/"
registries:
- maven-github
schedule:
interval: "daily"
open-pull-requests-limit: 5
ignore:
# Next two dependencies shouldn't be upgrade, because Quarkus isn't using newer version of EL.
- dependency-name: org.hibernate.validator:hibernate-validator
versions: [ "[7.0,)" ]
- dependency-name: org.glassfish:jakarta.el
versions: [ "[4.0,)" ]
5 changes: 3 additions & 2 deletions .github/workflows/build-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.11
uses: actions/setup-java@v1
uses: actions/setup-java@v2.3.0
with:
java-version: 1.11
distribution: 'zulu'
java-version: '11'
- name: Create custom Maven Settings.xml
uses: whelk-io/maven-settings-xml-action@v18
with:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/release-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ jobs:
shell: bash
# Extra the tagname form the git reference, value of GITHUB_REF will be something like refs/tags/<tag_name>.
run: echo "##[set-output name=tagname;]$(echo ${GITHUB_REF##*/})"
- uses: actions/setup-java@v2
- name: Set up JDK 1.11
uses: actions/setup-java@v2.3.0
with:
distribution: 'zulu'
java-version: '11'
distribution: 'adopt'
- name: Create custom Maven Settings.xml
uses: whelk-io/maven-settings-xml-action@v18
with:
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/sonarcloud-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v1
- name: Set up JDK 1.11
uses: actions/setup-java@v2.3.0
with:
java-version: 1.11
distribution: 'zulu'
java-version: '11'
- name: Cache SonarCloud packages
uses: actions/cache@v1
uses: actions/cache@v2.1.6
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v1
uses: actions/cache@v2.1.6
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
Expand Down
83 changes: 76 additions & 7 deletions MAPPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,31 @@ There is an IEC document describing the mapping, namely IEC/TS 62361-102, but no
| id | name | |
| name | desc | |
| List&lt;cim:VoltageLevel&gt; | List&lt;TVoltageLevel&gt; | (1) |
| List&lt;*PowerTransformer*&gt; | List&lt;TPowerTransformer&gt; | |

(1): The list of VoltageLevels that belong to the Substation.

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:VoltageLevel* | *TVoltageLevel* | |
| name or id | name | |
| '0' | nomFreq | (1) |
| nominalV | voltage.value | |
| 'k' | voltage.multiplier | |
| 'V' | voltage.unit | |
| List&lt;Bay&gt; | List&lt;TBay&gt; | (1) |
| List&lt;Bay&gt; | List&lt;TBay&gt; | (2) |
| List&lt;*PowerTransformer*&gt; | List&lt;TPowerTransformer&gt; | |

(1): The list of Bays that belong to the VoltageLevel.
(1): The nomFreq will be set to 0 if there is a Switch connected to it of the type 'DCLineSegment'.
(2): The list of Bays that belong to the VoltageLevel.

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:Bay* | *TBay* | |
| name or id | name | |
| List&lt;cim:ConnectivityNode&gt; | List&lt;TConnectivityNode&gt; | (1) |
| List&lt;*Switches*&gt; | List&lt;TConductingEquipment&gt; | (2) |
| List&lt;*PowerTransformer*&gt; | List&lt;TPowerTransformer&gt; | |

(1): ConnectivityNode in IEC CIM can be linked to a Bay, but also to the VoltageLevel. In IEC 61850 a ConnectivityNode
can only be added to a Bay, so also the ConnectivityNode from the VoltageLevel are added to the Bay. This causes those
Expand All @@ -46,7 +51,30 @@ ProtectedSwitch.These classes are all mapped in the same way on IEC 61850

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:ConnectivityNode* | *TConnectivityNode | |
| *cim:PowerTransformer* | *TPowerTransformer* | |
| name or id | name | |
| description | desc | |
| 'PTR' | type | |

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:PowerTransformerEnd* | *TTransformerWinding* | |
| name or id | name | |
| 'PTW' | type | |
| Terminal | List&lt;TTerminal&gt; | (1) |

(1): The terminal found in IEC CIM will be added as List to IEC 61850.

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:RatioTapChanger* | *TTapChanger* | |
| *cim:PhaseTapChanger* | *TTapChanger* | |
| name or id | name | |
| 'LTC' | type | |

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:ConnectivityNode* | *TConnectivityNode* | |
| name or id | name | |
| - | pathName | (1) |

Expand All @@ -56,22 +84,63 @@ ConnectivityNode.

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *Switches* | *TConductingEquipment | (1) |
| *Switches* | *TConductingEquipment* | (1) |
| name or id | name | |
| type | type | (2) |
| List&lt;cim:Terminal&gt; | List&lt;TTerminal&gt; | (3) |

(1): Switches in IEC CIM can be the following types, cim:Switch cim:Breaker cim:Disconnector cim:LoadBreakSwitch cim:
ProtectedSwitch.These classes are all mapped in the same way on IEC 61850
(2): The mapping between types is described in 5.6.2 of IEC/TS 62361-102.
ProtectedSwitch.These classes are all mapped in the same way on IEC 61850
(2): The mapping between types is described in 5.6.2 of IEC/TS 62361-102. Below is a table describing how the mapper
implements this mapping.
(3): The list of Terminal that belong to the Switch.

| CIM Class | IEC Class | Remark |
| -------------------------------- | -------------------------------- | --------- |
| *cim:Terminal* | *TTerminal | |
| *cim:Terminal* | *TTerminal* | |
| name or id | name | |
| - | connectivityNode | (1) |
| - | CNodeName | (1) |

(1): Use the ID of the ConnectivityNode to find the name or pathName of that ConnectivityNode. A map is saved of all
ConnectivityNode that are processed for each Bay.

## Mapping from Cim Switch Type to IEC TConductingEquipment

| IEC 61850 Type | CIM Type |
| --------------- | --------------------- |
| BSH | Connector |
| CAB | ACLineSegment |
| CAB | DCLineSegment |
| CAP | ShuntCompensator |
| CAP | SeriesCompensator |
| CBR | ProtectedSwitch |
| CBR | Breaker |
| CBR | Recloser |
| CON | FrequencyConverter |
| CTR | CurrentTransformer |
| DIS | Switch |
| DIS | Disconnector |
| DIS | Fuse |
| DIS | Jumper |
| DIS | LoadBreakSwitch |
| DIS | GroundDisconnector |
| DIS | Sectionaliser |
| EFN | PetersenCoil |
| GEN | GeneratingUnit |
| LTC | TapChanger |
| LTC | RatioTapChanger |
| LTC | PhaseTapChanger |
| MOT | AsynchronousMachine |
| PSH | GroundingImpedance |
| PTR | PowerTransformer |
| PTW | TransformerEnd |
| PTW | PowerTransformerEnd |
| PTW | TransformerTankEnd |
| RES | EarthFaultCompensator |
| SAR | SurgeArrester |
| SCR | ACDCConverter |
| SMC | SynchronousMachine |
| TCR | StaticVarCompensator |
| TNK | TransformerTank |
| VTR | PotentialTransformer |
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,26 @@ You can then execute your native executable with: `./app/target/code-with-quarku

If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html
.

## Environment variables

Below environment variable(s) can be used to configure which claims are used to fill user information, for instance Who
in History Record.

| Environment variable | Java Property | Description | Example |
| -------------------------------- | ------------------------------ | --------------------------------------------- | ---------------- |
| USERINFO_WHO_CLAIMNAME | compas.userinfo.who.claimname | The Name of the user used in the Who History. | name |

## Security

To use most of the endpoints the users needs to be authenticated using JWT in the authorization header. There are 4
environment variables that can be set in the container to configure the validation/processing of the JWT.

| Environment variable | Java Property | Description | Example |
| -------------------------------- | -------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------- |
| JWT_VERIFY_KEY | smallrye.jwt.verify.key.location | Location of certificates to verify the JWT. | http://localhost:8089/auth/realms/compas/protocol/openid-connect/certs |
| JWT_VERIFY_ISSUER | mp.jwt.verify.issuer | The issuer of the JWT. | http://localhost:8089/auth/realms/compas |
| JWT_VERIFY_CLIENT_ID | mp.jwt.verify.audiences | The Client ID that should be in the "aud" claim. | cim-mapping |
| JWT_GROUPS_PATH | smallrye.jwt.path.groups | The JSON Path where to find the roles of the user. | resource_access/cim-mapping/roles |

There are no roles defined in this service, only need to be authenticated.
4 changes: 2 additions & 2 deletions app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ SPDX-License-Identifier: Apache-2.0
<packaging>jar</packaging>

<properties>
<quarkus.platform.version>2.0.0.Final</quarkus.platform.version>
<quarkus.platform.version>2.2.1.Final</quarkus.platform.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -94,7 +94,7 @@ SPDX-License-Identifier: Apache-2.0
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security</artifactId>
<artifactId>quarkus-test-security-jwt</artifactId>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2021 Alliander N.V.
//
// SPDX-License-Identifier: Apache-2.0
package org.lfenergy.compas.cim.mapping.rest;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithName;

@ConfigMapping(prefix = "compas.userinfo")
public interface UserInfoProperties {
@WithName("who.claimname")
String who();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
package org.lfenergy.compas.cim.mapping.rest.v1;

import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.SecurityIdentity;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.lfenergy.compas.cim.mapping.rest.UserInfoProperties;
import org.lfenergy.compas.cim.mapping.rest.v1.model.MapRequest;
import org.lfenergy.compas.cim.mapping.rest.v1.model.MapResponse;
import org.lfenergy.compas.cim.mapping.service.CompasCimMappingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
Expand All @@ -22,10 +25,15 @@
@RequestScoped
@Path("/cim/v1/")
public class CompasCimMappingResource {
private static final Logger LOGGER = LoggerFactory.getLogger(CompasCimMappingResource.class);

private CompasCimMappingService compasCimMappingService;

@Inject
SecurityIdentity securityIdentity;
JsonWebToken jsonWebToken;

@Inject
UserInfoProperties userInfoProperties;

@Inject
public CompasCimMappingResource(CompasCimMappingService compasCimMappingService) {
Expand All @@ -37,8 +45,11 @@ public CompasCimMappingResource(CompasCimMappingService compasCimMappingService)
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public MapResponse mapCimToScl(@Valid MapRequest request) {
String who = jsonWebToken.getClaim(userInfoProperties.who());
LOGGER.trace("Username used for Who {}", who);

var response = new MapResponse();
response.setScl(compasCimMappingService.map(request.getCimData(), securityIdentity.getPrincipal()));
response.setScl(compasCimMappingService.map(request.getCimData(), who));
return response;
}
}
2 changes: 2 additions & 0 deletions app/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#
# SPDX-License-Identifier: Apache-2.0

compas.userinfo.who.claimname = ${USERINFO_WHO_CLAIMNAME:name}

quarkus.http.cors = false
quarkus.http.root-path = /compas-cim-mapping/
quarkus.http.limits.max-body-size = 150M
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectMock;
import io.quarkus.test.security.TestSecurity;
import io.quarkus.test.security.jwt.Claim;
import io.quarkus.test.security.jwt.JwtSecurity;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
import org.lfenergy.compas.cim.mapping.model.CimData;
Expand All @@ -18,7 +20,6 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Principal;
import java.util.List;

import static io.restassured.RestAssured.given;
Expand All @@ -32,6 +33,10 @@
@QuarkusTest
@TestHTTPEndpoint(CompasCimMappingResource.class)
@TestSecurity(user = "test-mapper")
@JwtSecurity(claims = {
// Default the claim "name" is configured for Who, so we will set this claim for the test.
@Claim(key = "name", value = "Test User")
})
class CompasCimMappingResourceTest {
@InjectMock
private CompasCimMappingService compasCimMappingService;
Expand All @@ -47,7 +52,7 @@ void mapCimToScl_WhenCalled_ThenCorrectMessageIsRetrieved() throws IOException {

var scl = new SCL();
scl.setVersion("2007");
when(compasCimMappingService.map(any(), any(Principal.class))).thenReturn(scl);
when(compasCimMappingService.map(any(), eq("Test User"))).thenReturn(scl);

var response = given()
.contentType(ContentType.XML)
Expand All @@ -65,7 +70,7 @@ void mapCimToScl_WhenCalled_ThenCorrectMessageIsRetrieved() throws IOException {
var sclVersion = xmlPath.getString("cms:MapResponse.scl:SCL.@version");
assertNotNull(sclVersion);
assertEquals("2007", sclVersion);
verify(compasCimMappingService, times(1)).map(any(), any(Principal.class));
verify(compasCimMappingService, times(1)).map(any(), eq("Test User"));
}

private String readFile() throws IOException {
Expand Down
Loading

0 comments on commit bfa5366

Please sign in to comment.