Bloks

Blok Auth

class anyblok_pyramid.bloks.auth.Auth(registry)

Bases: anyblok.blok.Blok

author = 'Jean-Sébastien Suzanne'
conditional_by = []
conflicting_by = []
classmethod import_declaration_module()

Do the python import for the Declaration of the model or other

name = 'auth'
optional_by = []
classmethod reload_declaration_module(reload)
required = ['anyblok-core', 'pyramid']
required_by = ['auth-password', 'authorization', 'user-identity']
version = '0.1.0'

How to use it

This blok define a User model and add the basics of Pyramid Authentication and Authorization policy. It is required by the ‘password’ and ‘authorization’ bloks. Used alone it adds :

  • Pyramid.User and Pyramid.Role models
  • login / logout extendable views (That will throw an exception until you require ‘password’ and ‘authorization’ bloks into your project.)

Basically you can:

  • Create a new user:

    user = registry.Pyramid.User.insert(login='jssuzanne')
    user.login  # jssuzanne
    
  • Add a role to the created user:

    role = registry.Pyramid.Role.insert(
        name='admin',
        label='Administrator'
    )
    user.roles.append(role)
    
    user.roles # [<Model.Pyramid.Role(children=[], label='Administrator', name='admin', parents=<not loaded>, users=<Model.Pyramid.User len(1)>)>]
    role.users # [<Model.Pyramid.User(login='jssuzanne', roles=<Model.Pyramid.Role len(1)>)>]
    
  • Check a permission for a user to use a resource:

    from anyblok_pyramid.security import AnyBlokResourceFactory
    
    @view_config(
        route_name='my_view',
        factory=AnyBlokResourceFactory('my_resource')
        permission='my_permission'
    )
    def my_view(request):
        return Response('Ok I have the permission')
    

Warning

Remember that until you had credential behaviours, the ‘login’ view from ‘auth.views’ will raise an ‘HTTPUnauthorized’ exception.

User

class anyblok_pyramid.bloks.auth.user.User

Bases: object

User declaration need for Auth

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid.User
  • Tablename: pyramid_user
Fields  
login
  • Type - anyblok.column.String
  • primary_key - True
  • nullable - False
  • default - anyblok.column.NoDefaultValue
  • size - 64
classmethod check_acl(login, resource, type_)

Overwrite the method to return the ACL for the resource and user

Parameters:
  • login – str, login of the user
  • resource – str, name of the resource
  • type – str, name of the action
classmethod check_login(login=None, password=None, **kwargs)

Check login / password

This method raise an exception, because any credential is stored in this bloks

Warning

This method must be overwriting by anycredential blok

Parameters:
  • login – str, the login attribute of the user
  • password – str
  • kwargs – any options need to validate credential
classmethod get_acl(login, resource, params=None)

Retun the ACL for a ressource and a user

Auth, does not implement any rule to compute ACL, This method allow all user to use the resource ask by controllers.

For other configuration, this method must be overwrite

Parameters:
  • login – str, login attribute of the user
  • resource – str, name of a resource
  • params – all options need to compute ACL
classmethod get_login_location_to(login, request)

Return the default path after the login

classmethod get_logout_location_to(request)

Return the default path after the logout

classmethod get_roles(login)

Return the roles of an user

Parameters:login – str, login attribute of the user
Return type:list of str (name of the roles)
login = <anyblok.column.String object>

Role

class anyblok_pyramid.bloks.auth.role.Role

Bases: object

Role, allow to group some authorization for an user

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid.Role
  • Tablename: pyramid_role
Fields  
name
  • Type - anyblok.column.String
  • primary_key - True
  • nullable - False
  • default - anyblok.column.NoDefaultValue
  • size - 64
label
  • Type - anyblok.column.String
  • nullable - False
  • default - anyblok.column.NoDefaultValue
  • size - 64
children
  • Type - anyblok.relationship.Many2Many
  • backref - 'parents'
  • model - Model.Pyramid.Role
  • remote_columns - None
  • m2m_remote_columns - None
  • local_columns - None
  • m2m_local_columns - None
  • compute_join - False
