REST API Examples

1. General

1.1. User Authentication with Keycloak

The preconfigured authentication flow in Keycloak supports X.509 certificate user authentication, cookie authentication and username/password login. The certificates used for user authentication must be certificates signed by a CA trusted by Keycloak. In order to use RA Certificates produced from MTG CARA for user authentication, the MTG CARA RA Root CA must be trusted by Keycloak.

Keycloak supports the OpenID Connect protocol and can delegate authentication and identity management operations to a third party centralized server.

1.1.1. OAuth2 Flows

Formalising the concepts standardised by the [RFC6749] protocol for OAuth 2.0 framework, openid connect defines four main flows that can be used to authenticate a user:

  • Authorization Code Flow for browser-based applications like SPAs (Single Page Applications) or server-side application;

  • Implicit Flow for browser-based application, less secure than the previous one, not recommended and deprecated in OAuth 2.1;

  • Client Credentials Grant for REST clients like web services, it involves storing a secret, so the client is supposed to be trustworthy;

  • Resource Owner Password Credentials Grant for REST clients like interfaces to mainframes and other legacy systems which cannot support modern authentication protocols, it involves sharing credentials with another service, caution here.

1.2. MTG API Calls

In order for some basic API Calls to be completed successfully (e.g. creating a new realm), a user with admin rights has to be logged in, using the following:

  • Provider Client Id (Type: UUID)

  • Client Secret (Type: String)

These could be retrieved easily from Keycloak.

2. Admin Login

Listing 1 shows a code snippet for the Login process in Java.

Listing 1. Login as User - Java snippet
private void login() {

    LoginWithSecretRequest loginUserDto =
        new LoginWithSecretRequest()
            .clientId("< provider client id >")
            .clientSecret("< client secret >");
    clmClient.login(loginUserDto);
}

Listing 2 shows how to retrieve the Authentication Token needed when running cURL commands:

Listing 2. Retrieve authentication token using cURL
curl --location --request POST '< base url >/auth/realms/mtg-ers/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=< username >' \
--data-urlencode 'password=< password >' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=< client id >' \
--data-urlencode 'client_secret=< client secret >' \
--data-urlencode 'scope=openid'

3. Create a Realm

Realm is a responsibility area that offers separation of concerns for the management of digital certificates. It is necessary for the creation of every component provided by the API, such as a new policy or an end-entity.

Listing 3 shows a code snippet for the creation of realm in Java.

Listing 3. Create a realm - Java snippet
private CreateRealmResponseDto createRealm() {

    var createRealmRequestDto = new CreateRealmRequestDto()
        .name("simple-api-realm")

    return Objects.requireNonNull(clmClient.getRealmApi()
        .createNewRealm(createRealmRequestDto)
        .block());
}

Listing 4 shows the creation of a realm using cURL.

Listing 4. Create a realm in cURL
curl --location --request POST '< base url >/api/v1/realms/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer < token from keycloak >' \
--data '{
  "name": "< realm name >"
}'

4. Create a Policy in a Realm

A policy specifies the rules on how certificates are created. It identifies the CA that will issue the certificate, the template that will be used and also can contain additional restrictions/configurations for the certificate lifecycle.

Listing 5 shows a code snippet for the creation of a policy in Java.

Listing 5. Create a policy - Java snippet
private CreatePolicyResponseDto createPolicy(UUID realmId,
        UUID providerId, String certProviderConfig) {

    var cryptoRestrictionsDto = new CryptoRestrictionsDto()
        .allowedCryptoAlgorithms(List.of(
            CryptoAlgorithm.RSA,
            CryptoAlgorithm.EC));

    var createPolicyRequestDto = new CreatePolicyRequestDto()
        .certificateProviderId(providerId)
        .certificateProviderConfiguration(certProvideronfig)
        .realmId(realmId)
        .name("simple-api-policy")
        .requiresManualApproval(false)
        .allowedKeyPairModes(Set.of(KeyPairMode.values()))
        .allowedValidForValues(Set.of(ValidFor.values()))
        .cryptoRestrictions(cryptoRestrictions)
        .endEntityStrategy(EndEntityStrategy.COMMON_NAME);

    return Objects.requireNonNull(clmClient.getPolicyApi()
        .createNewPolicy(createPolicyRequestDto)
        .block());
}

Listing 6 shows the creation of a policy using cURL

