atoti.security.Security.restrictions#
- property Security.restrictions: MutableMapping[str, Condition[ColumnIdentifier, Literal['eq', 'isin'], Constant, Literal['and'] | None]]#
Mapping from role name to corresponding restriction.
Restrictions limit the data accessible to users based on their roles. Restrictions apply on table columns and are inherited by all hierarchies based on these columns.
Restrictions on different columns/hierarchies are intersected.
Restrictions on the same column/hierarchy are unioned.
See the example below for an illustration.
Note
ROLE_USER and ROLE_ADMIN are reserved roles for which restrictions cannot be declared.
ROLE_ADMIN always grants full access to the application (read, write, delete, etc.).
Example
>>> session_config = tt.SessionConfig(security=tt.SecurityConfig()) >>> session = tt.Session.start(session_config) >>> 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"], ... ) >>> 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 level_name in cube.hierarchies["Geography"]: ... del cube.hierarchies[level_name] >>> username, password = "john", "abcdef123456" >>> session.security.basic_authentication.credentials[username] = password
The user initially has no individual roles:
>>> username in session.security.individual_roles False
Adding ROLE_USER grants access to the application:
>>> session.security.individual_roles[username] = {"ROLE_USER"} >>> connected_session = tt.Session.connect( ... session.url, ... authentication=tt.BasicAuthentication(username, password), ... ) >>> cube = connected_session.cubes[cube.name] >>> h, l, m = cube.hierarchies, cube.levels, cube.measures
ROLE_USER has no restrictions so all the countries and currencies are accessible:
>>> 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
Assigning a role to the user to limit access to France only:
>>> session.security.restrictions["ROLE_FRANCE"] = table["Country"] == "France" >>> session.security.individual_roles[username] |= {"ROLE_FRANCE"} >>> cube.query(m["contributors.COUNT"], levels=[l["Country"]]) contributors.COUNT Continent Country Europe France 1
In the code block below, ROLE_FRANCE and ROLE_GERMANY individually limit access to, respectively, France only and Germany only. However, when a user has both, the union of the sets are accessible.
>>> session.security.restrictions["ROLE_GERMANY"] = ( ... table["Country"] == "Germany" ... ) >>> session.security.individual_roles[username] |= {"ROLE_GERMANY"} >>> cube.query(m["contributors.COUNT"], levels=[l["Country"]]) contributors.COUNT Continent Country Europe France 1 Germany 1
Restrictions can include multiple elements:
>>> session.security.restrictions["ROLE_NORDIC"] = table["Country"].isin( ... "Norway", "Sweden" ... ) >>> session.security.individual_roles[username] |= {"ROLE_NORDIC"} >>> cube.query(m["contributors.COUNT"], levels=[l["Country"]]) contributors.COUNT Continent Country Europe France 1 Germany 1 Norway 1 Sweden 1
Since Country and Continent are part of the same Geography hierarchy, restrictions on these two levels are unioned:
>>> session.security.restrictions["ROLE_ASIA"] = table["Continent"] == "Asia" >>> session.security.individual_roles[username] |= {"ROLE_ASIA"} >>> 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
Currency is part of a different hierarchy so restrictions on it are intersected with the ones from Geography:
>>> session.security.restrictions["ROLE_EUR"] = table["Currency"] == "EUR" >>> session.security.individual_roles[username] |= {"ROLE_EUR"} >>> cube.query(m["contributors.COUNT"], levels=[l["Country"], l["Currency"]]) contributors.COUNT Continent Country Currency Europe France EUR 1 Germany EUR 1
Removing the ROLE_FRANCE and ROLE_GERMANY roles leaves no remaining accessible countries:
>>> session.security.individual_roles[username] -= { ... "ROLE_FRANCE", ... "ROLE_GERMANY", ... } >>> cube.query(m["contributors.COUNT"], levels=[l["Country"]]) Empty DataFrame Columns: [contributors.COUNT] Index: []