Session configuration

The session configuration regroups all the aspects of the session that might change dependending on where it is deployed. The configuration is passed as an argument of create_session, either as:

  • a Python object

  • a path to a YAML file, allowing you to change the configuration without modifying the project’s code

[1]:
import atoti as tt

Port and URL

Port

The port used by the session defaults to a random available port but it can be set to a specific one:

[2]:
config = tt.config.create_config(port=8080)

or in a YAML file:

port: 8080

URL pattern

This sets the URL returned by session.url to connect to the user interface. It defaults to http://localhost:{port} where {port} will be replaced with the port on which the session is exposed:

In a YAML file, it can be set like that:

url_pattern: https://example.com:{port}/

which is equivalent to:

[3]:
config = tt.config.create_config(url_pattern="https://example.com:{port}/")

Metadata database

Some data, such as the dashboards generated by the users, is not part of the data sources but is stored anyway in what we call the metadata database. By default, this database is in memory so everything is lost when the atoti session is closed. However, it can also be persisted to a file.

For instance:

metadata_db: ./metadata.db

or in Python:

[4]:
config = tt.config.create_config(metadata_db="./metadata.db")

Security

Atoti+ only: security configuration is only available in Atoti+.

When sharing your application with other users, you can set up security to configure which users are allowed to connect to the application and which part of the data they are allowed to see.

Roles

Roles are a way to restrict what users can see in a cube. By default, all users mentioned in your configuration file have a role called ROLE_USER which gives access to the full cube. You can define additional roles with restrictions and give these roles to your users.

This in an example of roles in a YAML file:

roles:
  - name: ROLE_FRANCE
    restrictions:
      Country: France
      Currency: Euro
  - name: ROLE_AMERICA
    restrictions:
      Country: [USA, Canada]
  - name: ROLE_CHINA
    restrictions:
      Country: [China]

Roles can also be defined directly in Python:

[5]:
french = tt.config.create_role(
    "ROLE_FRANCE", restrictions={"Country": "France", "Currency": "Euro"}
)
american = tt.config.create_role(
    "ROLE_AMERICA", restrictions={"Country": ["USA", "Canada"]}
)
chinese = tt.config.create_role("ROLE_CHINA", restrictions={"Country": "China"})

config = tt.config.create_config(roles=[french, american, chinese])

Roles are defined per column. Column restrictions are inherited by all hierarchies based on this column. For instance, in the previous configuration, a user with the role ROLE_AMERICA will only see the data related to USA and Canada and won’t see the data for France.

Combining roles

Restrictions on different hierarchies are intersected. For instance, in the previous configuration, a user with the role ROLE_FRANCE will only see the data where the country is France AND the currency is Euro.

However, if a user has several roles with restrictions on the same hierarchies, the access to the union of restricted members will be granted. For instance, in the previous configuration, a user with both ROLE_AMERICA and ROLE_CHINA will see the data where the country is USA, Canada, OR China.

Authentication

Basic

Basic authentication only requires usernames and passwords. It is the easiest way to get started with security on a project since you only have to define the users, their password, and their roles.

This is an example of YAML configuration defining 3 users:

authentication:
  basic:
    users:
      - name: admin
        password: nidma
        roles:
          - ROLE_ADMIN
      - name: user1
        password: 1resu
        roles:
          - ROLE_FRANCE
      - name: user2
        password: 2resu
        roles:
          - ROLE_UK

Which is equivalent to the following Python code:

[6]:
admin = tt.config.create_basic_user("admin", "nidma", roles=["ROLE_ADMIN"])
user1 = tt.config.create_basic_user("user1", "1resu", roles=["ROLE_FRANCE"])
user2 = tt.config.create_basic_user("user2", "2resu", roles=["ROLE_UK"])
basic = tt.config.create_basic_authentication(
    [admin, user1, user2], realm="Configuration Tutorial"
)

config = tt.config.create_config(authentication=basic)

OpenID Connect

Atoti+ is compliant with any OpenID Connect OAuth2 authentication provider (Auth0, Google, Keycloak, etc.).

The configuration requires:

  • information about your application (clientId, clientSecret)

  • information about the OAuth2 provider you are using

  • optional: a role mapping between the OAuth2 roles/users and atoti roles

This is an example YAML configuration for OAuth2 giving access to other users:

authentication:
  oidc:
    provider_id: myProvider # This configures redirectUrls, the format of the redirect URL is {baseUrl}/login/oauth2/code/{providerId}
    issuer_url: myIssuer # The URL of the authentication server
    client_id: clientId
    client_secret: clientSecret
    name_attribute: email # The value to use as the displayed username in the application
    scopes: # The scopes to request access to (openid is passed by default)
      - email
      - profile
    paths_to_authorities:
      - paths/to/authorities # The path to the authorities in the claims contained in the token
    role_mapping:
      dev_team: # map a role granted by the OAuth2 server to one or several atoti roles
        - ROLE_USER # required to access the application
        - ROLE_DEV # custom role used to define specific restrictions
      admin: # map a username to atoti roles
        - ROLE_ADMIN
