Operator Web Service

Overview

A RESTful web service (also called a RESTful web API) is a web service implemented using HTTP(S) and the principles of REST (Representational State Transfer). REST requires the use of HTTP methods explicitly and in a way that is consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping:

  • POST: is used to create a resource on the server
  • GET: is used to retrieve a resource
  • PUT: is used to change the state of a resource or to update it
  • DELETE: is used to remove or delete a resource

The PKI web service is mainly based on two resources:

  • Profiles
  • ITS stations

In the different deployments of the PKI, the web service is generally protected with an OpenId Connect layer, for the authentication. Even if that part is not strictly speaking the REST API, the next section will describe how to get an authentication token and how to use it. Then, we will see the different requests associated with the resources.

Authentication

To get access, an HTTP(S) request should be sent:

  • using the method POST,
  • to the OpenId Connect service URL (should be given along with this document, can be different of the operator web service base URL),
  • sending an url-encoded form with this fields:
    • scope fixed to openid,
    • grant_type fixed to password,
    • client_id and client_secret (also given along with this document),
    • username and password of a registered account.

If the request is accepted, an HTTP response should be received, with a status code 200. The response should contain a payload in Json format, with a field access_token. In the next requests, addressed to the REST web service, an HTTP header should be added: Authorization: Bearer <access_token> where <access_token> is the value found in the response.

Of course, in the rest of the document, the HTTP header Authorization is implicit: it's not mentioned, but it should be present in every request.

Example

In this situation:

  • OpenId Connect access point: https://keycloak.c-its-pki.eu/auth/realms/idn-l0/protocol/openid-connect/token
  • client id: operator, client secret: 97793a4b-ae56-494c-9f4c-2f395cc35ab1
  • user name: myuser, password Password#1234

The following request should be sent (using the command line tool HTTPie), receiving this response (the values of access_token, id_token and refresh_token have been truncated):

$ http https://keycloak.c-its-pki.eu/auth/realms/idn-l0/protocol/openid-connect/token "scope=openid" "grant_type=password" "client_id=operator" "client_secret=97793a4b-ae56-494c-9f4c-2f395cc35ab1" "username=myuser" "password=Password#1234" -fv
POST /auth/realms/idn-l0/protocol/openid-connect/token HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 141
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Host: keycloak.c-its-pki.eu
User-Agent: HTTPie/1.0.3

scope=openid&grant_type=password&client_id=operator&client_secret=97793a4b-ae56-494c-9f4c-2f395cc35ab1&username=myuser&password=Password%231234

HTTP/1.1 200 OK
Cache-Control: no-store
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json
Date: Tue, 13 Oct 2020 13:41:32 GMT
Pragma: no-cache
Referrer-Policy: no-referrer
Server: openresty/1.15.8.1
Set-Cookie: KEYCLOAK_LOCALE=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/auth/realms/idn-l0/; HttpOnly
Set-Cookie: KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/auth/realms/idn-l0/; HttpOnly
Strict-Transport-Security: max-age=15724800; includeSubDomains
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAi[...]D7ewWLjhSTJXsfA",
    "expires_in": 300,
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldU[...]GzivenB7aTf_8kg",
    "not-before-policy": 0,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiA[...]5CDElob-7TUf7hs",
    "scope": "openid profile email",
    "session_state": "ffd527d8-76b7-4b5c-b955-870043c15f93",
    "token_type": "bearer"
}

Then, to use the token to get the list of the profiles, with the operator base URL at https://0.atos-op.l0.c-its-pki.eu:

$ http https://0.atos-op.l0.c-its-pki.eu/v1/profiles "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAi[...]D7ewWLjhSTJXsfA"
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json
Date: Tue, 13 Oct 2020 14:28:02 GMT
Expires: 0
Pragma: no-cache
Server: openresty/1.15.8.1
Set-Cookie: JSESSIONID=64D45A954860CCC37CA9C846C83F30F5; Path=/; Secure; HttpOnly
Strict-Transport-Security: max-age=15724800; includeSubDomains
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Xss-Protection: 1; mode=block

