Security Changes in Atoti V0.8
Aligning and simplifying coding
In case you haven’t noticed, we have one less plugin with Atoti Python API v0.8 — the atoti-plus plugin. Plus features like security and the ability to build custom UI extensions have been merged into the core modules. With this change came simplifications such as:
- Depending on our license, we can use the features that previously came with the atoti-plus plugin without having to install the plugin.
- We can streamline our code as we no longer have to import modules like security separately.
In this article, we will explore how this change simplifies our security implementation. Note, this feature is not available in the Community Edition. Explore these features by requesting an evaluation license.
Module deprecation
In v0.7.x, the atoti_plus.UserServiceClient
module is used to manage parts of the security config:
from atoti_plus import UserServiceClient
user_service_client = UserServiceClient.from_session(session)
user_service_client.basic.create_user(
"atoti_admin", password="password", roles=["ROLE_ADMIN", "ROLE_SHARE"]
)
user_service_client.basic.create_user(
"atoti_user", password="password", roles=["ROLE_SHARE"]
)
Below are the changes in v0.8.0:
- Instead of using
user_service_client
, we will usesession.security
instead. - Instead of using
create_user
, we will use credentials which is a mutable mapping.
session.security.basic.credentials.update({
"atoti_admin": "password",
"atoti_user": "password",
})
session.security.individual_roles.update({
"atoti_admin": {"ROLE_ADMIN", "ROLE_SHARE"},
"atoti_user": {"ROLE_SHARE"},
})
As we can see, instead of invoking the create_user
function each time we create a username we can invoke the credential update function to create multiple users at the same time. Also, we can grant roles to multiple users in one go.
Permission for sharing
Before v0.8.0, ROLE_SHARE
was a system-defined role that could be assigned to users for the rights to share folders, dashboards, widgets and filters.
Now, ROLE_SHARE
is no longer available. Instead, all users with the role ROLE_USER
will be granted sharing permissions. This permission is configured in the admin application using the canShare
property.
ROLE_ADMIN
assigned.Controlling sharing permissions
We can remove the default sharing permissions for all users by removing the canShare
properties or set it to false
, using ctrl+s
or cmd+s
to save the change.
To control who has permission to share, we can either grant canShare
permissions to an individual user or by a role. For instance, under the user_roles
folder, we can create a new folder for a role dedicated to sharing, e.g. ATOTI_SHARE
. Under the role folder, create a file named permissions
.
Grant the user role the canShare
permission by setting it to true
. Anyone who is granted the role ATOTI_SHARE
will be able to share now.
💡It is important to note that before v0.8.0, users were granted the role ROLE_USER
by default when we created them with basic authentication. Starting with v0.8.0, remember to grant our users this role explicitly.
Setting sharing permissions using requests
Other than updating sharing permissions using the admin web application, we can call the rest services to do so. But first, we should create a technical user to perform this backend action:
technical_user_name = "ATOTI_TECH_ADMIN"
technical_user_password = "password"
technical_user = session.security.basic.credentials[
technical_user_name
] = technical_user_password
session.security.individual_roles[technical_user_name] = {"ROLE_USER", "ROLE_ADMIN"}
💡Regardless of the type of authentication provider the session is using, we can always create a technical user using the basic authentication function as shown above.
Since we have activated security, our put request requires authentication to be passed in:
response = requests.put(
f"http://localhost:{session.port}/activeviam/content/rest/v7/files?path=ui/user_roles/ROLE_SHARE/permissions",
auth=(technical_user_name, technical_user_password),
json={
"content": '{"canShare": true}',
"owners": ["atoti_admin"],
"readers": ["ROLE_USER"],
"overwrite": True,
"recursive": True,
},
)
Restricting Access
We used to create a role and apply restrictions on it by defining a tuple containing the table and column name, mapped to the value that the role has access to.
role_inspire = user_service_client.create_role(,
"ATOTI_ROLE_INSPIRE",
restrictions={("parent_co", "parent_company"): ["Inspire Brands"]},
)
Without having to explicitly create roles in Atoti, we can now use the name of the role mapped to the conditions of the restrictions. This syntax is now consistent with how other conditions are written across Atoti.
session.security.restrictions.update(
{
"ATOTI_ROLE_INSPIRE": (base_tbl["parent_company"] == "Inspire Brands"),
"ATOTI_ROLE_RESTAURANT": (
base_tbl["parent_company"] == "Restaurant Brands International Inc."
),
}
)
Login form in place of Basic Auth Prompt
Before Atoti v0.8.0, we leveraged the Basic Authentication prompt from the browser for login when we used either basic authentication or LDAP authentication:
However, such authentication prompts can be disruptive and may negatively impact the user experience. Therefore, we now have a login page in place of the login prompt!
Using Atoti Community Edition and want to try Atoti Python API? Request an evaluation license online!