The aim of this document is to explain how to configure and deploy OperatorFabric.

1. Deployment

For now OperatorFabric consist of Docker images available either by compiling the project or by using images releases from Dockerhub

Service images are all based on openjdk:8-jre-alpine.

For simple one instance per service deployment, you can find a sample deployment as a docker-compose file here

To run OperatorFabric in development mode, see the development environment documentation .

2. Configuration

OperatorFabric has multiple services to configure.

See the architecture documentation for more information on the different services.

All services are SpringBoot applications and use jetty as an embedded servlet container. As such, they share some common configuration which is described in the following documentation:

Configuration is centralized in the config directory, the dev sub-directory is specific to development environments while the docker sub-directory is a specific configuration meant for use in a full docker environment.

2.1. Business service configuration

2.1.1. Shared business service configuration

The configuration shared by all business services is in a yaml file, you can find an example with the file /config/docker/common-docker.yml. In this file you will find, among others, the parameters below :

name default mandatory? Description

operatorfabric.businessLogActivated

false

no

Indicates whether or not operatorfabric should record business logs

2.1.2. Business service specific configurations

Each business service has a specific yaml configuration file. It should a least contain the name of the service:

spring:
  application:
    name: businessconfig

It can contain references to other services as well, for example :

users:
  ribbon:
    listOfServers: users:8080

Examples of configuration of each business service can be found either under config/docker or config/dev depending on the type of deployment you’re looking for.

2.1.2.1. Businessconfig service

The businessconfig service has this specific property :

name default mandatory? Description

operatorfabric.businessconfig.storage.path

null

no

File path to data storage folder

2.1.2.2. Users service

The user service has these specific properties :

name default mandatory? Description

operatorfabric.users.default.users

null

no

Array of user objects to create upon startup if they don’t exist

operatorfabric.users.default.user-settings

null

no

Array of user settings objects to create upon startup if they don’t exist

operatorfabric.users.default.groups

null

no

Array of group objects to create upon startup if they don’t exist

operatorfabric.users.default.entities

null

no

Array of entity objects to create upon startup if they don’t exist

2.1.2.3. Cards-publication service

The cards-publication service has this specific property :

name default mandatory? Description

checkPerimeterForResponseCard

true

no

If false, OperatorFabric will not check that a user has write rights on a process/state to respond to a card

2.2. Web UI Configuration

OperatorFabric Web UI service is built on top of a NGINX server. It serves the Angular SPA to browsers and act as a reverse proxy for other services.

2.2.1. NGINX configuration

An external nginx.conf file configures the OperatorFabric Nginx instance named web-ui service. Those files are mounted as docker volumes. There are two of them in OperatorFabric, one in config/dev and one in config/docker.

The one in config/dev is set with permissive CORS rules to enable web development using ng serve within the ui/main project.It’s possible to use ng serve with the one in config/docker version also. To do so use the conf file named nginx-cors-permissive.conf by configuring the /docker-compose.yml with the following line:

- "./nginx-cors-permissive.conf:/etc/nginx/conf.d/default.conf"

instead of:

- "./nginx.conf:/etc/nginx/conf.d/default.conf"

The line customized in the nginx configuration file must end with à semi-colon (';') otherwise the Nginx server will stop immediately

2.2.2. UI properties

The properties lie in the web-ui.json.The following table describes their meaning and how to use them. An example file can be found in the config/docker directory.

name default mandatory? Description

security.provider-realm

yes

The realm name in keycloak server settings page. This is used for the log out process to know which realm should be affected.

security.provider-url

yes

The keycloak server instance

security.logout-url

yes

The keycloak logout URL. Is a composition of: - Your keycloak instance and the auth keyword (ex: www.keycloakurl.com/auth), but we also support domains without auth (ex: www.keycloakurl.com/customPath) - The realm name (Ex: dev) - The redirect URL (redirect_uri): The redirect URL after success authentification

security.oauth2.flow.mode

PASSWORD

no

authentication mode, awailable options:

  • CODE: Authorization Code Flow;

  • PASSWORD: Direct Password Flow (fallback);

  • IMPLICIT: Implicit Flow.

security.oauth2.flow.provider

null

no

provider name to display on log in button

security.oauth2.flow.delegate-url

null

no

Url to redirect the browser to for authentication. Mandatory with:

  • CODE flow: must be the url with protocol choice and version as query parameters;

  • IMPLICIT flow: must be the url part before .well-known/openid-configuration (for example in dev configuration it’s localhost:89/auth/realms/dev).

feed.card.time.display

BUSINESS

no

