¡Esta es una revisión vieja del documento!
Es una librería para desarrollar la autorización a recursos de un sistema.
Usa un lenguaje propio denominado Polar, con este se definen una serie de reglas. Luego, desde Python se realizará la pregunta a Oso si tal usuario tiene un acceso concreto (que podría ser lectura, escritura…) a un recurso. Oso pasará esa pregunta por la serie de reglas y se obtendrá un booleano con la respuesta.
El código en Polar es interpretado en tiempo de ejecución.
Por defecto Polar rechaza el acceso a un recurso a no ser que la política diga lo contrario.
Un actor es el elemento que hace una acción sobre un recurso. Es la base del funcionamiento de oso con esta misma terminología.
Enforcement es la acción de decidir la autorización en un punto concreto.
Autorización basada en RBAC (roles, Role Based Access control) es aquella en la que se asigna uno o varios roles a un actor. Un rol es un grupo de permisos.
Autorización basada en ReBAC (relaciones, Relationship Based Access control) es aquella en la que el actor y el recurso comparten una relación (un comentario “creado” por un usuario, un usuario “es dueño” de un repositorio, un usuario “pertenece” a un equipo).
Autorización basada en ABAC (atributos, Attribute Based Access control) es aquella en la que el actor tendrá acceso al recurso dependiendo en el valor de alguno de sus atributos (ya sea del mismo actor o del recurso en sí). Por ejemplo un actor marcado como administrador puede acceder a todos los recursos.
Un atributo puede ser cualquier cosa, incluso un rol o una relación. Incluso un rol podría ser una forma de relación. Por eso RBAC y ReBAC se consideran subsets de ABAC. Pero pongamos por ejemplo un atributo público en un repositorio, cualquier usuario puede acceder a ese repositorio si lo tiene marcado como tal. Esto no es ni una relación ni un rol.
Tras inicializar Oso en tu aplicación podrás llamar a las siguientes funciones de la instancia:
load_file para cargar el archivo .polar.
register_class para añadir el acceso a un nuevo tipo personalizado al código en Polar.
is_allowed(actor, action, resource) es el método para realizar el enforcing. El que responde si está o no autorizado a acceder de esa forma a ese recurso.
enable_roles
Inicializando FlaskOso en la aplicación de Flask permite realizar ciertas acciones sobre la librería tales como…
require_authorization para indicar que ninguna request podrá devolver una response si no se ha llamado a un código de autorización desde dentro, si ocurre saltará una excepción. Siempre se podrá llamar a skip_authorization para que no salte la excepción.
authorize(action, resource) es un hook que llama a is_allowed pero sin necesidad de indicar el actor ya que este lo toma de flask.g.current_user. Si falla devuelve un 403. Para indicar una alternativa de dónde tomar el actor se usa la función set_get_actor.
Para cambiar el comportamiento de un fallo de autenticación se usa set_unauthorized_action.
Los decoradores @authorize y @skip_authorization permiten realizar estas acciones antes de entrar al código.
perform_route_authorization permite que a @authorize se le pase como parámetro la request. El código sería algo parecido a lo siguiente:
from flask import request
@flask_oso.authorize(resource=request)
@app.route("/")
def route():
return "authorized"
Y en Polar:
# Allow any actor to make a GET request to "/".
allow(_actor, "GET", _resource: Request{path: "/"});
Se pueden añadir tantas funciones\reglas con el mismo nombre como se quiera, no se sobreescriben sino que se añaden.
La regla principal y que ha de existir es allow(actor, acción, documento).
Si el usuario es el dueño del gasto:
allow(user: User, "read", expense: Expense) if
user.id = expense.user_id;
Si el usuario es contable o contable senior:
user_in_role(user: User, "accountant") if
user.title = "Accountant";
user_in_role(user: User, "accountant") if
user.title = "Senior Accountant";
allow(user: User, "read", _expense: Expense) if
user_in_role(user, "accountant");
El siguiente fichero Polar indica que cualquier actor con el rol guest puede leer una página, pero olo actores con el rol admin pueden escribirla.
allow(actor, action, resource) if
role_allows(actor, action, resource);
actor_has_role_for_resource(actor, role_name, resource) if
role in actor.get_roles() and
role_name = role.name and
resource = role.resource;
resource(_type: Page, "page", actions, roles) if
actions = ["read", "write"] and
roles = {
guest: {
permissions: ["read"]
},
admin: {
permissions: ["write"],
implies: ["guest"]
}
};
Existe la regla principal allow. En este caso la decisión la toma otra regla propia de Polar denominada role_allows que implementa la lógica para el RBAC.
La ruta para el RBAC es una combinación de otras funciones actor_has_role_for_resource y resource.
La regla actor_has_role_for_resource(actor, role_name, resource) ha de devolver si un objeto rol está asociado a un actor. Esta regla es necesaria ya que es la que se buscará por las reglas internas de Oso.
❓En este caso o siempre (?) los roles tienen el formato {name: “the-role-name”, resource: TheResourceObject}.