Home

Awesome

UsersHub-authentification-module pytestcodecov

UsersHub-authentification-module est une extension Flask permettant d'intégrer un système d'authentification et de gestion de sessions utilisateurs à son application. L'extension fournit un mécanisme d'authentification basé sur une base de données locale et permet également de se connecter via des mécanismes d'authentification externe standard (OAuth, OIDC). La gestion des session est gérée par l'extension Flask-Login.

Get Started

Installation

pip install pypnusershub

Application Flask minimale

Pour disposer des routes de connexion/déconnexion avec le protocole de connexion par défaut, le code minimal d'une application Flask est le suivant:

from flask import Flask
from pypnusershub.auth import auth_manager

app = Flask(__name__) # Instantiate a Flask application
app.config["URL_APPLICATION"] = "/" # Home page of your application
providers_config = # Declare identity providers used to log into your app
    [
      # Default identity provider (comes with UH-AM)
      {
        "module" : "pypnusershub.auth.providers.default.LocalProvider",
        "id_provider":"local_provider"
      },
      # you can add other identity providers that works with OpenID protocol (and many others !)
    ]
auth_manager.init_app(app,providers_declaration=providers_config)

if __name__ == "__main__":
  app.run(host="0.0.0.0",port=5000)

Protèger une route

Pour protéger une route en utilisant les profils de permissions, utilisez le décorateur check_auth(niveau_profil):

from pypnusershub.decorators import check_auth

@adresses.route('/', methods=['POST', 'PUT'])
@check_auth(4) # Decorate the Flask route
def insertUpdate_bibtaxons(id_taxon=None):
  pass

Si vous voulez limitez l'accès à une route uniquement aux utilisateurs connectés (qu'importe leur profils), utilisez le décorateur login_required de Flask-login

from flask_login import login_required

@adresses.route('/', methods=['POST', 'PUT'])
@login_required
def insertUpdate_bibtaxons(id_taxon=None):
  pass

Installation

Pré-requis

Installer UsersHub-authentification-module

Cloner le dépôt (ou télécharger une archive), dirigez vous dans le dossier et lancez la commande :

pip install .

Configuration de l'extension

Configuration Flask

Indiquer la route de la homepage de votre application dans la variable URL_APPLICATION

Pour manipuler la base de données, nous utilisons l'extension flask-sqlalchemy. Si votre application déclare déjà un objet flask_sqlalchemy.SQLAlchemy, déclarer le chemin python vers celui-ci dans la variable de configuration FLASK_SQLALCHEMY_DB.

os.environ["FLASK_SQLALCHEMY_DB"] = "unmodule.unsousmodule.nomvariable"

Configuration de Flask-login

