---
# System prepended metadata

title: 'TP TIW4 2020-2021 "autorisation" : rapport'

---


  
TP TIW4 2020-2021 "autorisation" : rapport  
==========================================  
  
Introduction  
------------  
  
- Numéro de binôme  
  * Molinares Diogenes 12019196  
  * Bunel Maxime 11914012  
- Nom DNS de la VM fournie  
  * 192.168.237.138  
  
Prise en main  
-------------  
  
### Identification  
  
#### Indiquer quelle sont les machines qui peuvent se connecter au serveur 

 Les machines sur sous-reseaux 192.168.237.128/27
  
#### Quel est le mode d'authentification imposé par PostgreSQL  
Authentification avec utilisateur / mot de passe
  
### Création de bases et utilisateurs  
  
#### Donner les requêtes SQL pour vérifier que les utilisateurs sont créés  
  
```sql  
-- ici les définitions  
create user lambda1 with encrypted password 'lambda1';  
create user lambda2 with encrypted password 'lambda2';  
create user adjoint with encrypted password 'adjoint';  
create user responsable with encrypted password 'responsable';  
```  
```sql  
-- ici les vérifications  
SELECT * FROM pg_roles;  
SELECT 1 FROM pg_roles WHERE rolname='lambda1'; 
SELECT 1 FROM pg_roles WHERE rolname='lambda2';  
SELECT 1 FROM pg_roles WHERE rolname='adjoint';  
SELECT 1 FROM pg_roles WHERE rolname='responsable';  
```  
 
#### Montrer que vous avez vérifié que ces utilisateurs peuvent s'authentifier depuis une autre VM  

```sql=
Avec ces commandes noux pouvons nous connecter au utilisateur

psql -U lambda1 -W -p 5432 -h 192.168.237.146 -d test
psql -U lambda2 -W -p 5432 -h 192.168.237.146 -d test
psql -U responsable -W -p 5432 -h 192.168.237.146 -d test
psql -U adjoint -W -p 5432 -h 192.168.237.146 -d test
```

  
Le modèle de contrôle d'accès _applicatif_  
------------------------------------------  
  
### Schéma de départ  
  
#### Commenter chacune des lignes du début du script ci-dessous  
  
```sql  
--Creation d'un schéma nommé rbac si il n'existe pas déjà
CREATE SCHEMA IF NOT EXISTS rbac;  
--Défini le chemin de recherche de la table test 
ALTER DATABASE "test" SET search_path TO "$user", rbac, public; 

-- Défini le chemin de recherche de la session actuelle
SET search_path TO "$user", rbac, public;  
  
-- Supprime le type de données http_method si il existe
DROP TYPE IF EXISTS http_method;  

-- Créer le type de données http_method qui est un enum qui peut avoir comme valeur (get,post,put,delete)
CREATE TYPE http_method AS ENUM ('GET', 'POST', 'PUT', 'DELETE', 'PATCH');  
```  
  
#### Expliquez ce qui change sur la hiérarchie de rôle selont qu'on prenne pour PK de `rbac.inherits` une des 4 possibilités suivantes  
  
```sql 
-- Evite les doublons dans la table, un enfant peut avoir plusieurs parents et un parent peut avoir plusieurs enfants
  PRIMARY KEY (role_id_child, role_id_parent) --celle du script
-- un enfant ne peux avoir qu'un seul parent et un parent peut avoir plusieurs enfants
  PRIMARY KEY (role_id_child)
-- un parent ne peux avoir qu'un seul enfant et un enfant peut avoir plusieurs parents
  PRIMARY KEY (role_id_parent)
-- Possibilité d'avoir des doublons
  -- pas de PK dÃ©clarÃ©e
```  
  
### Calcul des décisions d'accès  
  
#### Donner la définition et les tests de la vue `rbac.rbac_inherits_trans`  
  
```sql  
CREATE OR REPLACE RECURSIVE VIEW rbac.inherits_trans(role_id_child, role_id_parent) AS ( 
	SELECT inherits.role_id_child, inherits.role_id_parent FROM rbac.inherits inherits 
	UNION SELECT role_id, role_id FROM rbac.role 
	UNION SELECT inherits.role_id_child, trans.role_id_parent FROM rbac.inherits inherits 
	INNER JOIN inherits_trans trans ON inherits.role_id_parent = trans.role_id_child
);
```  
  
```sql  
-- ici les tests sur le jeu d'essai
SELECT * FROM rbac.inherits_trans;
```  
  
