atoti_plus.security module

class atoti_plus.security.BasicSecurity(_java_api, users)

Manage basic authentication on the session.

Note

This requires AuthenticationConfig to be configured.

create_user(username, *, password=None, roles=())

Add a user able to authenticate against the session using Basic Authentication.

The roles and password of the user can be changed at any time.

Example

>>> session = tt.create_session(
...     "tesla", config={"authentication": {"basic": {}}}
... )
>>> list(session.security.basic.users)
[]
>>> elon = session.security.basic.create_user("elon", password="X Æ A-12")
>>> list(session.security.basic.users)
['elon']
>>> # The special ROLE_USER role is automatically added
>>> elon.roles
{'ROLE_USER'}
>>> # Change the password
>>> elon.password = "AE A-XII"
>>> # Revoke access
>>> del session.security.basic.users["elon"]
>>> list(session.security.basic.users)
[]
Return type

User

users: BasicUsers
class atoti_plus.security.BasicUsers(_java_api)
authentication_type()

Get the type of user this contains.

Return type

str

class atoti_plus.security.IndividualRoles(_java_api)

The roles given to users on top of the ones that can be added by authentication providers.

Users without the ROLE_USER will not be able to access the session.

Example

>>> session = tt.create_session(
...     name="roles", config={"authentication": {"basic": {}}}
... )
>>> elon = session.security.basic.create_user("John", password="X Æ A-12")
>>> elon.roles
{'ROLE_USER'}
>>> session.security.individual_roles[elon.username].add("ROLE_USA")
>>> sorted(elon.roles)
['ROLE_USA', 'ROLE_USER']
>>> session.security.individual_roles[elon.username].remove("ROLE_USA")
>>> elon.roles
{'ROLE_USER'}
>>> # Removing all the roles will prevent the user from accessing the session:
>>> del session.security.individual_roles[elon.username]
>>> list(elon.roles)
[]
update(__m: Mapping[str, Union[Collection[str], atoti_plus.security._UserRoles]], **kwargs: Union[Collection[str], atoti_plus.security._UserRoles]) None
update(__m: Iterable[Tuple[str, Union[Collection[str], atoti_plus.security._UserRoles]]], **kwargs: Union[Collection[str], atoti_plus.security._UserRoles]) None
update(**kwargs: Union[Collection[str], atoti_plus.security._UserRoles]) None

Update the mapping.

Return type

None

class atoti_plus.security.KerberosSecurity(_java_api, users)

Manage Kerberos authentication on the session. .. note:: This requires KerberosConfig to be configured.

create_user(username, *, roles=())

Add a user able to authenticate against the session using Kerberos. The roles of the user can be changed at any time. Users without the role ROLE_USER will not have access to the application. .. seealso:: create_user() for a similar usage example.

Return type

User

users: KerberosUsers
class atoti_plus.security.KerberosUsers(_java_api)
authentication_type()

Get the type of user this contains.

Return type

str

class atoti_plus.security.LdapSecurity(_java_api, role_mapping)

Allows mapping roles granted by the authentication provider to the roles to use in the session.

Users who do not have the ROLE_USER session role will not be able to access the session.

Note

This requires LdapConfig to be configured.

Example
>>> session = tt.create_session(
...     config={
...         "authentication": {
...             "ldap": {
...                 "url": "ldap://ldap.forumsys.com:389/",
...                 "base_dn": "dc=example,dc=com",
...                 "user_search_filter": "(uid={0})",
...                 "group_search_filter": "(uniqueMember={0})",
...             },
...         },
...     }
... )
>>> mathematicians_role = session.security.create_role(
...     "ROLE_MATHS", restrictions={"City": ["Paris"]}
... )

Roles from the authentication provider can be mapped to roles in the session.

>>> session.security.ldap.role_mapping["MATHEMATICIANS"] = [
...     "ROLE_MATHS",
...     "ROLE_USER",
... ]
>>> sorted(session.security.ldap.role_mapping["MATHEMATICIANS"])
['ROLE_MATHS', 'ROLE_USER']
role_mapping: RoleMapping
class atoti_plus.security.OidcSecurity(_java_api, role_mapping)

Allows mapping roles granted by the authentication provider’s ID Token to the roles to use in the session.