Paramètres à rajouter dans la configuration ( attribut config de l'objet Flask) de votre application.

Les paramètre concernant la gestion du cookie sont gérés par flask-admin : https://flask-login.readthedocs.io/en/latest/#cookie-settings

REDIRECT_ON_FORBIDDEN : paramètre de redirection utilisé par le décorateur check_auth lorsque les droits d'accès à une ressource/page sont insuffisants (par défaut lève une erreur 403)

Lien avec UsersHub

Pour utiliser les routes de UsersHub, ajouter les paramètres suivants dans la configuration de l'application :

app.config["URL_USERSHUB"]="http://usershub-url.ext"

# Administrateur de mon application
app.config["ADMIN_APPLICATION_LOGIN"]="admin-monapplication"
app.config["ADMIN_APPLICATION_PASSWORD"]="monpassword"
app.config["ADMIN_APPLICATION_MAIL"]="admin-monapplication@mail.ext"

[!TIP] Si vous souhaitez une interface permettant de modifier les données utilisateurs décritent dans UsersHub-authentification-module, il est conseillé d'utiliser UsersHub.

Configuration de la base de données

Création des tables et schémas nécessaires

UsersHub-authentification-module s'appuit sur un schéma PostgreSQL nommé utilisateurs. Pour créer ce dernier et l'ensemble des tables nécessaires, on utilise alembic. Alembic est une librairie Python de versionnage de base de données. Chaque modification sur la base de données est décrite par une révision (e.g. /src/pypnusershub/migrations/versions/fa35dfe5ff27_create_utilisateurs_schema.py). Cette dernière indique quelles sont les actions sur la base de données à effectuer pour:

Avant de lancer la création du schéma, indiquer la nouvelle url de connexion à votre BDD dans la variable sqlalchemy.url dans le fichier alembic.ini.

sqlalchemy.url = postgresql://parcnational:<mot_de_passe>@localhost:5432/db_name

Une fois modifié, lancer la commande suivante pour remplir la base de données:

alembic upgrade utilisateurs@head

N.B. Si vous utilisez alembic dans votre projet, il est possible d'accéder aux révisions de UsersHub-authenfication-module à l'aide de la variable alembic.script_location.

Remplissage des tables pour son application

Pour utiliser votre application avec les UsersHub-authentification-module, il est nécessaire :

Ci-dessous, un exemple minimal d'une migration alembic pour utiliser UsersHub-authentification-module pour votre application

from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "id_revision"
down_revision = "id_revision_precedente"
branch_labels = "branch_votre_application"
depends_on = None


def upgrade():
    op.execute(
        """
    INSERT INTO utilisateurs.t_roles (id_role, nom_role, desc_role)
    VALUES (1, 'Grp_admin', 'Role qui fait des trucs');


    INSERT INTO utilisateurs.t_applications (id_application,code_application, nom_application,desc_application, id_parent)
    VALUES (250,'APP','votre_application','Application qui fait des trucs', NULL);

    INSERT INTO utilisateurs.t_profils (id_profil, code_profil, nom_profil, desc_profil)
    VALUES (15, 15, 'votre_profil', 'Profil qui fait des trucs');

    INSERT INTO utilisateurs.cor_profil_for_app (id_profil, id_application)
    VALUES (1, 250);

    INSERT INTO utilisateurs.cor_role_app_profil (id_role, id_application, id_profil,is_default_group_for_app)
    VALUES (1, 250, 15, true);

    """
    )


def downgrade():
    op.execute(
        """
    DELETE FROM utilisateurs.cor_role_app_profil cor
    USING
        utilisateurs.t_roles r,
        utilisateurs.t_applications a,
        utilisateurs.t_profils p
    WHERE
            cor.id_role = r.id_role
        AND cor.id_application = a.id_application
        AND cor.id_profil = p.id_profil
        AND r.nom_role = 'Grp_admin'
        AND a.code_application = 'APP'
        AND p.code_profil = 15
    """
    )

    op.execute(
        """
    DELETE FROM utilisateurs.cor_profil_app
    WHERE id_profil = 15
        AND id_application = 250;
    """
    )

    op.execute(
        """
    DELETE FROM utilisateurs.t_profils
    WHERE code_profil = 15;
    """
    )

    op.execute(
        """
    DELETE FROM utilisateurs.t_applications
    WHERE code_application = 'APP';
    """
    )

Utilisation de l'API

Ajout des routes

Les routes déclarées par le blueprint de UsersHub-authentification-module sont automatiquement ajoutés dans le blueprint de votre application lors de l'appel de la méthode init_app() de l'object AuthManager.

Routes définies par UsersHub-authentification module

Les routes suivantes sont implémentés dans UsersHub-authentification-module:

Route URIActionParamètresRetourne
/providersRetourne l'ensemble des fournisseurs d'identités activésNA
/get_current_userRetourne les informations de l'utilisateur connectéNA{user,expires,token}
/login/<provider>Connecte un utilisateur avec le provider <provider>Optionnel({user,password}){user,expires,token} ou redirect
/public_loginConnecte l'utilisateur permettant l'accès public à votre applicationNA{user,expires,token}
/logoutDéconnecte l'utilisateur courantNAredirect
/authorizeConnecte un utilisateur à l'aide des infos retournées par le fournisseurs d'identités (Si redirection vers un portail de connexion par /login){data}redirect

[!TIP] Certaines routes utilisées accessibles depuis UsersHub-authentification-module proviennent du module UsersHub. Les routes sont les suivantes :

Route URIActionParamètresRetourne
/create_tmp_userCréation d'un utilisateur temporaire en base{données sur l'utilisateur}{token}
/valid_temp_userCréation utilisateur en base dans la table t_role et ajout d'un profil avec code 1 pour une l’application donnée{token, application_id}{role}
/create_cor_role_tokenGénère un token pour utilisateur ayant l’email indiqué et stoque le token dans cor_role_token{email}{role}
/change_passwordMise à jour du mot de passe de l’utilisateur et suppression du token en base{token, password, password_confirmation}{role}
/change_application_rightModifie le profil de l’utilisateur pour l’application{id_application, id_profil, id_role}{id_role, id_profil, id_application, role}
/update_userMise à jour d'un rôle{id_role, données utilisateur}{role}