[
    {
        "assuranceLevel": 0,
        "atPreloadingDuration": 90,
        "atPreloadingUnit": "DAYS",
        "atValidityDuration": 7,
        "atValidityUnit": "DAYS",
        "confidenceLevel": 0,
        "ecValidityDuration": 3,
        "ecValidityUnit": "YEARS",
        "editAllowed": true,
        "groupId": "idn-l0.Atos",
        "id": "3f621d8e-f7a1-427f-bb34-b3c02e07d96c",
        "name": "TestProfile",
        "permissions": [
            {
                "opaque": false,
                "psid": 36,
                "ssp": "AQAA"
            }
        ],
        "privacyPolicy": "OPTIONAL"
    }
]

CSRF Token

GET requests: no need for a CSRF token, skip this step. POST/PUT/DELETE requests: require same CSRF token as a header and as a cookie header. Add the following headers using any random value:

"X-XSRF-TOKEN: MyRandomValue007"
"Cookie: XSRF-TOKEN=MyRandomValue007"

Profile

Profile format

In JSON format, a profile is an object with the fields:

  • id (string): Identifier of the profile (read only).
  • name (string): Name of the profile. This name is used during the registration of ITS stations.
  • ecValidityDuration (number): The maximum EC validity period. The value should be positive.
  • ecValidityUnit (string): The unit of the field ecValidityDuration. Can be "SECONDS", "MINUTES", "HOURS", "DAYS" or "YEARS".
  • atValidityDuration (number): The maximum AT validity period. The value should be positive.
  • atValidityUnit (string): The unit of the field atValidityDuration. Can be "SECONDS", "MINUTES", "HOURS", "DAYS" or "YEARS".
  • atPreloadingDuration (number): The maximum period between the moment of the request is received and the validity start of the requested AT. The value should be positive.
  • atPreloadingUnit (string): The unit of the field atPreloadingDuration. Can be "SECONDS", "MINUTES", "HOURS", "DAYS" or "YEARS".
  • assuranceLevel (number): Define the assurance level part of the maximum subject assurance. The value should be between 0 and 7.
  • confidenceLevel (number): Define the confidence level part of the maximum subject assurance. The value should be between 0 and 3.
  • privacyPolicy (string): The acceptable format (encrypted or not) of the detached signature in the AT request. Can be "OPTIONAL", "WITHOUT_PRIVACY" or "WITH_PRIVACY".
  • permissions (array of objects): An array of PSID/SSP that an ITS can exactly request. Each object is defined by:
    • psid (number): The PSID (decimal format).
    • ssp (string): The SSP, in base 64.
    • opaque (boolean): true if the SSP is defined as opaque, false if it is defined as a bit mask.
  • groupId (string): The security group of the profile. Can be choose in the accessible groups of the authenticated user (format: <realm>.<group>).
  • editAllowed (boolean): true if the profile can be edited (read only).

Example :

{
    "id": "d4989cf0-4145-41b1-b96b-2e484f1c2e09",
    "name": "DefaultProfile",
    "ecValidityDuration": 3,
    "ecValidityUnit": "YEARS",
    "atValidityDuration": 7,
    "atValidityUnit": "DAYS",
    "atPreloadingDuration": 30,
    "atPreloadingUnit": "DAYS",
    "assuranceLevel": 0,
    "confidenceLevel": 0,
    "privacyPolicy": "OPTIONAL",
    "groupId": "idn-l0.Atos",
    "permissions": [
        {
            "psid": 36,
            "ssp": "Af/8",
            "opaque": false
        },
        {
            "psid": 37,
            "ssp": "AQAAAA==",
            "opaque": false
        }
    ],
    "editAllowed": true
}

Save a profile

  • Request: POST /v1/profiles
  • Request body: A profile in JSON format (without the read only fields)
  • Response:
  • 201: Profile created. The header Location is set to the complete location of the created resource. The body contains the newly created profile.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

Retrieve a profile

  • Request: GET /v1/profiles/{id}
  • Parameters:
  • {id}: The id of the profile
  • Response :
  • 200: The profile has been retrieved. The body contains the requested profile in JSON format.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