Users who do not have the ROLE_USER session role will not be able to access the session.

Note

This requires OidcConfig to be configured.

Example

>>> import os
>>> session = tt.create_session(
...     "OpenID",
...     config={
...         "authentication": {
...             "oidc": {
...                 "provider_id": "auth0",
...                 "issuer_url": os.environ["AUTH0_ISSUER"],
...                 "client_id": os.environ["AUTH0_CLIENT_ID"],
...                 "client_secret": os.environ["AUTH0_CLIENT_SECRET"],
...                 "scopes": ["email", "profile", "username"],
...                 "name_claim": "email",
...                 "roles_claims": ["https://activeviam:eu:auth0:com/roles"],
...             },
...         },
...         "port": 1234,
...     },
... )
>>> france_role = session.security.create_role(
...     "ROLE_FRANCE", restrictions={"Country": "France"}
... )

Roles from the authentication provider’s ID Token can be mapped to roles in the session:

>>> session.security.oidc.role_mapping.update(
...     {"atoti user": ["ROLE_USER"], "France": [france_role.name]}
... )
>>> session.security.oidc.role_mapping
{'atoti user': {'ROLE_USER'}, 'France': {'ROLE_FRANCE'}}
role_mapping: RoleMapping
class atoti_plus.security.Restrictions(*, _java_api, _role, _restrictions)

The restrictions associated with a role can be modified at any time.

  • Restrictions apply on table columns and are inherited by all hierarchies based on these columns.

  • Restrictions on different hierarchies are intersected.

  • However, if a user has several roles with restrictions on the same hierarchies, access to the union of restricted members will be granted.

    Example:

    >>> from typing import List
    >>> df = pd.DataFrame(
    ...     [
    ...         ("Asia", "Korea", "KRW"),
    ...         ("Asia", "Japan", "JPY"),
    ...         ("Europe", "France", "EUR"),
    ...         ("Europe", "Germany", "EUR"),
    ...         ("Europe", "Norway", "NOK"),
    ...         ("Europe", "Sweden", "SEK"),
    ...     ],
    ...     columns=["Continent", "Country", "Currency"],
    ... )
    >>> session = tt.create_session(
    ...     config={"authentication": {"basic": {}}}
    ... )
    >>> table = session.read_pandas(
    ...     df,
    ...     keys=["Continent", "Country", "Currency"],
    ...     table_name="Restrictions example",
    ... )
    >>> cube = session.create_cube(table)
    >>> h, l, m = cube.hierarchies, cube.levels, cube.measures
    >>> cube.hierarchies["Geography"] = [
    ...     table["Continent"],
    ...     table["Country"],
    ... ]
    >>> for name in cube.hierarchies["Geography"].levels:
    ...     del cube.hierarchies[name]
    ...
    >>> password = "BYXV$9P_rEr4"
    >>> user = session.security.basic.create_user("john", password=password)
    

    Opening a query session to authenticate as the user just created:

    >>> query_session = tt.QuerySession(
    ...     f"http://localhost:{session.port}",
    ...     auth=tt.BasicAuthentication(
    ...         username=user.username, password=password
    ...     ),
    ... )
    >>> query_cube = query_session.cubes[cube.name]
    >>> l, m = query_cube.levels, query_cube.measures
    

    The user initially only has the ROLE_USER:

    >>> user.roles
    {'ROLE_USER'}
    

    This role has no restrictions so all the countries and currencies are accessible:

    >>> query_cube.query(
    ...     m["contributors.COUNT"], levels=[l["Country"], l["Currency"]]
    ... )
                               contributors.COUNT
    Continent Country Currency
    Asia      Japan   JPY                       1
              Korea   KRW                       1
    Europe    France  EUR                       1
              Germany EUR                       1
              Norway  NOK                       1
              Sweden  SEK                       1
    

    Adding a restricting role to the user so that only France is accessible:

    >>> role_france = session.security.create_role(
    ...     "ROLE_FRANCE", restrictions={"Country": ["France"]}
    ... )
    >>> session.security.individual_roles[user.username].add(
    ...     role_france.name
    ... )
    >>> query_cube.query(m["contributors.COUNT"], levels=[l["Country"]])
                      contributors.COUNT
    Continent Country
    Europe    France                   1
    

    Restrictions on the same hierarchy grant access to the union of the restricted members:

    >>> role_germany = session.security.create_role(
    ...     "ROLE_GERMANY", restrictions={"Country": ["Germany"]}
    ... )
    >>> session.security.individual_roles[user.username].add(
    ...     role_germany.name
    ... )
    >>> query_cube.query(m["contributors.COUNT"], levels=[l["Country"]])
                      contributors.COUNT
    Continent Country
    Europe    France                   1
              Germany                  1
    

    Restrictions can grant access to multiple members:

    >>> role_nordic = session.security.create_role(
    ...     "ROLE_NORDIC", restrictions={"Country": ["Norway", "Sweden"]}
    ... )
    >>> session.security.individual_roles[user.username].add(
    ...     role_nordic.name
    ... )
    >>> query_cube.query(m["contributors.COUNT"], levels=[l["Country"]])
                      contributors.COUNT
    Continent Country
    Europe    France                   1
              Germany                  1
              Norway                   1
              Sweden                   1
    

    Also give access to the Asian countries with a restriction on Continent:

    >>> role_asia = session.security.create_role(
    ...     "ROLE_ASIA", restrictions={"Continent": ["Asia"]}
    ... )
    >>> session.security.individual_roles[user.username].add(role_asia.name)
    >>> query_cube.query(m["contributors.COUNT"], levels=[l["Country"]])
                      contributors.COUNT
    Continent Country
    Asia      Japan                    1
              Korea                    1
    Europe    France                   1
              Germany                  1
              Norway                   1
              Sweden                   1
    

    Restrictions on different hierarchies are intersected:

    >>> role_eur = session.security.create_role(
    ...     "ROLE_EUR", restrictions={"Currency": ["EUR"]}
    ... )
    >>> session.security.individual_roles[user.username].add(role_eur.name)
    >>> query_cube.query(
    ...     m["contributors.COUNT"], levels=[l["Country"], l["Currency"]]
    ... )
                               contributors.COUNT
    Continent Country Currency
    Europe    France  EUR                       1
              Germany EUR                       1
    

    Removing the roles granting access to France and Germany leaves no remaining accessible countries:

    >>> for role in [role_france, role_germany]:
    ...     session.security.individual_roles[user.username].remove(
    ...         role.name
    ...     )
    ...
    >>> query_cube.query(m["contributors.COUNT"], levels=[l["Country"]])
    Empty DataFrame
    Columns: [contributors.COUNT]
    Index: []
    