card time display mode in the feed. Values :

  • BUSINESS: displays card with entire business period. It the fallback if the set value is none of the values listed here;

  • BUSINESS_START: displays card with business start date;

  • PUBLICATION: displays card with publication date;

  • LTTD: displays card with lttd date;

  • NONE: nothing displayed.

feed.timeline.hide

false

no

If set to true, the time line is not loaded in the feed screen. If the timeline is not loaded , the time filter on the feed is filtering on business date otherwise it is filtering on publish date.

feed.card.hideTimeFilter

false

no

Control if you want to show or hide the time filter in the feed page

feed.card.hideAckFilter

false

no

Control if you want to show or hide the acknowledgement filter in the feed page

feed.card.secondsBeforeLttdForClockDisplay

180

no

Number of seconds before lttd when a clock is activated in cards on the feed

feed.timeline.domains

["TR", "J", "7D", "W", "M", "Y"]

no

List of domains to show on the timeline, possible domains are : "TR", "J", "7D", "W", "M", "Y".

feed.notify

false

no

If set to true, new cards are notified in the OS through web-push notifications

playSoundForAlarm

false

no

If set to true, a sound is played when Alarm cards are added or updated in the feed

playSoundForAction

false

no

If set to true, a sound is played when Action cards are added or updated in the feed

playSoundForCompliant

false

no

If set to true, a sound is played when Compliant cards are added or updated in the feed

playSoundForInformation

false

no

If set to true, a sound is played when Information cards are added or updated in the feed

i18n.supported.locales

no

List of supported locales (Only fr and en so far)

i10n.supported.time-zones

no

List of supported time zones, for instance 'Europe/Paris'. Values should be taken from the TZ database.

archive.filters.page.size

10

no

The page size of archive filters

archive.filters.process.list

no

List of processes to choose from in the corresponding filter in archives

archive.filters.tags.list

no

List of tags to choose from in the corresponding filter in archives

settings.tags.hide

no

Control if you want to show or hide the tags filter in settings and feed page

settings.nightDayMode

false

no

if you want to activate toggle for night or day mode

settings.styleWhenNightDayModeDesactivated

no

style to apply if not using day night mode, possible value are DAY,NIGHT or LEGACY (black background and white timeline)

settings.infos.disable

no

Control if we want to disable/enable editing user email, description in the settings page

settings.infos.email

false

no

Control if we want to hide(true) or display(false or not specified) the user email in the settings page

settings.infos.description

false

no

Control if we want to hide(true) or display(false or not specified) the user description in the settings page

settings.infos.language

false

no

Control if we want to hide(true) or display(false or not specified) the language in the settings page

settings.infos.timezone

false

no

Control if we want to hide(true) or display(false or not specified) the timezone in the settings page

settings.infos.timeformat

false

no

Control if we want to hide(true) or display(false or not specified) the timeformat in the settings page

settings.infos.dateformat

false

no

Control if we want to hide(true) or display(false or not specified) the dateformat in the settings page

settings.infos.datetimeformat

false

no

Control if we want to hide(true) or display(false or not specified) the datetimeformat in the settings page

settings.infos.tags

false

no

Control if we want to hide(true) or display(false or not specified) the tags in the settings page

settings.infos.sounds

false

no

Control if we want to hide(true) or display(false or not specified) the checkboxes for sound notifications in the settings page

settings.about

none

no

Declares application names and their version into web-ui about section.
Each entry is a free key value followed by its name (a string of characters), its version (a string of characters) and its facultative rank of declaration (a number).
For OperatorFabric value, with 'OperatorFabric' as name and 0 as rank, the value of ${currentVersion} is the version of the current release, 1.3.0.RELEASE for example.
It should look like:

"operatorfabric": {
 "name":  "OperatorFabric",
 "version":  "1.3.0.RElEASE",
 "rank": 0
}

logo.base64

medium OperatorFabric icon

no

The encoding result of converting the svg logo to Base64, use this online tool to encode your svg. If it is not set, a medium (32px) OperatorFabric icon is displayed.

logo.height

32

no

The height of the logo (in px) (only taken into account if logo.base64 is set).

logo.width

150

no

The width of the logo (in px) (only taken into account if logo.base64 is set).

logo.limitSize

true

no

If it is true, the height limit is 32(px) and the width limit is 200(px), it means that if the height is over than 32, it will be set to 32, if the width is over than 200, it is set to 200. If it is false, no limit restriction for the height and the width.

title

OperatorFabric

no

Title of the application, displayed on the browser

navbar.hidden

["logging","monitoring"]

no