users
  • Type - anyblok.relationship.Many2Many
  • backref - 'roles'
  • model - Model.Pyramid.User
  • remote_columns - None
  • m2m_remote_columns - None
  • local_columns - None
  • m2m_local_columns - None
  • compute_join - False
roles_name
  • Type - anyblok.field.Function
  • fget - 'get_all_roles_name'
classmethod before_update_orm_event(mapper, connection, target)

Check if the role has not any cyclical dependencies

children = <anyblok.relationship.Many2Many object>
get_all_roles_name()

Return all the name of the roles self and dependencies

label = <anyblok.column.String object>
name = <anyblok.column.String object>
roles_name = <anyblok.field.Function object>
users = <anyblok.relationship.Many2Many object>

Views

Define views for login and logout. Those views are not automatically applied to your project. You must declare the route to use them in the pyramid_load_config method of your project blok.

First import them in your blok definition __init__.py file:

from anyblok_pyramid.bloks.auth.views import login, logout

Then set route path in pyramid_load_config method:

def pyramid_load_config(cls, config):
config.add_route(‘login’, ‘/login’, request_method=’POST’) config.add_view(view=login, route_name=’login’, renderer=”JSON”) config.add_route(‘logout’, ‘/logout’, request_method=’POST’) config.add_view(view=logout, route_name=’logout’)
anyblok_pyramid.bloks.auth.views.login(request)

Default view to login a user

anyblok_pyramid.bloks.auth.views.logout(request)

Default view to logout a user

Configuration

Define the authentification / authorization policies, This depend on the options defined in global configuration.

Exceptions

exception anyblok_pyramid.bloks.auth.exceptions.RecursionRoleError

Simple exception to check if the roles is cyclic

Blok Password

class anyblok_pyramid.bloks.password.Password(registry)

Bases: anyblok.blok.Blok

author = 'Jean-Sébastien Suzanne'
conditional_by = []
conflicting_by = []
classmethod import_declaration_module()

Do the python import for the Declaration of the model or other

name = 'auth-password'
optional_by = []
classmethod reload_declaration_module(reload)
required = ['auth']
required_by = []
version = '0.1.0'

How to use it

This Blok add Pyramid.CredentialStore model, a simple login / password table. You can not add credential for an unexisting user because one foreign key constraint is defined between both.

  • Before all you must create a new user:

    user = registry.Pyramid.User.insert(login='jssuzanne')
    
  • Then define a credential for this user:

    user_credential = registry.Pyramid.CredentialStore.insert(
        login=user.login,
        password='secret password',
    )
    
  • At this point you can check if a given password is the good one:

    user_credential.password == "not the good one" # False
    user_credential.password == "secret password" # True
    
  • You can also use ‘registry.Pyramid.User.check_login’ method to check that a password and a login match:

    registry.Pyramid.User.check_login(login='jssuzanne', password='a bad one') # Will raise an HTTPUnauthorized exception
    registry.Pyramid.User.check_login(login='jssuzanne', password='secret password') # 'jssuzanne'
    

Note

The password use the Password column, the value is an encrypted string in database and can not be revealed during the execution of the application, you can only compare it.

User

class anyblok_pyramid.bloks.password.user.CredentialStore

Bases: object

Simple login / password table

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid.CredentialStore
  • Tablename: pyramid_credentialstore
Fields  
login
  • Type - anyblok.column.String
  • primary_key - True
  • nullable - False
  • foreign_key - Model.Pyramid.User => login
  • default - anyblok.column.NoDefaultValue
  • size - 64
password
  • Type - anyblok.column.Password
  • nullable - False
  • default - anyblok.column.NoDefaultValue
  • size - 64
login = <anyblok.column.String object>
password = <anyblok.column.Password object>
class anyblok_pyramid.bloks.password.user.User

Bases: object

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid.User
  • Tablename: pyramid_user
classmethod check_login(login=None, password=None, **kwargs)