List all profiles

  • Request: GET /v1/profiles/
  • Response :
  • 200: The profiles have been retrieved. The body contains the list of profiles in JSON format.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

Update a profile

  • Request: PUT /v1/profiles/{id}
  • Parameters:
  • {id}: The id of the profile
  • Request body: The new profile value in JSON format (without the read only fields)
  • Response :
  • 200: The profile has been updated. The body contains the saved profile in JSON format.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

Delete a profile

  • Request: DELETE /v1/profiles/{id}
  • Parameters:
  • {id}: The id of the profile
  • Response :
  • 200: The profile has been deleted.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

ITS stations

ITS station format

In JSON format, an ITS station is an object with the fields:

  • id (string): Identifier of the ITS station (read only).
  • prefixId (string): First part of the canonical id of the ITS station, in ASCII. Can be empty if serialId is not empty.
  • serialId (string): End part of the canonical id of the ITS station, in base 64. Can be empty if prefixId if not empty.
  • canonicalName (string): Human readable representation of the canonical id of the ITS station (read only).
  • canonicalId (string): Base 64 representation of the canonical id of the ITS station (read only).
  • technicalPublicKey (string): The technical public key, in a X.509 public key format, in base 64.
  • status (string): The ITS station status. Can be "REGISTERED", "ACTIVATED", "SUSPENDED" or "DEACTIVATED".
  • profile (string): The name (not the id) of the profile of the ITS station.
  • tags (list of string): Tags associated with the ITS station.
  • ecNumber (number): Total number of EC requested by the ITS station (read only).

Example:

{
    "id": "4a5e179f-1e72-453a-8923-c85a9a8c1d0a",
    "prefixId": "ITS-STATION",
    "serialId": "AAE=",
    "canonicalName": "ITS-STATION.0001",
    "canonicalId": "SVRTLVNUQVRJT04AAQ==",
    "technicalPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWpBjhoHafQvkZjE6VlmSuv6YWidgFR4Ohisrs5GoVdE1YI5prKz3ckJzaoZwnRgB74mpcEJEeJjftS64FBPoOQ==",
    "status": "ACTIVATED",
    "profile": "DefaultProfile",
    "tags": [
        "PREPRODUCTION"
    ],
    "ecNumber": 1
}

Save an ITS station

  • Request: POST /v1/its
  • Request body: An ITS station in JSON format (without the read only fields)
  • Response:
  • 201: ITS station created. The header Location is set to the complete location of the created resource. The body contains the newly created ITS station.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

Retrieve an ITS station

  • Request: GET /v1/its/{id}
  • Parameters:
  • {id}: The id of the ITS station
  • Response :
  • 200: The ITS station has been retrieved. The body contains the requested ITS station in JSON format.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

List all ITS station

  • Request: GET /v1/its/?size={size}&page={page}
  • Parameters:
  • {size}: Maximal number of ITS station returned. Optional, default set to 20.
  • {page}: Page number. Optional, default set to 0.
  • Response :
  • 200: The ITS station has been retrieved. The body contains the requested ITS stations and some metadata about pages in JSON format:
    • content (list of objects): the list of ITS stations found in the requested page.
    • number (number): number of the current page.
    • numberOfElements (number): number of ITS stations in this page.
    • size (number): maximum size in a page.
    • sort (null): not used, always null.
    • first (boolean): true if it is the first page, false otherwise.
    • last (boolean): true if it is the last page, false otherwise.
    • totalPages (number): total number of pages.
    • totalElements (number): total number of ITS stations found.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

Update an ITS station

  • Request: PUT /v1/its/{id}
  • Parameters:
  • {id}: The id of the ITS station
  • Request body: The new station value in JSON format (without the read only fields)
  • Response :
  • 200: The ITS station has been updated. The body contains the saved station in JSON format.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.

Delete an ITS station

  • Request: DELETE /v1/its/{id}
  • Parameters:
  • {id}: The id of the ITS station
  • Response :
  • 200: The ITS station has been deleted.
  • 400: An error occurs. The body returns a structure containing an error description:
    • id (string): a code ID corresponding to the error.
    • description (string): human readable description of the error.
    • params (object): parameters related to the error.
  • other: see the HTTP standard.