class atoti_plus.security.Role(name, *, restrictions, _java_api)

A role and its restrictions.

name: str
restrictions: Restrictions
class atoti_plus.security.RoleMapping(_java_api, _type)

Mapping between roles or usernames comming from the authentication provider to those to use in the session.

update(__m: Mapping[str, Union[Iterable[str], atoti_plus.security._MappedRoles]], **kwargs: Union[Iterable[str], atoti_plus.security._MappedRoles]) None
update(__m: Iterable[Tuple[str, Union[Iterable[str], atoti_plus.security._MappedRoles]]], **kwargs: Union[Iterable[str], atoti_plus.security._MappedRoles]) None
update(**kwargs: Union[Iterable[str], atoti_plus.security._MappedRoles]) None

Update the mapping.

Return type

None

class atoti_plus.security.Roles(_java_api)

All of the roles defined in the session.

class atoti_plus.security.Security(*, java_api)

Security management for the current session.

basic: BasicSecurity
create_role(name, *, restrictions={})

Create a role with the given restrictions.

There are special roles which cannot be redefined:

  • ROLE_USER: required to access the application

  • ROLE_ADMIN: gives full access (read, write, delete, etc) to the application

Return type

Role

individual_roles: IndividualRoles
kerberos: KerberosSecurity
ldap: LdapSecurity
oidc: OidcSecurity
roles: Roles
class atoti_plus.security.User(username, *, java_api, authentication_type, password=None)
password: Optional[str]
property roles: Collection[str]
Return type

Collection[str]

username: str
class atoti_plus.security.Users(_java_api)
abstract authentication_type()

Get the type of user this contains.

Return type

str