Lists the application menu to hide in the navbar.
The keys used are the route.path declared in the ${OF_HOME}ui/main/src/app/app-routing.module.ts file.
Currently the application routes are:

  • feed;

  • archives.

There will be two new routes with the release of the [OC-936]:

  • logging;

  • monitoring.

checkPerimeterForResponseCard

true

no

If false, OperatorFabric will not check that a user has write rights on a process/state to respond to a card.

User Settings default values

name

default

mandatory?

Description

settings.timeZone

no

Default user time zone for users (use

settings.timeFormat

LT

no

Default user time format (moment)

settings.dateFormat

LL

no

Default user date format (moment)

settings.dateTimeFormat

LL LT

no

Default user date format (moment)

settings.locale

en

no

Default user locale (use en if not set)

settings.default-tags

no

Default user list of filtered in tags

2.3. Security Configuration

Configure the security concern throughout several files:

  • nginx.conf of the nginx server

  • config/dev/common-dev.yml or config/docker/common-docker.yml, called common.yml in the following chapters

  • web-ui.json served by the web-ui service;

2.3.1. Authentication configuration

There are 3 OAuth2 Authentication flows available into OperatorFabric UI:

  • password grant: referred as PASSWORD mode flow;

  • code flow : referred as CODE mode flow;

  • implicit flow: referred as IMPLICIT mode flow.

2.3.1.1. Nginx Configuration

The UI calls need some mapping to reach the Authentication Provider. In the default OperatorFabric configuration it’s a docker keycloak instance, called keycloak in the project docker-compose.yml files.

There are 3 properties to configure within nginx.conf file:

  • $KeycloakBaseUrl: the base url of keycloak;

  • $OperatorFabricRealm: the realm configure within keycloak instance to provide authentication to OperatorFabric;

  • $ClientPairOFAuthentication: base64 encoded string of the pair of client authentication used by OperatorFabric to log to the Authentication Provider (keycloak). The cient-id and the client-secret are separated by a colon(':').

Example of the docker configuration

# Url of the Authentication provider
    set $KeycloakBaseUrl "http://keycloak:8080";
# Realm associated to OperatorFabric within the Authentication provider
    set $OperatorFabricRealm "dev";

# base64 encoded pair of authentication in the form of 'client-id:secret-id'
    set $ClientPairOFAuthentication "b3BmYWItY2xpZW50Om9wZmFiLWtleWNsb2FrLXNlY3JldA==" ;

where b3BmYWItY2xpZW50Om9wZmFiLWtleWNsb2FrLXNlY3JldA== is the base64 encoded string of opfab-client:opfab-keycloak-secret with opfab-client as client-id and opfab-keycloak-secret its client secret.

2.3.1.2. Configuration file common.yml
name default mandatory? Description

operatorfabric.security.oauth2.client-id

null

yes

Oauth2 client id used by OperatorFabric may be specific for each service

operatorfabric.security.jwt.login-claim

sub

no

Jwt claim is used as user login or id

operatorfabric.security.jwt.expire-claim

exp

no

Jwt claim is used as token expiration timestamp

spring.security.provider-url

null

no

The keycloak instance url.

spring.security.provider-realm

null

no

The realm name within the keycloak instance.

spring.security.oauth2.resourceserver.jwt.jwk-set-uri

null

yes

The url providing the certificat used to verify the jwt signature

example of common.yml

operatorfabric:
    security:
        oauth2:
            client-id: opfab-client
        jwt:
            login-claim: preferred_username
            expire-claim: exp
spring:
  security:
    provider-url: http://localhost:89
    provider-realm: dev
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: ${spring.security.provider-url}/auth/realms/${spring.security.provider-realm}/protocol/openid-connect/certs

where operatorfabric.security.jwt.expire-claim could have been omitted because having the same value as the default one and where jwt-set-uri reuses provider-url and provider-realm properties.

2.3.1.3. Configuration file web-ui.json

Nginx web server serves this file. OperatorFabric creates and uses a custom Docker image containing an Nginx server with a docker volume containing this file. The two docker-compose environments contain an example of it. The path in the image to it is /usr/share/nginx/html/opfab/web-ui.json.

For OAuth2 security concerns into this file, there are two ways to configure it, based on the Oauth2 chosen flow. There are several common properties:

  • security.provider-realm: OAuth2 provider realm under which the OpertaroFabric client is declared;

  • security.provider-url: url of the keycloak server instance.

  • security.logout-url: url used when a user is logged out of the UI;

  • security.oauth2.flow.provider: name of the OAuth2 provider;

  • security.oauth2.flow.delegate-url: url used to connect to the Authentication provider;

  • security.oauth2.flow.mode: technical way to be authenticated by the Autentication provider.

2.3.1.4. OAuth2 PASSWORD or CODE Flows

These two modes share the same way of declaring the delegate URL. CODE is the default mode of authentication for deploy docker-compose environment.

  • security.oauth2.flow.mode to PASSWORD or CODE;

  • security.oauth2.flow.delegate-url with the URL of the OAuth2 leading to the protocol used for authentication.

Example of Configuration For CODE Flow
{
    "security": {
      "oauth2": {
        "flow": {
          "mode": "CODE",
          "provider": "Opfab Keycloak",
          "delegate-url": "http://localhost:89/auth/realms/dev/protocol/openid-connect/auth?response_type=code&client_id=opfab-client"
      },
      "logout-url":"http://localhost:89/auth/realms/dev/protocol/openid-connect/logout?redirect_uri=http://localhost:2002/ui/",
    "provider-realm": "dev",
    "provider-url": "http://localhost:89"
    }
  }
}

Within the delegate-url property dev is the keycloak client realm of OperatorFabric. For keycloak instance used for development purposes, this delegate-url correspond to the realm under which the client opfab-client is registred. Here, the client-id value is opfab-client which is define as client under the realm named dev on the dev keycloak instance.

2.3.1.5. OAuth2 IMPLICIT Flow

It had its own way of configuration. To enable IMPLICIT Flow authentication the following properties need to be set:

  • security.oauth2.flow.mode to IMPLICIT;

  • security.oauth2.flow.delegate-url with the URL of the OAuth2 leading to the .well-known/openid-configuration end-point used for authentication configuration.

Example of configuration for IMPLICIT Flow
{
  "operatorfabric": {
    "security": {
      "oauth2": {
        "flow": {
          "mode": "IMPLICIT",
          "provider": "Opfab Keycloak",
          "delegate-url": "http://localhost:89/auth/realms/dev"
      },
      "logout-url":"http://localhost:89/auth/realms/dev/protocol/openid-connect/logout?redirect_uri=http://localhost:2002/ui/",
    "provider-realm": "dev",
    "provider-url": "http://localhost:89"
      }
    }
  }
}

Within the delegate-url property dev is the keycloak client realm of OperatorFabric. For keycloak instance used for development purposes, this delegate-url correspond to the realm under which the client opfab-client is registred. The url look up by the implicit ui mechanism is localhost:89/auth/realms/dev/.well-known/openid-configuration.

2.3.2. User creation

Setting automated user creation==. Creation user requires a user id. Given name and family name are optional.

name default mandatory? Description

operatorfabric.security.jwt.login-claim

sub

no

Jwt claim is used as a user login or id

operatorfabric.security.jwt.given-name-claim

given-name

no

Jwt claim is used to set the user’s given name

operatorfabric.security.jwt.family-name-claim

family-name

no

Jwt claim is used to set the user’s family name

2.3.3. Alternative way to manage groups (and/or entities)

By default, OperatorFabric manages groups (and/or entities) through the user's collection in the database. Another mode can be defined, the JWT mode. The groups (and/or entities) come from the authentication token. The administrator of the authentication service has to set what claims define a group (and/or entity). In the Operator-Fabric configuration, the opfab administrator has to set properties to retrieve those groups (and/or entities).

name default mandatory? Description

operatorfabric.security.jwt.groups.mode

OPERATOR_FABRIC

no

Set the group mode, possible values JWT or OPERATOR_FABRIC

operatorfabric.security.jwt.groups.rolesClaim.rolesClaimStandard.path

no

path in the JWT to retrieve the claim that defines a group

operatorfabric.security.jwt.groups.rolesClaim.rolesClaimStandardArray.path

no

path in the JWT to retrieve the claim that defines an array of groups

operatorfabric.security.jwt.groups.rolesClaim.rolesClaimStandardList.path

no

path in the JWT to retrieve the claim that defines a list of group

operatorfabric.security.jwt.groups.rolesClaim.rolesClaimStandardList.separator

no

set the separator value of the list of group

operatorfabric.security.jwt.groups.rolesClaim.rolesClaimCheckExistPath.path

no

path in the JWT to check if that path does exist, if it does, use the roleValue as a group

operatorfabric.security.jwt.groups.rolesClaim.rolesClaimCheckExistPath.roleValue

no

set the value of the group if the path exists

operatorfabric.security.jwt.entitiesIdClaim

no

set the name of the field in the token

operatorfabric.security.jwt.gettingEntitiesFromToken

no

boolean indicating if you want the entities of the user to come from the token and not mongoDB (possible values : true/false)

application.yml

operatorfabric:
  security:
    jwt:
      entitiesIdClaim: entitiesId
      gettingEntitiesFromToken: true
      groups:
        mode: JWT # value possible JWT | OPERATOR_FABRIC
        rolesClaim:
          rolesClaimStandard:
            - path: "ATTR1"
            - path: "ATTR2"
          rolesClaimStandardArray:
            - path: "resource_access/opfab-client/roles"
          rolesClaimStandardList:
            - path: "roleFieldList"
              separator: ";"
          rolesClaimCheckExistPath:
            - path: "resource_access/AAA"
              roleValue: "roleAAA"
            - path: "resource_access/BBB"
              roleValue: "roleBBB"

JWT example

{
  "jti": "5ff87583-10bd-4946-8753-9d58171c8b7f",
  "exp": 1572979628,
  "nbf": 0,
  "iat": 1572961628,
  "iss": "http://localhost:89/auth/realms/dev",
  "aud": [
    "AAA",
    "BBB",
    "account"
  ],
  "sub": "example_user",
  "typ": "Bearer",
  "azp": "opfab-client",
  "auth_time": 0,
  "session_state": "960cbec4-fcb2-47f2-a155-975832e61300",
  "acr": "1",
  "realm_access": {
    "roles": [
      "offline_access",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "AAA": {
      "roles": [
        "role_AAA"
      ]
    },
    "BBB": {
      "roles": [
        "role_BBB"
      ]
    },
    "opfab-client": {
      "roles": [
        "USER"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "openid ATTR2 email ATTR1 profile roleFieldList",
  "email_verified": false,
  "name": "example_firtstname example_lastname",
  "ATTR2": "roleATTR2",
  "ATTR1": "roleATTR1",
  "preferred_username": "example_user",
  "given_name": "example_firtstname",
  "entitiesId": "ENTITY1",
  "family_name": "example_lastname",
  "email": "example_user@mail.com",
  "roleFieldList": "roleA;roleB;roleC"
}

As the result, the group will be [ATTR1, ATTR2, roleA, roleB, roleC, USER, roleBBB, roleAAA]

2.3.4. Adding certification authorities or certificates to the Java keystore

If you’re using certificates (for example for Keycloak) that are not from a certification authority trusted by the JVM, this will cause errors such as this one:

Missing certificate error message

If that is the case, you can pass the additional authorities or certificates that you use to the containers at runtime.

To do so, put the relevant files (*.der files for example) under src/main/docker/certificates.

  1. This directory should only contain the files to be added to the keystore.

  2. The files can be nested inside directories.

  3. Each certificate will be added with its filename as alias. For example, the certificate in file mycertificate.der will be added under alias mycertificate. As a consequence, filenames should be unique or it will cause an error.

  4. If you need to add or remove certificates while the container is already running, the container will have to be restarted for the changes to be taken into account.

If you would like certificates to be sourced from a different location, replace the volumes declarations in the deploy docker-compose.yml file with the selected location:

volumes:
 - "path/to/my/selected/location:/certificates_to_add"

instead of

volumes:
 - "../../../../src/main/docker/certificates:/certificates_to_add"
The steps described here assume you’re running OperatorFabric in docker mode using the deploy docker-compose, but they can be adapted for single container deployments and development mode.

If you want to check that the certificates were correctly added, you can do so with the following steps:

  1. Open a bash shell in the container you want to check

    docker exec -it deploy_businessconfig_1 bash
  2. Run the following command

    $JAVA_HOME/bin/keytool -list -v -keystore /tmp/cacerts -storepass changeit

You can also look at the default list of authorities and certificates trusted by the JVM with this command:

$JAVA_HOME/bin/keytool -list -v -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

2.4. OperatorFabric Mongo configuration

We only use URI configuration for mongo through the usage of the spring.data.mongodb.uris, it allows us to share the same configuration behavior for simple or cluster configuration and with both spring classic and reactive mongo configuration. See mongo connection string for the complete URI syntax.

2.4.1. Define time to live for archived cards

By default, archived cards will remain stored in the database forever. It is possible to have them automatically removed after a specified duration by using the TTL index feature of mongoDB on their publishDate field.

For example, to have cards expire after 10 days (864000s), enter the following commands in the mongo shell:

use operator-fabric
db.archivedCards.createIndex( { "publishDate": 1 }, { expireAfterSeconds: 864000 } )
You cannot use createIndex() to change the value of expireAfterSeconds of an existing index. Instead use the collMod database command in conjunction with the index collection flag. Otherwise, to change the value of the option of an existing index, you must drop the index first and recreate.

3. RabbitMQ

3.1. Docker container

In development mode, the simplest way to deploy a RabbitMQ server is to create a RabbitMQ docker container. A docker-compose file is provided to allow quick setup of a convenient RabbitMQ server.

3.2. Server installation

This section is dedicated to production deployment of RabbitMQ. It is not complete and needs to be tailored to any specific production environment.

3.2.1. Download & Installation

Download and install RabbitMQ following the official procedure for the target environment

3.2.2. Used ports

If RabbitMQ may not bind to the following ports, it won’t start :

  • 4369: epmd, a peer discovery service used by RabbitMQ nodes and CLI tools

  • 5672, 5671: used by AMQP 0-9-1 and 1.0 clients without and with TLS

  • 25672: used for inter-node and CLI tools communication (Erlang distribution server port) and is allocated from a dynamic range (limited to a single port by default, computed as AMQP port + 20000). Unless external connections on these ports are really necessary (e.g. the cluster uses federation or CLI tools are used on machines outside the subnet), these ports should not be publicly exposed. See networking guide for details.

  • 35672-35682: used by CLI tools (Erlang distribution client ports) for communication with nodes and is allocated from a dynamic range (computed as server distribution port + 10000 through server distribution port + 10010). See networking guide for details.

  • 15672: HTTP API clients, management UI and rabbitmqadmin (only if the management plugin is enabled)

  • 61613, 61614: STOMP clients without and with TLS (only if the STOMP plugin is enabled)

  • 1883, 8883: (MQTT clients without and with TLS, if the MQTT plugin is enabled)

  • 15674: STOMP-over-WebSockets clients (only if the Web STOMP plugin is enabled)

  • 15675: MQTT-over-WebSockets clients (only if the Web MQTT plugin is enabled)

3.2.3. Production configuration

See the guide for production configuration guidelines

4. Users, Groups and Entities Administration

A new operator call John Doe, who has OAuth granted right to connect ot current OperatorFabric instance, need to receive cards within current OperatorFabric instance. As a user of OperatorFabric, he needs to be added to the system with a login (john-doe-operator), his firstName (John) and his lastName (Doe). operator As there is no Administration GUI for the moment, it must be performed through command line, as detailed in the Users API.

4.1. Users

4.1.1. List all users

First of all, list the users (who are the recipients in OperatorFabric) of the system with the following commands:

Httpie

http http://localhost:2103/users "Authorization:Bearer $token" "Content-Type:application/type"

cURL

curl -v http://localhost:2103/users -H "Authorization:Bearer $token" -H "Content-Type:application/type"

response

HTTP/1.1 200 OK

[
    {
        "firstName": null,
        "groups": [
            "ADMIN"
        ],
        "entities": [
            "ENTITY1",
            "ENTITY2"
        ],
        "lastName": null,
        "login": "admin"
    },
    {
        "firstName": null,
        "groups": [
            "RTE",
            "ADMIN",
            "CORESO",
            "TRANS",
            "TEST"
        ],
        "lastName": null,
        "login": "rte-operator"
    },
    {
        "firstName": null,
        "groups": [
            "ELIA"
        ],
        "lastName": null,
        "login": "elia-operator"
    },
    {
        "firstName": null,
        "groups": [
            "CORESO"
        ],
        "lastName": null,
        "login": "coreso-operator"
    },
    {
        "firstName": null,
        "groups": [
            "TSO1",
            "TRANS",
            "TEST"
        ],
        "entities": [
            "ENTITY1"
        ],
        "lastName": null,
        "login": "tso1-operator"
    },
    {
        "firstName": null,
        "groups": [
            "TSO2",
            "TRANS"
        ],
        "entities": [
            "ENTITY2"
        ],
        "lastName": null,
        "login": "tso2-operator"
    },
]

4.1.2. Create a new User

We are sure that no John-doe-operator exists in our OperatorFabric instance. We can add him in our OperatorFabric instance using the following command use httpie:

echo '{"login":"john-doe-operator","firstName":"Jahne","lastName":"Doe"}' | http POST http://localhost:2103/users "Authorization:Bearer $token" "Content-Type:application/json"

Or here cURL:

curl -X POST http://localhost:2103/users -H "Authorization:Bearer $token" -H "Content-Type:application/json" --data '{"login":"john-doe-operator","firstName":"Jahne","lastName":"Doe"}'

response

HTTP/1.1 200 OK

{
    "firstName": "Jahne",
    "lastName": "Doe",
    "login": "john-doe-operator"
}

4.1.3. Fetch user details

It’s always a good thing to verify if all the information has been correctly recorded in the system:

with httpie:

http -b http://localhost:2103/users/john-doe-operator "Authorization:Bearer $token" "Content-Type:application/json"

or with cURL:

curl http://localhost:2103/users/john-doe-operator -H "Authorization:Bearer $token" -H "Content-Type:application/json"

response

HTTP/1.1 200 OK

{
    "firstName": "Jahne",
    "groups": [],
    "entities": [],
    "lastName": "Doe",
    "login": "john-doe-operator"
}

4.1.4. Update user details

As shown by this result, the firstName of the new operator has been misspelled.We need to update the existing user with john-doe-operator login. To correct this mistake, the following commands can be used :

with httpie:

echo '{"login":"john-doe-operator","lastName":"Doe","firstName":"John"}' | http PUT http://localhost:2103/users/john-doe-operator "Authorization:Bearer $token" "Content-Type:application/json"

or with cURL:

curl -X PUT http://localhost:2103/users/john-doe-operator -H "Authorization:Bearer $token" -H "Content-Type:application/json" --data '{"login":"john-doe-operator","firstName":"John","lastName":"Doe"}'

response

HTTP/1.1 200 OK

{
    "firstName": "John",
    "lastName": "Doe",
    "login": "john-doe-operator"
}

4.2. Groups/Entities

All the commands below :

  • List groups

  • Create a new group

  • Fetch details of a given group

  • Update details of a group

  • Add a user to a group

  • Remove a user from a group

are available for both groups and entities. In order not to overload the documentation, we will only detail groups endpoints.

4.2.1. List groups (or entities)

This operator is the first member of a new group operator called the OPERATORS, which doesn’t exist for the moment in the system. As shown when we list the groups existing in the server.

Httpie

http http://localhost:2103/groups "Authorization:Bearer $token" "Content-Type:application/type"

cURL

curl http://localhost:2103/groups -H "Authorization:Bearer $token" -H "Content-Type:application/json"

response

HTTP/1.1 200 OK

[
    {
        "description": "The admin group",
        "name": "ADMIN group",
        "id": "ADMIN"
    },
    {
        "description": "RTE TSO Group",
        "name": "RTE group",
        "id": "RTE"
    },
    {
        "description": "ELIA TSO group",
        "name": "ELIA group",
        "id": "ELIA"
    },
    {
        "description": "CORESO Group",
        "name": "CORESO group",
        "id": "CORESO"
    },
    {
        "description": "TSO 1 Group",
        "name": "TSO1 group",
        "id": "TSO1"
    },
    {
        "description": "TSO 2 Group",
        "name": "TSO2 group",
        "id": "TSO2"
    },
    {
        "description": "Transnationnal Group",
        "name": "TRANS group",
        "id": "TRANS"
    }
]

4.2.2. Create a new group (or entity)

Firstly, the group called OPERATORS has to be added to the system using the following command:

using httpie:

echo '{"id":"OPERATORS","decription":"This is the brand new  group of operator"}' | http POST http://localhost:2103/groups "Authorization:Bearer $token" "Content-Type:application/json"

using cURL:

curl -X POST http://localhost:2103/groups -H "Authorization:Bearer $token" -H "Content-Type:application/json" --data '{"id":"OPERATORS","decription":"This is the brand new  group of operator"}'

response

HTTP/1.1 200 OK

{
    "description": null,
    "name": null,
    "id": "OPERATORS"
}

4.2.3. Fetch details of a given group (or entity)

The result returned seems strange, to verify if it’s the correct answer by displaying the details of the group called OPERATORS, use the following command:

using httpie:

http http://localhost:2103/groups/OPERATORS "Authorization:Bearer $token" "Content-Type:application/json"

using cURL:

curl http://localhost:2103/groups/OPERATORS -H "Authorization:Bearer $token" -H "Content-Type:application/json"

response

HTTP/1.1 200 OK

{
    "description": null,
    "name": null,
    "id": "OPERATORS"
}

4.2.4. Update details of a group (or entity)

The description is really null. After verification, in our first command used to create the group, the attribute for the description is misspelled. Using the following command to update the group with the correct spelling, the new group of operator gets a proper description:

with httpie:

echo '{"id":"OPERATORS","description":"This is the brand-new group of operator"}' | http -b PUT http://localhost:2103/groups/OPERATORS "Authorization:Bearer $token" "Content-Type:application/json"

with cURL:

curl -X PUT http://localhost:2103/groups/OPERATORS -H "Authorization:Bearer $token" -H "Content-Type:application/json" --data '{"id":"OPERATORS","description":"This is the brand-new group of operator"}'

response

{
    "description": "This is the brand-new group of operator",
    "name": null,
    "id": "OPERATORS"
}

4.2.5. Add a user to a group (or entity)

As both new group and new user are correct it’s time to make the user a member of the group . To achieve this, use the following command:

with httpie:

echo '["john-doe-operator"]' | http PATCH http://localhost:2103/groups/OPERATORS/users "Authorization:Bearer $token" "Content-Type:application/json"

with cURL:

curl -X PATCH http://localhost:2103/groups/OPERATORS/users -H "Authorization:Bearer $token" -H "Content-Type:application/json" --data '["john-doe-operator"]'

response

HTTP/1.1 200 OK

Let’s verify that the changes are correctly recorded by fetching the :

http http://localhost:2103/users/john-doe-operator "Authorization:Bearer $token" "Content-Type:application/json"

with cURL

curl http://localhost:2103/users/john-doe-operator -H "Authorization:Bearer $token" -H "Content-Type:application/json"

response

HTTP/1.1 200 OK

{
    "firstName": "John",
    "groups": ["OPERATORS"],
    "entities": [],
    "lastName": "Doe",
    "login": "john-doe-operator"
}

It’s now possible to send cards either specifically to john-doe-operator or more generally to the OPERATORS group.

4.2.6. Remove a user from a group (or entity)

When John Doe is no longer in charge of hypervising cards for OPERATORS group, this group has to be removed from his login by using the following command:

with httpie:

http DELETE http://localhost:2103/groups/OPERATORS/users/john-doe-operator "Authorization:Bearer $token"

with cURL:

curl -X DELETE -H "Authorization:Bearer $token" http://localhost:2103/groups/OPERATORS/users/john-doe-operator

response

HTTP/1.1 200 OK

{
	"login":"john-doe-operator","
	firstName":"John",
	"lastName":"Doe",
	"groups":[],
    "entities":[]
}

A last command to verify that OPERATORS is no longer linked to john-doe-operator:

with httpie:

http http://localhost:2103/users/john-doe-operator "Authorization:Bearer $token" "Content-Type:application/json"

with cURL:

curl http://localhost:2103/users/john-doe-operator -H "Authorization:Bearer $token" -H "Content-Type:application/json"

response

HTTP/1.1 200 OK

{
    "firstName": "John",
    "groups": [],
    "entities": [],
    "lastName": "Doe",
    "login": "john-doe-operator"

}

5. Service port table

By default all service built artifacts are configured with server.port set to 8080

If you run the services using bootRun Gradle task, the run_all.sh script or the full docker docker-compose (found under config/docker), the used ports are:

Port Service Forwards to Description

89

KeyCloak

89

KeyCloak api port

2002

web-ui

8080

Web ui and gateway (Nginx server)

2100

businessconfig

8080

Businessconfig management service http (REST)

2102

cards-publication

8080

Cards publication service http (REST)

2103

users

8080

Users management service http (REST)

2104

cards-consultation

8080

Cards consultation service http (REST)

4100

businessconfig

5005

java debug port

4102

cards-publication

5005

java debug port

4103

users

5005

java debug port

4104

cards-consultation

5005

java debug port

27017

mongo

27017

mongo api port

5672

rabbitmq

5672

amqp api port

15672

rabbitmq

15672

rabbitmq api port

6. Restricted operations (administration)

Some operations are restricted to users with the ADMIN role, either because they are administration operations with the potential to impact the OperatorFabric instance as a whole, or because they give access to information that should be private to a user.

Below is a quick recap of these restricted operations.

Users Service

Any action (read, create/update or delete) regarding a single user’s data (their personal info such as their first and last name, as well as their settings) can be performed either by the user in question or by a user with the ADMIN role.

Any action on a list of users or on the groups (or entities) (if authorization is managed in OperatorFabric) can only be performed by a user with the ADMIN role.

Businessconfig Service

Any write (create, update or delete) action on bundles can only be performed by a user with the ADMIN role. As such, administrators are responsible for the quality and security of the provided bundles. In particular, as it is possible to use scripts in templates, they should perform a security check to make sure that there is no XSS risk.

The ADMIN role doesn’t grant any special privileges when it comes to card consultation (be they current or archived), so a user with the ADMIN role will only see cards that have been addressed to them (or to one of their groups (or entities)), just like any other user.