[7]:
oidc = tt.config.create_oidc_authentication(
    provider_id="MyProvider",
    issuer_url="MyIssuer",
    client_id="clientId",
    client_secret="clientSecret",
    scopes=["email", "profile"],
    name_attribute="username",
    paths_to_authorities=["path/to/authorities"],
    role_mapping={"ROLE_ADMIN": ["ROLE_ADMIN", "ROLE_TEST"]},
)

LDAP

atoti supports LDAP authentication.

This is an example YAML configuration for an LDAP Directory Service:

authentication:
  ldap:
    url: ldap://example.com:639 #  The LDAP URL including the protocol and port.
    base_dn: dc=example,dc=com # Base Distinguished Name of the directory service.
    user_search_base: ou=people # Search base for user searches.
    user_search_filter: (uid={0}) # The LDAP filter used to search for users.
    role_mapping: # mapping from LDAP group roles to atoti roles.
      admin:
        - ROLE_ADMIN
      team-A:
        - ROLE_USER # required to access the application
      France:
        - ROLE_FRANCE
        - ROLE_EUR
[8]:
ldap = tt.config.create_ldap_authentication(
    url="ldap://example.com:639",
    base_dn="dc=example,dc=com",
    user_search_base="ou=people",
    user_search_filter="(uid={0})",
    role_mapping={"admin": ["ROLE_ADMIN"], "france": ["ROLE_FRANCE", "ROLE_EUR"]},
)

JWT authentication

Atoti+ uses JSON Web Tokens to authenticate communications between its various components (e.g. between the app and the session), but also to authenticate communications with remote metadata DB. By default, the application will generate a random key pair used to sign JWTs, but you can also provide your own RSA key pair in the configuration if you want to. The default key’s size is 2048 bytes.

This configuration requires:

  • public_key: The public key used to generate and sign JWTs

  • private_key: The private key used to genaret and sign JWTs

Here is an example configuration file to setup JWTs for your application:

jwt_key_pair:
  public_key: "myPublicKey"
  private_key: "myPrivateKey"
[9]:
jwt_key_pair = tt.config.create_jwt_key_pair(
    public_key="myPubicKey", private_key="myPrivateKey"
)

Branding

Atoti+ only: Branding configuration is only available in Atoti+.

Some elements of the app can be changed to replace the atoti branding with another one:

branding:
  accent_color: "#f7931a"
  favicon: company.ico
  frame_color: MidnightBlue
  logo: company.svg
  title: DataCorp
[10]:
branding = tt.config.create_branding(
    accent_color="#f7931a",
    favicon="company.ico",
    frame_color="MidnightBlue",
    logo="company.svg",
    title="DataCorp",
)

HTTPS

Atoti+ only: HTTPS configuration is only available in Atoti+.

You can pass a PKCS12 certificate (and its password) to Atoti+ to serve it in HTTPS. If you have PEM or DER certificates, you can use tools like openssl to convert them to PKCS12 format:

openssl pkcs12 -export -out cert.p12 -in cert.pem -inkey key.pem

The configuration requires:

  • certificate: The path to your certificate in PKCS12 format.

  • password: The password to read the certificate.

Here is an example YAML configuration file:

https:
  certificate: cert.p12
  password: changeit
[11]:
https = tt.config.create_https_config(certificate="cert.p12", password="changeit")

Sampling mode

This sets the default sampling mode for all the stores. When building the data model, it is more efficient to work only on a subset of the data. Once the modeling is over, everything can be loaded with Session.load_all_data().

This mode will load only the first 10,000 lines for each store:

sampling_mode:
  first_lines: 10000

This mode will load only the first file for each store:

sampling_mode:
  first_files: 1

This mode will load all the data:

sampling_mode: full

These can also be defined in Python:

[12]:
config = tt.config.create_config(sampling_mode=tt.sampling.first_lines(10000))
config = tt.config.create_config(sampling_mode=tt.sampling.first_files(1))
config = tt.config.create_config(sampling_mode=tt.sampling.FULL)

Application memory

atoti loads all the data in memory. The max memory can be set to increase the capacity of the application.

The format is a string containing a number followed by a unit among G, M and K, for instance “64G”. This actually sets the -Xmx JVM parameters and defaults to the JVM default memory which is 25% of the machine memory.

max_memory: 64G
[13]:
config = tt.config.create_config(max_memory="64G")

Advanced Java Arguments

It is possible to provide additional arguments to Java in order to do some custom optimization or debugging

In YAML it is done with a list of arguments:

java_args:
  - "-Xms1g"
  - "-XX:+UseG1GC"

equivalent to this Python code:

[14]:
config = tt.config.create_config(java_args=["-Xms1g", "-XX:+UseG1GC"])

Configuration inheritance

If you work on multiple atoti projects, you might want to share some configuration properties such as authentication or branding between them. It’s possible to do that without repeating these properties by using configuration inheritance.

To do so declare the shared parts of the configuration in a global configuration file located at $ATOTI_HOME/config.yml where $ATOTI_HOME defaults to $HOME/.atoti.

By default, the project-specific configurations will be merged with the global one, set inherit_global_config to False to prevent it.

Environment variables

Environment variables can be used in the configuration with the following syntax:

authentication:
  basic:
    users:
      - name: ${{ env.PROJECT_USERNAME }}
        password: ${{ env.PROJECT_PASSWORD }}