atoti.Cube.restrictions#
- property Cube.restrictions: MutableMapping[str, IsInCondition[LevelIdentifier, 'IS_IN', Constant] | RelationalCondition[LevelIdentifier, 'EQ', Constant] | LogicalCondition[IsInCondition[LevelIdentifier, 'IS_IN', Constant] | RelationalCondition[LevelIdentifier, 'EQ', Constant], 'AND']]#
Mapping from role name to the corresponding restriction.
Restrictions limit the data accessible to users based on their roles.
Restrictions on different hierarchies are intersected.
Restrictions on the same hierarchy are unioned.
Warning
A
QueryCube
only enforces its own restrictions, it ignores the ones of the contributing data cubes.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]
Adding a user to the session:
>>> password = "abcdef123456" >>> session.security.basic_authentication.credentials["Rose"] = password >>> session.security.individual_roles["Rose"] = {"ROLE_USER"} >>> rose_session = tt.Session.connect( ... session.url, ... authentication=tt.BasicAuthentication("Rose", password), ... ) >>> rose_cube = rose_session.cubes[cube.name]
ROLE_USER has no restrictions so all the countries and currencies are accessible from the cube:
>>> rose_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 Rose to limit her access to France only:
>>> cube.restrictions["ROLE_FRANCE"] = l["Country"] == "France" >>> session.security.individual_roles["Rose"] |= {"ROLE_FRANCE"} >>> rose_cube.query( ... m["contributors.COUNT"], include_totals=True, levels=[l["Country"]] ... ) contributors.COUNT Continent Country Total 1 Europe 1 France 1
Unlike
atoti.tables.Tables.restrictions
, cube restrictions have no impact on tables:>>> rose_table = rose_session.tables[table.name] >>> rose_table.query().set_index(["Continent", "Country"]).sort_index() Currency Continent Country Asia Japan JPY Korea KRW Europe France EUR Germany EUR Norway NOK Sweden SEK
Adding Lena with ROLE_GERMANY limiting her access to Germany only:
>>> cube.restrictions["ROLE_GERMANY"] = l["Country"] == "Germany" >>> session.security.basic_authentication.credentials["Lena"] = password >>> session.security.individual_roles["Lena"] = { ... "ROLE_GERMANY", ... "ROLE_USER", ... } >>> lena_session = tt.Session.connect( ... session.url, ... authentication=tt.BasicAuthentication("Lena", password), ... ) >>> lena_cube = lena_session.cubes[cube.name] >>> lena_cube.query(m["contributors.COUNT"], levels=[l["Country"]]) contributors.COUNT Continent Country Europe Germany 1
Assigning ROLE_GERMANY to Rose lets her access the union of the restricted countries:
>>> session.security.individual_roles["Rose"] |= {"ROLE_GERMANY"} >>> cube.restrictions {'ROLE_FRANCE': l['Restrictions example', 'Geography', 'Country'] == 'France', 'ROLE_GERMANY': l['Restrictions example', 'Geography', 'Country'] == 'Germany'} >>> rose_cube.query(m["contributors.COUNT"], levels=[l["Country"]]) contributors.COUNT Continent Country Europe France 1 Germany 1
Restrictions can include multiple elements:
>>> cube.restrictions["ROLE_NORDIC"] = l["Country"].isin("Norway", "Sweden") >>> session.security.individual_roles["Rose"] |= {"ROLE_NORDIC"} >>> rose_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:
>>> cube.restrictions["ROLE_ASIA"] = l["Continent"] == "Asia" >>> session.security.individual_roles["Rose"] |= {"ROLE_ASIA"} >>> rose_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:
>>> cube.restrictions["ROLE_EUR"] = l["Currency"] == "EUR" >>> session.security.individual_roles["Rose"] |= {"ROLE_EUR"} >>> rose_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["Rose"] -= { ... "ROLE_FRANCE", ... "ROLE_GERMANY", ... } >>> rose_cube.query(m["contributors.COUNT"], levels=[l["Country"]]) Empty DataFrame Columns: [contributors.COUNT] Index: []
A
QuerySession
has cubes but no tables so there is nothing to merge cube restrictions with. However, data cubes have their restrictions merged with the ones from the session’stables
:>>> session.tables.restrictions.update( ... { ... "ROLE_SEK": table["Currency"] == "SEK", ... "ROLE_JPY": table["Currency"] == "JPY", ... } ... ) >>> session.security.individual_roles["Rose"] = { ... "ROLE_ASIA", # Cube restriction ... "ROLE_NORDIC", # Cube restriction ... "ROLE_SEK", # Tables restriction ... "ROLE_JPY", # Tables restriction ... "ROLE_USER", ... } >>> rose_table.query().set_index(["Continent", "Country"]).sort_index() Currency Continent Country Asia Japan JPY Europe Sweden SEK >>> rose_cube.query( ... m["contributors.COUNT"], levels=[l["Country"], l["Currency"]] ... ) contributors.COUNT Continent Country Currency Asia Japan JPY 1 Europe Sweden SEK 1
See also