Modelli di controllo di accessi come tipi Haskell
Prendendo spunto dalla lettura di uno dei miei blog preferiti, mi è capitato di dare una scorsa al documento intitolato A Survey of Access Control Models, che descrive modelli di controllo di accessi di complessità crescente. Questa complessità crescente si manifesta nella dipendenza da fattori intermedi sempre più ricchi e mi è venuta la tentazione di esprimere queste dipendenze come signature di funzioni in Haskell. Ecco cosa ne è uscito fuori.
Per chi fosse digiuno di Haskell, basta sapere che:
data NuovoTipo = A | B | Cdefinisce un nuovo tipo che contiene solo i tre oggetti A, B e C. Ad esempio, il tipo Permission può essere definito così:
data Permission = Read | Write | Execute | Delete | ModifySi possono definire type alias, ad esempio
type UserPermissions = [ ( User, [ Permission ] ) ]definisce un tipo UserPermissions che consiste in liste ([ ... ]) di coppie con primo elemento uno User e secondo elemento una lista di Permission.
Un'espressione di questo tipo
funzione :: TipoPar1 -> TipoPar2 -> TipoPar3 -> TipoRisultatoè la type-signature di una funzione con parametri di tipo TipoPar1, TipoPar2, TipoPar3 e risultato di tipo TipoRisultato.
Per ogni modello, l'unica implementazione è quella della funzione getUserPerms che restituisce i permessi di un utente per una certa risorsa.
ACL (Access Control Lists)
Un modello molto semplice: i permessi dipendono solamente dall'utente e dalla risorsa.
data ACL = [ ( User, [ Permission ] ) ] getResourceACL :: Resource -> ACL getPerms :: ACL -> User -> [ Permission ] getUserPerms :: User -> Resource -> [ Permission ] getUserPerms user resource = getPerms ( getResourceACL resource ) user
L'associazione tra risorsa e ACL (la funzione getResourceACL) può essere implementata con metadati associati alla risorsa. Una possibile implementazione di getPerms consiste nel filtrare gli elementi dell'ACL che hanno l'utente di interesse e prendere poi i permessi corrispondenti, nel caso semplificato che le ACL siano implementate come array, come definito sopra.
getPerms :: ACL -> User -> [ Permission ] getPerms acl user = map snd $ filter ( ( == user ) . fst ) acl
RBAC (Role-Based Access Control)
In questo modello, ad ogni utente sono associati ruoli e i permessi dipendono solo da questi ruoli (ad esempio con ACL applicate ai ruoli e non direttamente agli utenti).
getRoles :: User -> [ Role ] getPerms :: [ Role ] -> Resource -> [ Permission ] getUserPerms :: User -> Resource -> [ Permission ] getUserPerms user resource = getPerms ( getRoles user ) resource
ABAC (Attribute-Based Access Control)
Il modello basato sugli attributi utilizza una struttura intermedia più ricca, basata su attributi che possono essere associati agli utenti (ad esempio area, qualifica, data di assunzione), alle risorse (ad esempio area, sensibilità dei dati) e all'ambiente.
data Attribute = Attribute AttrKey AttrValue getUserAttrs :: User -> [ Attribute ] getResourceAttrs :: Resource -> [ Attribute ] getEnvironmentAttrs :: [ Attribute ] getPerms :: [ Attribute ] -> [ Attribute ] -> [ Attribute ] -> Resource -> [ Permission ] getUserPerms :: User -> Resource -> [ Permission ] getUserPerms user resource = getPerms userAttrs resourceAttrs environmentAttrs resource where userAttrs = getUserAttrs user resourceAttrs = getResourceAttrs resource environmentAttrs = getEnvironmentAttrs
PBAC (Policy-Based Access Control)
In questo modello c'è un ulteriore elemento: la presenza di policy che entrano nel momento decisionale della concessione degli accessi.
data Attribute = Attribute AttrKey AttrValue getUserAttrs :: User -> [ Attribute ] getResourceAttrs :: Resource -> [ Attribute ] getEnvironmentAttrs :: [ Attribute ] getPerms :: [ Attribute ] -> [ Attribute ] -> [ Attribute ] -> Resource -> [ Policy ] -> [ Permission ] getPolicies :: [ Policy ] getUserPerms :: User -> Resource -> [ Policy ] -> [ Permission ] getUserPerms user resource = getPerms userAttrs resourceAttrs environmentAttrs resource policies where userAttrs = getUserAttrs user resourceAttrs = getResourceAttrs resource environmentAttrs = getEnvironmentAttrs policies = getPolicies
RAAC (Risk-Adaptive Access Control)
Un ulteriore elemento entra in gioco: una valutazione del rischio, che modifica dinamicamente le policy. Questo permette di avere regole più restrittive in momenti particolari (attacco hacker, fase delicata dello sviluppo di un nuovo prodotto, possibile fuga di informazioni).
data Attribute = Attribute AttrKey AttrValue getUserAttrs :: User -> [ Attribute ] getResourceAttrs :: Resource -> [ Attribute ] getEnvironmentAttrs :: IO [ Attribute ] getPerms :: [ Attribute ] -> [ Attribute ] -> [ Attribute ] -> Resource -> [ Policy ] -> [ Permission ] getPolicies :: RiskCondition -> [ Policy ] getRisk :: RiskCondition getUserPerms user resource = getPerms userAttrs resourceAttrs environmentAttrs resource policies where userAttrs = getUserAttrs user resourceAttrs = getResourceAttrs resource environmentAttrs = getEnvironmentAttrs risk = getRisk policies = getPolicies risk