Overwrite the initial method to check if the given login match with an existing user that has the same password.

Parameters:
  • login – str
  • password – str
Exception:

HTTPUnauthorized

Blok Authorization

class anyblok_pyramid.bloks.authorization.Authorization(registry)

Bases: anyblok.blok.Blok

author = 'Jean-Sébastien Suzanne'
conditional_by = []
conflicting_by = []
classmethod import_declaration_module()

Do the python import for the Declaration of the model or other

name = 'authorization'
optional_by = []
classmethod reload_declaration_module(reload)
required = ['auth']
required_by = []
version = '0.1.0'

How to use it

This blok helps defining authorization for User or Role on a resource or model.

  • Create an user:

    user = registry.Pyramid.User.insert(login='jssuzanne')
    
  • Add an authorization for the user to access a Pyramid resource:

    registry.Pyramid.Authorization.insert(
        resource='something',
        user=user,
        perm_create=dict(matched=True),
        perm_read=dict(matched=True),
        perm_update=dict(matched=True),
        perm_delete=dict(matched=True)
    )
    
    registry.Pyramid.Authorization.get_acl('jssuzanne', 'something')
    #  [
    #      (Allow, 'jssuzanne', ['create', 'delete', 'read', 'update']),
    #      (Deny, 'jssuzanne', ALL_PERMISSIONS),
    #  ]
    
  • An user can have roles, this way you can define an authorization for a role and all users that have this role will be authorized:

    role = registry.Pyramid.Role.insert(
        name='admin',
        label='Administrator'
    )
    user.roles.append(role)
    
    registry.Pyramid.Authorization.insert(
        resource='otherthing',
        role=role,
        perm_create=dict(matched=True),
        perm_read=dict(matched=True),
        perm_update=dict(matched=True),
        perm_delete=dict(matched=True)
    )
    
    registry.Pyramid.Authorization.get_acl('jssuzanne', 'otherthing')
    #  [
    #      (Allow, 'jssuzanne', ['create', 'delete', 'read', 'update']),
    #      (Deny, 'jssuzanne', ALL_PERMISSIONS),
    #  ]
    

The permission is stored in a Json column, the permissions can be CRUD or any other one that is defined.

Each permission can defined three keys:

  • condition: Query.filter_condition, if it’s empty then the condition is marked as True
  • matched: If condition is True, the entry indicate the value (default None)
  • unmatched: If condition is False, the entry indicate the value (default None)

matched and unmatched can have three values:

  • True: Add the permission in Allow list,
  • False: Add the permission in the Deny list,
  • None: Do nothing, because this rule can not Allow or Deny

User

class anyblok_pyramid.bloks.authorization.user.User

Bases: object

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid.User
  • Tablename: pyramid_user
classmethod check_acl(login, resource, type_)

Overwrite the method to return the ACL for the resource and user

Parameters:
  • login – str, login of the user
  • resource – str, name of the resource
  • type – str, name of the action
classmethod get_acl(login, resource, params=None)

Overwrite the method to return the ACL for the resource and user

Parameters:
  • login – str, login of the user
  • resource – str, name of the resource

Authorization

class anyblok_pyramid.bloks.authorization.authorization.Authorization

Bases: object

A model to store autorization rules (permissions for users against an Anyblok model or a Pyramid resource)

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid.Authorization
  • Tablename: pyramid_authorization
Fields  
id
  • Type - anyblok.column.Integer
  • primary_key - True
  • autoincrement - True
  • default - anyblok.column.NoDefaultValue
code
  • Type - anyblok.column.String
  • nullable - True
  • unique - True
  • default - anyblok.column.NoDefaultValue
  • size - 256
order
  • Type - anyblok.column.Integer
  • nullable - False
  • default - 100
resource
  • Type - anyblok.column.String
  • default - anyblok.column.NoDefaultValue
  • size - 64
model
  • Type - anyblok.column.String
  • foreign_key - Model.System.Model => name
  • default - anyblok.column.NoDefaultValue
  • size - 256