Méthodes définies dans le module

Changement du prefix d'accès aux routes de UsersHub-authentification-module

Par défaut, les routes sont accessibles depuis le préfixe /auth/. Si vous voulez changer cela, il suffit de modifier le paramètre prefix de l'appel de la méthode AuthManager.init_app() :

auth_manager.init_app(app, prefix="/authentification", providers_declaration=providers_config)

Connexion à l'aide de fournisseurs d'identités extérieurs

Depuis la version 3.0, il est possible d'ajouter la possibilité de se connecter à des fournisseurs d'identités externes utilisant d'autres protocoles de connexion : OpenID, OpenID Connect, CAS (INPN), etc. ...

Utiliser les protocoles de connexions existant

Lors de l'appel de AuthManager.init_app, il faut indiquer les configurations des différents fournisseurs d'identités sur lesquels on souhaite se connecter dans le paramètre providers_declaration.

Pour chaque configuration, on doit déclarer :

from flask import Flask
from pypnusershub.auth import auth_manager

app = Flask(__name__) # Instantiate a Flask application
app.config["URL_APPLICATION"] = "/" # Home page of your application
providers_config = # Declare identity providers used to log into your app
    [
      # Default identity provider (comes with UH-AM)
      {
        "module" : "pypnusershub.auth.providers.default.LocalProvider",
        "id_provider":"local_provider"
      },
      # Other identity provider
      {
        "module": "pypnusershub.auth.providers.openid_provider.OpenIDProvider",
        "id_provider":"open_id_1",
        "ISSUER":"http://<realmKeycloak>",
        "CLIENT_ID":"secret",
        "CLIENT_SECRET":"secret"
      }

      # you can add other identity providers that works with OpenID protocol (and many others !)
    ]
auth_manager.init_app(app,providers_declaration=providers_config)

if __name__ == "__main__":
  app.run(host="0.0.0.0",port=5200)

Pour lancer la connexion sur un provider en particulier, il suffit d'appeler la route /login/<id_provider>.

Paramètres de configurations des protocoles de connexions inclus

OpenID et OpenIDConnect.

UsersHub-authentification-module

CAS INPN

Ajouter son propre protocole de connexion

L'ensemble des protocoles de connexion dans UsersHub-authentification-module n'est pas exhaustif et peut dans certains cas ne pas convenir à votre contexte. Pas de panique ! Il est possible de déclarer son propre protocole à l'aide de la classe Authentication comme dans l'exemple ci-dessous :

from marshmallow import Schema, fields
from typing import Any, Optional, Tuple, Union

from pypnusershub.auth import Authentication, ProviderConfigurationSchema
from pypnusershub.db import models, db
from flask import Response


class NEW_PROVIDER(Authentication):
    is_external = True # go through an external connection portal

    def authenticate(self, *args, **kwargs) -> Union[Response, models.User]:
        pass # return a User or a Flask redirection to the login portal of the provider

    def authorize(self):
        pass # must return a User

    def revoke(self):
        pass # if specific action have to be made when logout

    def configure(self, configuration: Union[dict, Any]):
        pass # Indique la configuration d'un fournisseur d'identités

Un protocole de connexion est défini par 5 méthodes et plusieurs attributs.

Les attributs sont les suivants

