[[TOC]] [wiki:DeveloperGuidelinesS3Framework] | S3AAA = S3 Authentication, Authorization and Accounting = '''Authentication''' is the act of establishing or confirming someone's identity.[[BR]] '''Authorization''' is the concept of allowing access to resources only to those permitted to use them.[[BR]] '''Accounting''' refers to the tracking of user actions - an audit trail. == Overview == AAA functions for S3 are implemented in the {{{modules/s3/s3aaa.py}}} module. This module extends the web2py Auth class as AuthS3 (Authentication), and defines additional classes for role management, access control and audit. ||'''Component'''||'''Location'''||'''Function'''|| ||AuthS3||modules/s3/s3aaa.py||Authentication, Login|| ||S3Permission||modules/s3/s3aaa.py||Authorization of Access, ACLs|| ||S3Audit||modules/s3/s3aaa.py||Data access logging, audit trail|| ||S3RoleManager||modules/s3/s3aaa.py||RESTful method to manage roles and ACLs|| ||Admin controllers||controllers/admin.py||User Management, role management|| == Authentication == === Current user === === Interactive Login === === HTTP Basic Authentication === == Roles == Roles are defined in the {{{auth_group}}} table, which is defined by the {{{AuthS3}}} module (in {{{modules/s3/s3aaa.py}}}).[[BR]] Each role as an ID, a unique name and an optional description. Access permissions are granted to roles, while a user gets permissions by assigning roles to him. Role assignment is stored in the {{{auth_membership}}} table, which is defined by the {{{AuthS3}}} class (in {{{modules/s3/s3aaa.py}}}). At the start of every request, the IDs of all roles of the currently logged-in user are stored as list in {{{session.s3.roles}}} (in {{{models/00_utils.py}}}. In cases where the user is logged-in during the request (e.g. by HTTP Basic Auth), a refresh of this list is also triggered by the {{{login_bare()}}} method of {{{AuthS3}}}. Roles can be managed in the {{{S3RoleManager}}} interface (Administration => User Management => Roles). The following roles are pre-defined in S3 and cannot be changed: ||'''ID'''||'''Name'''||'''Description'''|| ||1||Administrator||system administrator|| ||2||Authenticated||all authenticated users|| ||3||Creator||currently unused|| ||4||Editor||data editor|| The first registered user gets the '''Administrator''' role assigned.[[BR]] Users with the Administrator role always have all permissions, and may access all pages in Eden. The Administrator may also manage Users, Roles and ACLs. Users with the '''Editor''' role may access all data with all methods, except they can not manage Users, Roles or ACLs. Every authenticated user gets automatically the '''Authenticated''' role assigned. This role assignment cannot be revoked. == Simple Authorization == Simple authorization means, that - anonymous users have read-only permission - authenticated users have full access - the Administrator may additionally access the user management This is the fallback model wherever there are no ACLs defined. == ACLs == Access Control Lists (ACLs) are bit arrays with each bit representing a permissions to access data with a particular method: ||'''Bit'''||'''Value'''||'''Permission'''|| ||auth.permission.CREATE||0x01||may create new records|| ||auth.permission.READ||0x02||may read or list records|| ||auth.permission.UPDATE||0x04||may update existing records|| ||auth.permission.DELETE||0x08||may delete records|| ACLs are combinations of these bits (by logical OR), e.g. an ACL with the value 0x06 defines permissions to read and update records, while no permission to add or to delete any records. ACLs are stored per role and request destination in the {{{s3_permission}}} table, which is defined by the {{{S3Permission}}} class (in {{{modules/s3/s3aaa.py}}}). For every destination (controller/function/table) two ACLs can be defined to apply depending on whether a user ownes the record or not: - one ACL for users owning a record (Owner ACL = {{{oacl}}}) - one ACL for any other user not owning the record (User ACL = {{{uacl}}}). If a user ownes a record, then the most permissive of the User ACL and the Owner ACL gets applied, otherwise only the User ACL gets applied. === Record Ownership === Tables can implement a record ownership by adding two meta fields: ||'''Field name'''||'''Type'''||'''Description'''|| ||created_by||integer (reference auth_user)||ID of the user who has created this record|| ||owned_by||integer (reference auth_group)||ID of the group (role) who own the record|| These meta fields are contained in both {{{s3_authorstamp()}}} as well as {{{s3_meta_fields()}}}. A user is considered ''owner'' of a record if he has either created the record (user ID == {{{created_by}}}), or he is a member of the owner group ({{{owned_by}}} in user roles). In tables which do not define either of these meta-fields, ownership rules are not applied ({{{uacl}}} only). === !Controller/Table Restriction === ACLs can be defined for controllers, and for particular functions inside controllers.[[BR]] ACLs can additionally be defined for individual database tables. The controller ACLs are activated by setting the respective controller to {{{restricted=True}}} in {{{deployment_settings.modules}}} ({{{000_config.py}}}): {{{ dvi = Storage( name_nice = T("Disaster Victim Identification"), description = T("Disaster Victim Identification"), restricted = True, # Apply controller ACLs module_type = 10, resources = Storage( dvi_recreq = {"importer" : True}, ) ), }}} If {{{restricted}}} is {{{False}}} or not defined, then simple authorization is used for this controller. The Controller ACL can be defined for all functions in a controller, and additionally for particular functions inside a controller, where the function-specific ACLs override the general controller ACL. That means, you can define a general ACL for the {{{pr}}} controller, and a different one for the {{{pr/person}}} function. The Controller ACLs are applied to ''all'' resources when accessed through this controller/function. If the Controller ACL does not give any permission for the current user (ACL value==auth.permissions.NONE==0x00), then the request is rejected as "Unauthorized". Controllers do not have to implement this check - this is done at a central place (in {{{00_utils.py}}}). Once the user has passed that controller permission check (must have at least {{{read}}} permission), and tries to access to a particular table, then the controller checks for table-specific ACLs. This check is to be implemented by the particular controller using {{{s3_has_permission()}}} and {{{s3_accessible_query}}} (except controllers using S3CRUD only, which already contains it). '''Note:''' ''For consistency reasons, creating or deleting component records in a resource requires additional permission to update the main record, even though the main record is not changed by this operation, e.g. to add an address to a person record, you must also be permitted to update the person record.'' If there are specific ACLs defined for the table, then the most ''restrictive'' of controller and table ACLs apply (i.e. you cannot allow on the table level what you forbid at the controller level, and vice versa). If there are no specific ACLs defined for this table, then the controller ACLs apply. == Implementation of Access Control == Permission checking is always a two-step process: 1. Check permission to access the controller/function 2. Check permission to access the database table The first step is done at a central point, in {{{00_utils.py}}} before the models are loaded. If the ACLs, as defined for the current user, do not specify any permission for the target controller/function, then the request gets rejected before any models are loaded or the controller is entered. The second step has to be implemented in the respective controller functions. This can be done in two ways: - the controller uses s3_rest_controller() with S3CRUD, or, - the controller uses auth.s3_has_permission() and/or auth.s3_accessible_query() to check permissions before exposing any data to the user === s3_has_permission === === s3_accessible_query === === auth.permission.fail === In case of failure, a well-defined response action must take place: - in '''interactive''' formats: - already authenticated users should be informed about the insufficient permissions, and redirected to a (unrestricted) landing page - unauthenticated users should be requested to login, and thus forwarded to a login page - in '''non-interactive''' formats: - authenticated clients must receive a HTTP 403 (Forbidden) error code to cancel the request properly - unauthenticated clients must receive a HTTP 401 (Authorization Required) error in order to trigger an authentication attempt All this is covered by the {{{auth.permission.fail()}}} method: {{{ authorised = auth.shn_has_permission("delete", db.my_table) if not authorised: auth.permission.fail() }}} For interactive modes, you can alter the destinations for redirection by setting: - {{{auth.permission.homepage}}} for redirection when the user is logged-in, but has insufficient privileges (defaults to {{{default/index}}}). - {{{auth.permission.loginpage}}} for redirection when the user is not logged-in (defaults to {{{default/user/login}}}). Example: redirect to {{{my/index}}} rather than to {{{default/index}}} in case of insufficient privileges of an authenticated user: {{{ authorised = auth.shn_has_permission("delete", db.my_table) if not authorised: auth.permission.homepage = URL(r=request, c="my", f="index") auth.permission.fail() }}} == Data Access Tracking (Audit) == ---- [wiki:DeveloperGuidelinesS3Framework]