primary_keys
  • Type - anyblok.column.Json
filter
  • Type - anyblok.column.Json
role
  • Type - anyblok.relationship.Many2One
  • model - Model.Pyramid.Role
  • index - False
login
  • Type - anyblok.column.String
  • foreign_key - Model.Pyramid.User => login
  • default - anyblok.column.NoDefaultValue
  • size - 64
user
  • Type - anyblok.relationship.Many2One
  • model - Model.Pyramid.User
  • index - False
perms
  • Type - anyblok.column.Json
perm_create
  • Type - anyblok.field.JsonRelated
  • json_column - 'perms'
  • keys - 'create'
perm_read
  • Type - anyblok.field.JsonRelated
  • json_column - 'perms'
  • keys - 'read'
perm_update
  • Type - anyblok.field.JsonRelated
  • json_column - 'perms'
  • keys - 'update'
perm_delete
  • Type - anyblok.field.JsonRelated
  • json_column - 'perms'
  • keys - 'delete'
classmethod before_insert_orm_event(mapper, connection, target)
classmethod before_update_orm_event(mapper, connection, target)
classmethod check_acl(login, resource, type_)

Return the Pyramid ACL in function of the resource and user

Parameters:
  • login – str, login of the user
  • resource – str, name of the resource
  • type – str, name of the action
check_validity()

When creating or updating a User.Authorization, check that all rules objects exists or return an AuthorizationValidationException

Exception:AuthorizationValidationException
code = <anyblok.column.String object>
classmethod ensure_exists(code, **kwargs)

Ensure role’s authorization is present

Parameters:
  • code – String, authorization code.
  • kwargs – authorization fields
filter = <anyblok.column.Json object>
classmethod get_acl(login, resource, params=None)

Return the Pyramid ACL in function of the resource and user

Parameters:
  • login – str, login of the user
  • resource – str, name of the resource
classmethod get_acl_filter_model()

Return the Model to use to check the permission

id = <anyblok.column.Integer object>
login = <anyblok.column.String object>
model = <anyblok.column.String object>
order = <anyblok.column.Integer object>
perm_create = <anyblok.field.JsonRelated object>
perm_delete = <anyblok.field.JsonRelated object>
perm_read = <anyblok.field.JsonRelated object>
perm_update = <anyblok.field.JsonRelated object>
perms = <anyblok.column.Json object>
primary_keys = <anyblok.column.Json object>
resource = <anyblok.column.String object>
role = <anyblok.relationship.Many2One object>
user = <anyblok.relationship.Many2One object>

Exceptions

class anyblok_pyramid.bloks.authorization.exceptions.AuthorizationValidationException

Bases: Exception

Simple exception when Authorization entry is wrong

Blok Pyramid

class anyblok_pyramid.bloks.pyramid.Pyramid(registry)

Bases: anyblok.blok.Blok

author = 'Jean-Sébastien Suzanne'
conditional_by = []
conflicting_by = []
classmethod import_declaration_module()

Do the python import for the Declaration of the model or other

name = 'pyramid'
optional_by = []
classmethod pyramid_load_config(config)
classmethod reload_declaration_module(reload)
required = ['anyblok-core']
required_by = ['auth']
version = '0.1.0'

Pyramid Blok

OpenID Connect

This blok provide an integration with oic an OpenID Connect library, to make your service an Relying Party (not a provider).

The api documentation.

