Skip to content

ARGOeu/argo-accounting

Repository files navigation

ARGO-accounting

ARGO Accounting

This project uses Quarkus, the Supersonic Subatomic Java Framework.

Prerequisites

  • Java 11+
  • Apache Maven 3.8.1+
  • Docker (for dev mode)

Dev Services

Quarkus supports the automatic provisioning of unconfigured services in development and test mode. They refer to this capability as Dev Services. From a developer’s perspective this means that if you include an extension and don’t configure it then Quarkus will automatically start the relevant service (usually using Testcontainers behind the scenes) and wire up your application to use this service.

Running the application in dev mode

You can run your application in dev mode that enables live coding using:

mvn clean compile quarkus:dev

Packaging and running the application

The application can be packaged using:

mvn clean package

It produces the quarkus-run.jar file in the target/quarkus-app/ directory. Be aware that it’s not an über-jar as the dependencies are copied into the target/quarkus-app/lib/ directory.

The application is now runnable using java -jar target/quarkus-app/quarkus-run.jar.

If you want to build an über-jar, execute the following command:

mvn clean package -Dquarkus.package.type=uber-jar

The application, packaged as an über-jar, is now runnable using java -jar target/*-runner.jar.

Creating a native executable

You can create a native executable using:

mvn clean package -Pnative

Or, if you don't have GraalVM installed, you can run the native executable build in a container using:

mvn clean package -Pnative -Dquarkus.native.container-build=true

You can then execute your native executable with: ./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner

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

Mongo Database

When running the production version of the application, the MongoDB connection needs to be configured as normal by setting the connection string in quarkus.mongodb.connection-string. If you want to continue use Dev Services we recommend that you use the %prod. profile to define your MongoDB settings. What that means practically, is that Quarkus will automatically start a MongoDB container when running tests or dev-mode, and automatically configure the connection.

Authentication

To access Accounting System API resources, you have to be authenticated by EOSC Core Infrastructure Proxy. These resources are protected and can only be accessed if a client is sending a bearer token along with the request, which must be valid and trusted by the Accounting System API.

Authentication via EOSC Core Infrastructure Proxy

The EOSC Core Infrastructure Proxy offers various Identity Providers where the authentication process can be performed.

Login Page

Once you log in to your preferable Identity Provider, you obtain an access token. Using this token, you can access the available API operations.

When passing in the access token in an HTTP header, you should make a request like the following:

curl http://localhost:8080/accounting-system/metric-definitions
   -H "Authorization: Bearer {token}"

There is an ancillary web page at {accounting_system_host} where you can identify yourself. This page is responsible for :

  • redirecting a user to EOSC Core Infrastructure Proxy in order to be authenticated
  • displaying the obtained token

Client Credentials Flow

The Accounting System API also needs to authenticate services. For this scenario, typical authentication schemes like username + password don't make sense. Instead, the services use the Client Credentials Flow , in which they pass along their Client ID and Client Secret to authenticate themselves and get an access token.

The Client ID and Client Secret are generated by Keycloak and provided by GRNET. Once the service acquires them, it can obtain a token by executing the following HTTP request:

curl --location --request POST 'https://keycloak/auth/realms/einfra/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<CLIENT_ID>' \
--data-urlencode 'client_secret=<CLIENT_SECRET>' \
--data-urlencode 'grant_type=client_credentials'

Integrating with TestContainer in Dev mode

Quarkus starts a Keycloak container for both the dev and/or test modes and initializes them by registering the existing Keycloak realm or creating a new realm with the client and users for you to start developing the Accounting System application secured by Keycloak immediately. More details about how to obtain access tokens in dev mode you can find here.

Integrating with External OIDC Server in Dev mode

If you want to integrate with external OIDC Server, you have to remove the prefix %prod. from %prod.quarkus.oidc.auth-server-url. Then you have to configure the following variables in application.properties:

  • quarkus.oidc.auth-server-url={The base URL of the OIDC server}
  • quarkus.oidc.client-id={Specifies an alpha-numeric string that will be used as the client identifier for OIDC requests}
  • quarkus.oidc.credentials.secret={Client secret which is used for a client_secret_basic authentication method}

You also need to comment out all the properties that start with %dev.quarkus.oidc.

Authorization

Collection-level permissions control services’ access to the collection. Collection permissions are configured using roles, and each collection contains a set of roles that allows services to create, read, update and delete entities of that collection. We assign permissions to services based on their roles. A role is a collection of permissions that you can apply to every service. We can assign one or more roles to each service and one or more permissions to each role.

To generate a role, we have to define the available API operations and access types. By combining operations and access types, you can generate permissions and then you can assign these permissions to each role.

Operations

The available API operations are:

Operation Description
Create Can create new entities within a collection
Update Can update existing entities within a collection
Delete Can delete existing entities within a collection
Read Can fetch existing entities within a collection
Acl Can specify which services are granted access to particular entities within a collection

Access Types

The following table illustrates the available access types:

Access Type Description
Always Services are always able to perform this operation
Never Services are never able to perform this operation
Entity Services have only access to entities that they have created

If the service has more than one role :

  • If the access types are Always and Entity, the service will have Always access, because this access type is the most permissive and will override the others. In other words, the most permissive access type takes precedence.
  • Never always takes precedence over any other access type.

Collections

The available Accounting System API collections are:

Collections
MetricDefinition
Metric
Role
Provider
Installation

Examples

Based on the above, we can generate some indicative roles:

Role Create Update Delete Read Acl Collection
metric_definition_admin Always Always Always Always Always MetricDefinition
metric_inspector Always Metric
metric_creator Always Entity Entity Entity Entity Metric
role_editor Always Always Never Always Role

Notes:

  • The role name should be unique.
  • The blank value is converted to "Never" value

Consequently:

  • metric_definition_admin can create new Metric Definitions, as well as update, delete and read any entity in the collection. Can also specify which services will be granted access to any entity within a Metric Collection. In other words, metric_definition_admin will always be able to perform any operation in the Metric Definition collection.
  • metric_inspector can read any entity in the Metric collection, but cannot create new ones or update, delete any Metrics.
  • metric_creator can create new Metrics, but can update, delete or read only its Metrics. It can also specify which services will have access to the entities it has created. Finally, it can also manage Metrics that have been explicitly declared through the ACL process.
  • role_editor can create new Roles, as well as update, and read any entity in the Role collection but cannot delete any entity in it.

Generating new Roles via Accounting System API

It is possible to create and manage new roles using the API. It should be noted that only the system_admin role, which is initialized in the API, can create and manage roles through the API. Consequently, it is the only role that can grant access to other roles.

Create a new Role

We can create the aforementioned roles by executing the following requests:

  • metric_definition_admin
POST 'https://host/accounting-system/roles' 

{
  "name" : "metric_definition_admin",
  "collections_access_permissions":[
    {
    "collection": "MetricDefinition",
    "access_permissions" :[
      {
        "operation" : "CREATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "UPDATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "DELETE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "READ",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "ACL",
        "access_type" : "ALWAYS"
      }
    ]
    }
]
}
  • metric_inspector
POST 'https://host/accounting-system/roles' 

{
  "name" : "metric_inspector",
  "collections_access_permissions":[
    {
    "collection": "Metric",
    "access_permissions" :[
      {
        "operation" : "READ",
        "access_type" : "ALWAYS"
      }
    ]
    }
]
}
  • metric_creator
POST 'https://host/accounting-system/roles' 

{
  "name" : "metric_creator",
  "collections_access_permissions":[
    {
    "collection": "Metric",
    "access_permissions" :[
      {
        "operation" : "CREATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "UPDATE",
        "access_type" : "ENTITY"
      },
      {
        "operation" : "DELETE",
        "access_type" : "ENTITY"
      },
      {
        "operation" : "READ",
        "access_type" : "ENTITY"
      },
      {
        "operation" : "ACL",
        "access_type" : "ENTITY"
      }
    ]
    }
]
}
  • role_editor
POST 'https://host/accounting-system/roles' 

{
  "name" : "role_editor",
  "collections_access_permissions":[
    {
    "collection": "Role",
    "access_permissions" :[
      {
        "operation" : "CREATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "UPDATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "DELETE",
        "access_type" : "NEVER"
      },
      {
        "operation" : "READ",
        "access_type" : "ALWAYS"
      }
    ]
    }
]
}

You can also create a more generic role. For example, the editor can create new Roles, Metrics, and Metric Definitions, as well as update, and read any entity in those collections. But cannot delete any entity:

  • editor
POST 'https://host/accounting-system/roles' 

{
  "name" : "editor",
  "collections_access_permissions":[
    {
    "collection": "Role",
    "access_permissions" :[
      {
        "operation" : "CREATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "UPDATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "READ",
        "access_type" : "ALWAYS"
      }
    ]
    },
   {
    "collection": "Metric",
    "access_permissions" :[
      {
        "operation" : "CREATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "UPDATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "READ",
        "access_type" : "ALWAYS"
      }
    ]
    },
  {
    "collection": "MetricDefinition",
    "access_permissions" :[
      {
        "operation" : "CREATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "UPDATE",
        "access_type" : "ALWAYS"
      },
      {
        "operation" : "READ",
        "access_type" : "ALWAYS"
      }
    ]
    }
]
}

Assigning roles to Services/Users

The generated roles can be assigned to different users or services via Keycloak.

Deploying the Accounting System API

To deploy the API in a machine :

  • First, you have to set up a mongo database (We are currently using 4.0.28, but other versions may be compatible)
  • Second, there must be an über-jar version of the API on this machine

Before running the über-jar, you have to export the following variables:

- export QUARKUS_MONGODB_CONNECTION_STRING=mongodb://{host}:{port}
- export SERVER_URL={The proxy server URL that acts on behalf of the Accounting System}
- export QUARKUS_OIDC_AUTH_SERVER_URL={The base URL of the OpenID Connect (OIDC) server. Note if you work with Keycloak OIDC server, make sure the base URL is in the following format: https://host:port/auth/realms/{realm} where {realm} has to be replaced by the name of the Keycloak realm}
- export QUARKUS_OIDC_CLIENT_ID={Specifies an alpha-numeric string that will be used as the client identifier for OIDC requests}
- export QUARKUS_OIDC_CREDENTIALS_SECRET={Client secret which is used for a client_secret_basic authentication method}

Once the variables above have been exported, you should execute the following command: java -jar *-runner.jar

Expose OpenAPI Specifications

Once the application is started, you can make a request to the /open-api endpoint:

curl {accounting_system_host}/open-api

Swagger UI

Swagger UI is accessible at /swagger-ui endpoint:

{accounting_system_host}/swagger-ui