Listing 6. Create a policy in cURL
curl --location --request POST '< base url >/api/v1/policies/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer < token from keycloak >' \
--data '{
  "allowedKeyPairModes": [
    "SERVER_GEN"
  ],
  "allowedValidForValues": [
    "SIX_MONTHS"
  ],
  "certificateProviderConfiguration": "{\"templateSignerName\":\"Email\"}",
  "certificateProviderId": "< existing certificate provider id >",
  "cryptoRestrictions": {
    "allowedCryptoAlgorithms": [
        "RSA"
    ]
  },
  "endEntityStrategy": "COMMON_NAME",
  "name": "< policy name >",
  "realmId": "< existing realm id >"
}'

5. Create an End-Entity

An end-entity is the owner of a certificate. This is the PKI participant for whom the digital certificate is issued for.

Listing 7 shows a code snippet for the creation of an end-entity in Java.

Listing 7. Create an end-entity - Java snippet
private CreateEndEntityResponseDto createEndEntity(UUID realm) {

    CreateEndEntityRequestDto createEndEntityRequestDto = new CreateEndEntityRequestDto()
            .realmId(realm)
            .commonName("simple-api-ee")

    return Objects.requireNonNull(clmClient.getEndEntityApi().createNewEndEntity(createEndEntityRequestDto).block());
}

Listing 8 shows the creation of an end-entity using cURL

Depending on the selected End Entity Strategy in corresponding Policy, in option --data one more field will also be required except realm-id. For instance, when using the previously created Policy (with endEntityStrategy = "COMMON_NAME") as is in the following cURL command, only the realm-id and commonName fields will be required inside --data option.

Listing 8. Create an end-entity in cURL
curl --location --request POST '< base url >/api/v1/end-entities/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer < token from keycloak >' \
--data '{
  "commonName": "< end entity common name >",
  "realmId": "< existing realm id >",
  "organization": "< organization >",
  "organizationalUnit": "< organizational unit >",
  "country": "< country >",
  "externalId": "< external id >",
  "email": "< email >",
  "domains": [
    "< basic domain >",
    "< extra domain >"
  ],
  "ips": [
    "< basic ip >",
    "< extra ip >",
    "< extra ip >"
  ],
  "genericDtoList": [
    {
      "key": "< key for added information >",
      "value": "< value for previous key >"
    }
  ]
}'

6. Create a Certificate Request

A certificate request contains the cryptographic parameters that are needed for the creation of a new certificate. It is created always as part of the certificate issue process. Certificate requests are bound to a policy and an end-entity, which were selected/created in the first two steps of certificate creation.

Listing 9 shows a code snippet for the creation of a certificate request in Java.

Listing 9. Create a certificate request - Java snippet
private CreateCertReqResponseDto createCertRequest(UUID policyId,
        UUID endEntityId) {

    final KeyGenParamsDto keyGenParamsDto = new KeyGenParamsDto()
        .keySize(RsaKeySize._2048)
        .cryptoAlgorithm(CryptoAlgorithm.RSA);

    var certRequestDto = new CreateCertReqRequestDto()
        .policyId(policyId)
        .endEntityId(endEntityId)
        .validFor(ValidFor.SIX_MONTHS)
        .keyPairMode(KeyPairMode.SERVER_GEN)
        .keyGenParamsDto(keyGenParamsDto);

    return Objects.requireNonNull(clmClient.getCertRequestApi()
        .createCertRequest(certRequestDto)
        .block());
}

Listing 10 shows the creation of a certificate request using cURL

Listing 10. Create a certificate request in cURL
curl --location -request POST '< base url >/api/v1/cert-requests/' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer < token from keyloack >' \
--data '{
    "endEntityId": "< end entity id >",
    "keyPairMode": "SERVER_GEN",
    "policyId":"< policy id >",
    "validFor":"SIX_MONTHS",
    "keyGenParamsDto":{
        "cryptoAlgorithm":"RSA",
        "keySize":"2048"
    },
    "pkcs10ReqBase64": null,
    "publicKeyBase64": null
}'

7. Issue a Certificate

The main purpose of MTG Certificate Lifecycle Manager Server is to create and manage digital x.509 certificates. A certificate is created (issued) inside a specific realm and is bound to it. You also have to either choose an existing end entity and policy or to create new ones.

Listing 11 shows a code snippet for the issuance of a certificate in Java.

Listing 11. Issue a certificate - Java snippet
private CreateCertificateResponseDto createCertificate(
        UUID certRequestId) {

    return Objects.requireNonNull(
            clmClient.getCertificateApi()
                    .createCertificate(certRequestId)
                    .block());
}

Listing 12 shows the issuance of a certificate using cURL

Listing 12. Issue a certificate in cURL
curl --location --request POST '< base url >/api/v1/certificates/cert-requests/< certificate request id >' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer < token from keycloak >'

References