#### Donner la définition et les tests de la vue `rbac.rbac_matrix`  
  
```sql  
CREATE OR REPLACE VIEW rbac.rbac_matrix(usr_id, obj_id, act_id) AS(
    SELECT usr_id, obj_id, act_id
    FROM rbac.ura ura
    INNER JOIN rbac.pra pra ON ura.role_id = pra.role_id
);
```  
  
```sql  
-- ici les tests sur le jeu d'essai  
SELECT * FROM rbac.rbac_matrix;
```  
  
#### Donner la définition et les tests de la fonction `rbac.authorized_actions`  
  
```sql  
CREATE OR REPLACE FUNCTION rbac.authorized_actions(u_name text, o_name text)
RETURNS TABLE(action_id http_method) AS 
  $$
    SELECT DISTINCT act_id
    FROM rbac.rbac_matrix
    INNER JOIN rbac.usr usr ON usr.usr_name = u_name and usr.usr_id = rbac.rbac_matrix.usr_id
    INNER JOIN rbac.obj obj ON obj.obj_name = o_name and obj.obj_id = rbac.rbac_matrix.obj_id
  $$
  LANGUAGE SQL
  STABLE
  RETURNS NULL ON NULL INPUT;
```  
  
```sql  
-- ici les tests sur le jeu d'essai  
-- Cette commande va retourner que l'utilisateur 0 sur l'objet 0 à l'authorisation GET
select * from rbac.authorized_actions('U0', 'O0');

  action_id 
═══════════
 GET
(1 row)

-- Cette commande retour aucun resultat
select * from rbac.authorized_actions('U0', 'O1');
```  
  
#### Donner la définition et les tests de la fonction `rbac.count_auth_users`  
  
```sql  
CREATE OR REPLACE FUNCTION rbac.count_auth_users(r_id integer) 
RETURNS bigint AS 
$$ 
	SELECT count(*) 
	FROM ( -- roles fils de r_id 
		SELECT DISTINCT trans.role_id_child 
		FROM rbac.inherits_trans trans 
		WHERE trans.role_id_parent = r_id 
		UNION 
		SELECT DISTINCT ura.role_id 
		FROM rbac.ura ura 
		WHERE ura.role_id = r_id 
	) 
	childs 
	INNER JOIN rbac.ura ura ON ura.role_id = childs.role_id_child 
$$ 
LANGUAGE SQL STABLE RETURNS NULL ON NULL INPUT;
```  
  
```sql  
-- ici les tests sur le jeu d'essai  
-- On applique le fonction sur l'utilisateur 3
SELECT * FROM rbac.count_auth_users(3);

  count_auth_users 
══════════════════
                1
(1 row)

```  
  
### Extension aux sessions  
  
#### Donner les définitions des nouvelles tables et le trigger  
  
```sql  
-- ici les définitions  

CREATE TABLE IF NOT EXISTS rbac.session(
  usr_id integer REFERENCES rbac.usr(usr_id),
  role_id integer REFERENCES rbac.role(role_id),
  PRIMARY KEY (usr_id, role_id)
);

CREATE FUNCTION session_trigger() RETURNS trigger AS $session_trigger$
    BEGIN
        IF NEW.usr_id IS NULL  THEN
                RAISE EXCEPTION 'usr_id ne peut pas etre NULL.';
        END IF;
        IF NEW.role_id IS NULL  THEN
            RAISE EXCEPTION 'role_id ne peut pas etre NULL.';
        END IF;
        IF NEW.usr_id NOT IN (SELECT DISTINCT usr_id FROM rbac.usr) THEN
            RAISE EXCEPTION 'utilisateur nexiste pas';
        END IF;
        IF NEW.role_id NOT IN (SELECT DISTINCT role_id FROM rbac.role) THEN
            RAISE EXCEPTION 'Le role nexiste pas.';
        END IF;
        IF (NEW.usr_id, NEW.role_id) NOT IN (SELECT DISTINCT usr_id, role_id FROM rbac.ura) THEN
            RAISE EXCEPTION 'utilisateur ne peut pas posséder ce role.';
        END IF;
        RETURN NEW;
    END;
$session_trigger$ LANGUAGE plpgsql;


CREATE TRIGGER session_trigger BEFORE INSERT OR UPDATE ON rbac.session
    FOR EACH ROW EXECUTE PROCEDURE session_trigger();
    
    CREATE OR REPLACE FUNCTION rbac.authorized_actions_session(u_name text, o_name text)
RETURNS TABLE(action_id http_method) AS 
  $$
    select distinct act_id
    from rbac.rbac_matrix
    INNER JOIN rbac.usr usr ON usr.usr_name = u_name and usr.usr_id = rbac.rbac_matrix.usr_id
    INNER JOIN rbac.obj obj ON obj.obj_name = o_name and obj.obj_id = rbac.rbac_matrix.obj_id
    INNER JOIN rbac.session session ON session.usr_id = usr.usr_id
  $$
  LANGUAGE SQL
  STABLE
  RETURNS NULL ON NULL INPUT;


```  
  
