atoti.tables.Tables.restrictions#
- property Tables.restrictions: MutableMapping[str, TablesRestrictionCondition]#
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.
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_table = rose_session.tables[table.name] >>> rose_cube = rose_session.cubes[cube.name]
ROLE_USER has no restrictions so all the countries and currencies are accessible from the table:
>>> 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
And 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:
>>> session.tables.restrictions["ROLE_FRANCE"] = ( ... table["Country"] == "France" ... ) >>> session.security.individual_roles["Rose"] |= {"ROLE_FRANCE"} >>> rose_table.query() Continent Country Currency 0 Europe France EUR >>> rose_cube.query( ... m["contributors.COUNT"], include_totals=True, levels=[l["Country"]] ... ) contributors.COUNT Continent Country Total 1 Europe 1 France 1
Adding Lena with ROLE_GERMANY limiting her access to Germany only:
>>> session.tables.restrictions["ROLE_GERMANY"] = ( ... table["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_table = lena_session.tables[table.name] >>> lena_cube = lena_session.cubes[cube.name] >>> lena_table.query() Continent Country Currency 0 Europe Germany EUR >>> 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"} >>> session.tables.restrictions {'ROLE_FRANCE': t['Restrictions example']['Country'] == 'France', 'ROLE_GERMANY': t['Restrictions example']['Country'] == 'Germany'} >>> rose_table.query().set_index(["Continent", "Country"]).sort_index() Currency Continent Country Europe France EUR Germany EUR >>> rose_cube.query(m["contributors.COUNT"], levels=[l["Country"]]) contributors.COUNT Continent Country Europe France 1 Germany 1
Restrictions can include multiple elements:
>>> session.tables.restrictions["ROLE_NORDIC"] = table["Country"].isin( ... "Norway", "Sweden" ... ) >>> session.security.individual_roles["Rose"] |= {"ROLE_NORDIC"} >>> rose_table.query().set_index(["Continent", "Country"]).sort_index() Currency Continent Country Europe France EUR Germany EUR Norway NOK Sweden SEK >>> 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:
>>> session.tables.restrictions["ROLE_ASIA"] = table["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:
>>> session.tables.restrictions["ROLE_EUR"] = table["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_table.query() Empty DataFrame Columns: [Continent, Country, Currency] Index: [] >>> rose_cube.query(m["contributors.COUNT"], levels=[l["Country"]]) Empty DataFrame Columns: [contributors.COUNT] Index: []
See also