Les méthodes sont les suivantes :

Schéma de la base de données

[!IMPORTANT]

Concepts essentiels

Profil: Concept associé à un nom et à un niveau de permission. Provider: Concept associé à celui de fournisseurs d'identités. Service (Google, INPN, ORCID,...) qui permet de s’identifier et qui utilise un protocole de connexion (e.g. OAuth) Listes: Groupe d'utilisateurs

Structure de la base

Le diagramme ci-dessous décrit les différentes tables du schéma utilisateurs, leurs attributs et leur relations.

classDiagram
class t_roles {
  -id_role: int
  -uuid_role
  -identifiant: str
  -nom_role: str
  -prenom_role: str
  -pass: str
  -pass_plus: str
  -groupe: bool
  -id_organisme: int
  -remarques: str
  -champs_addi: dict
  -date_insert: datetime
  -date_update: datetime
  -active: bool
}
class temp_users{
  -id_temp_user: int
  -token_role: str
  -identifiant: str
  -nom_role: str
  -prenom_role: str
  -password: str
  -pass_md5: str
  -groupe: bool
  -id_organisme: int
  -remarques: str
  -champs_addi: dict
  -date_insert: datetime
  -date_update: datetime
}

class bib_organismes {
  -id_organisme: int
  -uuid_organisme: UUID
  -nom_organisme: str
  -adresse_organisme: str
  -cp_organisme: str
  -ville_organisme: str
  -tel_organisme: str
  -fax_organisme: str
  -email_organisme: str
  -url_organisme: str
  -url_logo: str
  -id_parent: int
  -additional_data: dict
}
class t_profils {
  -id_profil: int
  -code_profil: str
  -nom_profil: str
  -desc_profil: str
}
class t_listes{
  -id_liste:int
  -code_list:str(20)
  -nom_liste:str(50)
  -desc_liste:str
}
class t_applications {
  -id_application: int
  -code_application: str(20)
  -nom_application: str(50)
  -desc_application: str
  -id_parent: int
}

class t_providers {
  -id_provider:int
  -name:str
  -url:str
}

class cor_role_liste{
  -id_role:int
  -id_liste:int
}

class cor_roles{
  -id_role_groupe:int
  -id_role_utilisateur:int
}
class cor_profil_for_app{
  -id_profil
  -id_application
}
class cor_role_profil_app {
  -id_role: int
  -id_profil: int
  -id_application: int
}

class cor_role_token{
  -id_role:int
  -token:str
}

class cor_role_provider{
  -id_provider:int
  -id_role:int
}


t_roles --* t_roles

t_roles --* bib_organismes
temp_users --* bib_organismes
bib_organismes *-- bib_organismes

cor_role_profil_app *-- t_applications
cor_role_profil_app *-- t_profils
cor_role_profil_app *-- t_roles

cor_roles *-- t_roles

cor_role_token *-- t_roles

cor_role_liste *-- t_roles
cor_role_liste *-- t_listes

cor_role_provider *-- t_roles
cor_role_provider *-- t_providers

cor_role_token *-- t_roles

cor_profil_for_app *-- t_profils
cor_profil_for_app *-- t_applications

Fonctions des tables

Nom tableDescription
bib_organismesContient les organismes
t_rolesContient les utilisateurs
t_profilsPermet de définir les profils de permissions
t_providersContient les fournisseurs d'identités dans l'applications
t_applicationsListe les applications qui utilisent UsersHub-authentification-module
temp_usersPermet de créer des utilisateurs temporaires (en attente de validation par l'administrateur)
cor_profil_for_appPermet d'attribuer et limiter les profils disponibles pour chacune des applications
cor_role_app_profilCette table permet d'associer des utilisateurs à des profils par application
cor_role_listCette table permet d'associer des utilisateurs à des listes d'utilisateurs
cor_role_providerCette table permet d'associer des utilisateurs à des fournisseurs d'identités
cor_role_tokenPermet d'associer des utilisateurs à des tokens
cor_rolesPermet d'associer des utilisateurs entre eux (groupes et utilisateurs)