#### Donner les tests du trigger  
  
```sql  
-- ici les tests sur le jeu d'essai
insert into rbac.session values (0,0);
-- INSERT 0 1

insert into rbac.session values (0,3);
ERROR:  P0001: utilisateur ne peut pas posséder ce role.
CONTEXT:  PL/pgSQL function session_trigger() line 16 at RAISE

insert into rbac.session values (NULL, NULL);
ERROR:  P0001: usr_id ne peut pas etre NULL.
CONTEXT:  PL/pgSQL function session_trigger() line 4 at RAISE

insert into rbac.session values (0, NULL);
ERROR:  P0001: role_id ne peut pas etre NULL.

-- l'utilisateur 1 n'existe pas sur la table session, meme s'il a le droit d'acceder sur l'objet 1
select * from authorized_actions_session('U1', 'O1');
 action_id
═══════════
(0 rows)

-- l'utilisateur 0 apparait sur la table session
select * from authorized_actions_session('U0', 'O0')
test-# ;
 action_id
═══════════
 GET
(1 row)

```  
  
Gestion des droits sur le modèle  
--------------------------------  
  
### Modèle d'administration, base  
  
#### Donner les `GRANT` et `REVOKE`  
  
```sql  
-- connection sur la bdd test
GRANT CONNECT ON DATABASE test TO public 

REVOKE ALL PRIVILEGES ON SCHEMA RBAC from PUBLIC ;
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA RBAC from PUBLIC ;
GRANT USAGE ON SCHEMA RBAC to public;
GRANT SELECT ON ALL TABLES IN SCHEMA RBAC to public;

```  
  
### Délégation à l'adjoint  
  
#### Modification de la table  
  
```sql  
ALTER TABLE rbac.role ADD delegate BOOL DEFAULT 0 NOT NULL;
```  
  
#### Donner le ROW LEVEL SECURITY pour `rbac.pra`  
  
```sql  
-- ici la définition de la politique RLS 
   
CREATE POLICY policy_adjoint_insert ON rbac.pra
    FOR INSERT
    TO adjoint
    WITH check (rbac.pra.role_id IN (
        SELECT role_id  FROM rbac.role WHERE delegate is true)
    );

CREATE POLICY policy_adjoint_update ON rbac.pra
    FOR UPDATE
    TO adjoint
    USING (rbac.pra.role_id IN (
        SELECT role_id  FROM rbac.role WHERE delegate is true)
    );


CREATE POLICY policy_adjoint_delete ON rbac.pra
    FOR DELETE
    TO adjoint
    USING (rbac.pra.role_id IN (
        SELECT role_id  FROM rbac.role WHERE delegate is true)
    );
``` 

```sql  
-- ici les tests sur le jeu d'essai  
insert into rbac.pra values (5,1,'POST');
```  
  
  
#### Donner le ROW LEVEL SECURITY pour `rbac.inherits`  
  
```sql  
-- ici la définition de la politique RLS  
CREATE POLICY policy_adjoint_in_insert ON rbac.inherits
    FOR INSERT
    TO adjoint
    WITH CHECK (rbac.inherits.role_id_parent IN (
        SELECT role_id FROM rbac.role WHERE delegate is true
    ));

CREATE POLICY policy_adjoint_in_update ON rbac.inherits
    FOR UPDATE
    TO adjoint
    WITH CHECK (rbac.inherits.role_id_parent IN (
        SELECT role_id FROM rbac.role WHERE delegate is true
    ));

CREATE POLICY policy_adjoint_in_delete ON rbac.inherits
    FOR DELETE
    TO adjoint
    USING (rbac.inherits.role_id_parent IN (
        SELECT role_id FROM rbac.role WHERE delegate is true
    ));
```  
  
```sql  
-- ici les tests sur le jeu d'essai 
select * from rbac.inherits;
```