Requirements

  • install OIDC’s extra requirements:

    pip install anyblok_pyramid[oidc]
    
  • confiugre a server session management (we suggest to use anyblok_pyramid_beaker

Configuration

Following settings are available:

--oidc-provider-issuer OIDC_PROVIDER_ISSUER
                      he OIDC Provider urls (ie: https://gitlab.com)
--oidc-relying-party-callback OIDC_RELYING_PARTY_CALLBACK
                      The Relaying Party callback, once the user is
                      authenticate on the OIDC provider he will be redirect
                      to that uri to the RP service (ie:
                      http://localhost:8080/callback). In general this value
                      is also configured in your OIDC provider to avoid
                      redirection issues.
--oidc-relying-party-client-id OIDC_RELYING_PARTY_CLIENT_ID
                      The client id to authenticate the relying party (this
                      application) to the OIDC provider. This information
                      should be provide by your OIDC provider.
--oidc-relying-party-secret-id OIDC_RELYING_PARTY_SECRET_ID
                      The secret id to authenticate the relying party (this
                      application) to the OIDC provider. This information
                      should be provide by your OIDC provider.
--oidc-scope OIDC_SCOPE
                      Specify what access privileges are being requested for
                      Access Tokens. `cf Requesting claims using scope
                      values <https://openid.net/specs/openid-connect-
                      core-1_0.html#ScopeClaims`_. a list of claims
                      usingcoma separator.
--oidc-userinfo-field OIDC_USERINFO_FIELD
                      Specify which field to use from the response of the
                      OIDC provider `userinfo endpoint
                      <https://openid.net/specs/openid-connect-
                      core-1_0.html#UserInfoResponse>`_. To make sure it's a
                      known user

Pyramid

Pyramid model

class anyblok_pyramid.bloks.pyramid.model.Pyramid

Bases: object

AnyBlok registration:

  • Type: Model
  • Registry name: Model.Pyramid
  • Tablename: pyramid
classmethod check_acl(login, resource, type_)

Retun True if user is allowed to make action type of the resource

This method must be ober writting by the auth blok

Parameters:
  • login – str, login attribute of the user
  • resource – str, name of a resource
  • type – str, name of the action
  • params – all options need to compute ACL
classmethod check_login(**kwargs)

Check login / password

This method raise an exception, because any credential is stored in this bloks

Warning

This method must be overwriting by anycredential blok

Parameters:kwargs – any options need to validate credential
classmethod check_user_exists(login)
classmethod format_login_params(request)

Return the login and password from query

By default the query come from json_body and are named login and password

If the entries come from another place, this method must be overwrite :param request: the request from the controllers

classmethod get_acl(login, resource, params=None)

Retun the ACL for a ressource and a user

Auth, does not implement any rule to compute ACL, This method allow all user to use the resource ask by controllers.

For other configuration, this method must be overwrite

This method must be ober writting by the auth blok

Parameters:
  • login – str, login attribute of the user
  • resource – str, name of a resource
  • params – all options need to compute ACL
classmethod get_roles(login)

Return the roles of an user

This method must be ober writting by the auth blok

Parameters:login – str, login attribute of the user
Return type:list of str (name of the roles)
classmethod get_user(user_id)

Return user for a given user_id, to be overwrite in user bloks The method is called by get_user cached method to retreive user while restricting query by user.

Warning

User cache invalidation must be done by developer.

Parameters:user_id – This is the user primary key (could be a loging according the User class definition)
Return User (instance ?) or None:
 retreive the user for the given user_id
classmethod restrict_query_by_user(query, user_code)

Call registered decorated method (by from anyblok_pyramid.bloks.pyramid.restrict.restrict_query_by_user) to add filters on current query according the selected model.

Parameters:query – A query object which you have to add filters
User_code:User primary key value used to retreive users.

Note

This method is using get_user which cached user instance, you have to manage or mind to cache invalidation while using this method.

class anyblok_pyramid.bloks.pyramid.restrict.RestrictQueryByUserIdPlugin(registry)

Bases: anyblok.model.plugins.ModelPluginBase

An AnyBlok plugin that helps to add extra filters on queries according the current user

transform_base_attribute(attr, method, namespace, base, transformation_properties, new_type_properties)

Find restricted methods in the base to save the namespace and the method in the registry :param attr: attribute name :param method: method pointer of the attribute :param namespace: the namespace of the model :param base: One of the base of the model :param transformation_properties: the properties of the model :param new_type_properties: param to add in a new base if need

anyblok_pyramid.bloks.pyramid.restrict.restrict_query_by_user()

OIDC utility