Vous êtes sur la page 1sur 12

Dime quien eres y te dire donde puedes acceder

El proposito de este articulo es proponer un esquema de seguridad para contolar el acceso de los usuarios a las diferentes partes del programa. Se pretende que sea flexible y facilmente adaptable a cualquier aplicacin que necesite atacar esta problematica. Para ello vamos a hacer uso de patrones de diseo y en especial del patrn composite. El cdigo que aqui se muestra esta escrito en Delphi aunque el concepto se puede adaptar a cuanquier otro lenguaje como Java o C#. El esquema ms simple de seguridad que se nos propone es tener un conjunto de usuarios y un conjunto de funcionalidades a las que estos pueden acceder, ya sea partes del programa, mdulos u opciones de men. Luego debemos relacionar los elementos de un ambos conjuntos para indicar los accesos permitidos. A partir de all podemos definir esquemas de seguridad mas complejos. Esto describe basicamente la problemtica que vamos a tratar. El tema del acceso a la aplicacin, por ejemplo, mediante el ingreso del nombre usuario y password no es un tema que veamos aqu. Los Usuarios Habiendo descripto la situacin, concentrmonos ahora en los usuarios que van a usar nuestra aplicacin. Para ello definimos que en nuestro sistema tenemos nuestra clase TUsuario como se muestra en el siguiente diagrama:

TUsuario Nombre : string

Pero si a nuestra aplicacin la usan muchos usuarios a la vez, es posible que muchos de ellos accedan a la mismas opciones de menu y usen la aplicacin de la misma manera. Esto ya sea porque desarrollen la misma funcion o tengan el mismo perfil. Eso nos lleva a pensar la posibilidad de agrupar muchos usuarios. Siguiendo ese esquema podemos llegar a

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

TGrupoUsuarios

TUsuario Nombre : string

Casi todos los sitemas con los que llegu a conocer mantenan un esquema similar. Fijense que le estamos considerando la posibilidad de que un usuario pertenezca a mas de un grupo distinto. Esto presenta una limitacin. No podemos incluir un subconjuntos de usuarios dentro de otro. Por ejemplo, un un sistema de una facultad: definimos el grupo de todos los usuarios de los que asisten a la institucion (estudiantes, docentes, no-docentes, etc) que tienen determinados permisos dentro del sistema. Dentro de estos tenemos a los docentes. Es de esperar que estos ltimos puedan lo mismo que los que asisten a la facultad ms tareas adicionales como inscribir alumnos en sus cursos, etc. Hasta el momento no me he topado con ningun sitemas que permitan esta flexibilidad (claro que hay muchisimos que nunca use). Para modelar esta situacin podemos recurrir al patrn Composite. A continuacin mostramos una aproximacin de lo que queremos conseguir:
TUsuarioComposite Nombre : string Add() Remove()

TUsuario

TGrupoUsuarios

Fijense que an conservamos el poder seguir trabajar slo con usuarios dentro de grupos y nada mas. Las funcionalidades De la misma manera que los usuarios vamos a pasar ahora atratar el conjunto de funciones u opciones de men o como deseemos llamarle. Para este caso practico vamos a suponerlas representadas en nuestra clase TFuncionalidad y al igual que antes podemos agruparlas en TGrupoFuncionalidades.

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

Si recurrimos al mismo planteo que hicimos para los usuarios podemos llegar a un resultado similar. Visualismoslo de la siguiente manera: nuestro sistema de la facultad emite reportes. A su vez estos puedan ser reportes para los alumnos y reportes para los profesores. Dentro de estos subgrupos ubicamos los reportes concretos que el los alumnos y los profesores puede ver. Podemos volver a modelarlo con un composite. Para evirar los razonamientos intermedios pues son muy similares para el caso de los usuarios, directamente podremos el resultado:

TFuncionalidadComposite NombreOpcion Contains(F : TFuncionalidadComposite) : boolean Ejecutar() SubFuncionalidades TFuncionalidad Ejecutar()

TGrupoFuncionalidades Add(AFuncionalidad : TFuncionalidadComposite) Remove(AFuncionalidad : TFuncionalidadComposite) Contains(F : TFuncionalidadComposite) : boolean

El metodo contains es el que nos dira si una funcionalidad o subgrupo est incluida en un grupo de funcionalidades. Como se podr ver mas adelante en la implementacin esta es una funcin recursiva cuyo caso base es cuando a una funcionalidad le preguntamos si se contiene a si misma. Al igual que antes no he encontrado ningn sistema que deje agrupar subconjuntos de funcionalidades de esta manera y permita esta flexibilidad. Atando Cabos Habieno adaptado el patron composite para las funcionalidades y para el conjunto de usuarios de nuestro sistema, veamos ahora como unir las dos ideas anteriores. Apuntamos a poder indicar para cada usuario/grupos de usuarios cuales son las funcionalidades/grupos de funcionalidades a las que pueden acceder. Notese que queremos tener la suficiente flexibilidad para poder realizar cualquiera de las siguientes combinaciones:

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

Permitirle a un usuario el acceso a una funcionalidad Permitile a un usuario el acceso a un grupo de funcionalidades Permitirle a un grupo de usuarios el acceso a una funcionalidad Permitirle a grupo de usuarios el acceso a un grupo de funcionalidades

Poder conservar estas cuatro combinaciones es un aporte interesante considerando que generalmente las aplicaciones requeren la creacin de un grupo auxiliar cuando se le desea dar alguna funcionalidad estra a algun usuario en particular que no est contenida en el grupo al que pertenece. Sin embargo de sta manera podemos hacerlo directamente. Nuestro planteo tambin tiene siguiente ventaja. Podemos a un usuario en particular darle acceso una funcionalidad adicional que no posee ningun grupo a los que pertenece. El dia de maana si cambiamos al usuario de grupo, el deber poder conservar ese permiso extra que se le di a pesar de perder los del grupo al que no pertenece ms. A nuestra clase TUsuarioComposite vamos a agregale una serie de mtodos que permitan dar, quitar y verificar accesos a las distintas funcionalidades del programa. Este comportamiento lo incluiremos en esa clase para tener la flexibilidad de poder aplicarlo tanto para tanto los usuarios como los grupos tal como se explico anteriormente.
TUsuarioComposite Nombre : string Pertenece Add(U : TUsuarioAbstracto) Remove(U : TUsuarioAbstracto) TieneAcceso(F : TFuncionalidadComposite) : boolean PermitirAcceso(F : TFuncionalidadComposite) DenegarAcceso(F : TFuncionalidadComposite) SubGrupos

TUsuario

TGrupoUsuarios Add(U : TUsuarioAbstracto) Remove(U : TUsuarioAbstracto)

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

Los mtodos Add y Remove en la clase TUsuarioComposite son protegidos. Deben existir aqui pues a esta clase le asignamos la responsabilidad de mantener el control de los accesos tal como se puede ver en la implementacin. No se han definido operaciones para la clase usuario. Esto se debe a que para el caso puntual que estamos tratando no vamos a necesitar. Esto implca que en la aplicacin real no se disponga de ellas. En el diagrama anterior incluimos una relacin de agregacin en la clase TUsuarioComposite con si misma. Ella nos permite la posibilidad conocer todos los grupos de usuarios a los que pertenecemos. Lo necesitamos a la hora de saber si tenemos o no acceso a una determinada funcionalidad. Como se menciono anteriormente, un usuario, ademas de las propias, puede acceder a todas las funcionalidades del grupo al que pertenece y as sucesivamente. Esto lo implementamos en el metodo TieneAcceso donde hacemos uso de esta agregacin extra que incluimos. A continuacin mostramos el diagrama de clases completo de lo que queremos lograr:

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

TUsuario

TGrupoUsuarios Add(U : TUsuarioAbstracto) Remove(U : TUsuarioAbstracto)

SubGrupos TUsuarioComposite Pertenece Nombre : string Add(U : TUsuarioAbstracto) Remove(U : TUsuarioAbstracto) TieneAccesor(F : TFuncionalidadComposite) : boolean PermitirAcceso(F : TFuncionalidadComposite) DenegarAcceso(F : TFuncionalidadComposite)

Accede

TFuncionalidadComposite NombreOpcion Contains(F : TFuncionalidadComposite) : boolean Ejecutar()

SubFuncionalidades

TFuncionalidad Ejecutar()

TGrupoFuncionalidades Add(AFuncionalidad : TFuncionalidadComposite) Remove(AFuncionalidad : TFuncionalidadComposite) Contains(F : TFuncionalidadComposite) : boolean

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

Implementacion Sin mas preludios, vemos entonces como sera la implementacion de la clase TUsuarioComposite:
unit UUsuarioComposite; interface uses UFuncionalidadComposite,ContNrs; type TUsuarioComposite = class private FPerteneceA : TObjectList; //Los grupos a los que pertenece FAccedeA : TObjectList; //Las Funcionalidades que accede protected procedure Add(U : TUsuarioComposite);virtual; procedure Remove(U : TUsuarioComposite);virtual; public constructor Create(); procedure PermitirAcceso(F : TFuncionalidadComposite); procedure DenegarAcceso(F : TFuncionalidadComposite); function TieneAcceso(F : TFuncionalidadComposite):boolean; destructor Destroy();override; end; implementation { TUsuarioComposite } constructor TUsuarioComposite.Create; begin Self.FPerteneceA := TObjectList.Create(False); Self.FAccedeA := TObjectList.Create(False); end; destructor TUsuarioComposite.Destroy; begin Self.FPerteneceA.Free; Self.FAccedeA.Free; inherited end; procedure TUsuarioComposite.PermitirAcceso(F: TFuncionalidadComposite); begin Self.FAccedeA.Add(F); end; procedure TUsuarioComposite.DenegarAcceso(F: TFuncionalidadComposite); begin Self.FAccedeA.Remove(F);

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

end; function TUsuarioComposite.TieneAcceso(F: TFuncionalidadComposite): boolean; var i : integer; begin Result := false; for i:=0 to Self.FAccedeA.Count-1 do Begin result := result or (Self.FAccedeA[i] as TFuncionalidadComposite).Contains(F); end; if not(Result) then Begin for i:=0 to Self.FPerteneceA.Count-1 do Begin result := result or (Self.FPerteneceA[i] as TUsuarioComposite).TieneAcceso(F); end; end; end; procedure TUsuarioComposite.Add(U: TUsuarioComposite); begin Self.FPerteneceA.Add(U); end; procedure TUsuarioComposite.Remove(U: TUsuarioComposite); begin Self.FPerteneceA.Remove(U); end; end.

Aqui se ven reflejadas todas las aclaraciones que hicimos anteriormente. Como se mencion lo mas interesante es la implementacion del mtodo TieneAcceso. De la misma manera mostraremos como implementamos la clase TGrupoUsuarios. Esta no representa dificultades adicionales:
unit UGrupoUsuarios; interface uses UUsuarioComposite, ContNrs; type TGrupoUsuarios = class(TUsuarioComposite) private FSubGrupos:TObjectList; public Constructor Create; procedure Add(U : TUsuarioComposite);override; procedure Remove(U : TUsuarioComposite);override;

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

Destructor Destroy; end; implementation { TGrupoUsuarios } constructor TGrupoUsuarios.Create; begin inherited; Self.FSubGrupos := TObjectList.Create(False); end; procedure TGrupoUsuarios.Add(U: TUsuarioComposite); begin inherited; Self.FSubGrupos.Add(U); end; procedure TGrupoUsuarios.Remove(U: TUsuarioComposite); begin inherited; Self.FSubGrupos.Remove(U); end; destructor TGrupoUsuarios.Destroy; begin Self.FSubGrupos.Free; inherited; end; end.

Para mayor claridad incluimos la implentacion de la clase TFuncionalidad Composite y TgrupoFuncionalidades. Lo ms importante es el mtodo contains.
unit UFuncionalidadComposite; interface type TFuncionalidadComposite = class public function Contains(F:TFuncionalidadComposite):boolean;virtual; //procecure Ejecutar; end; implementation { TFuncionalidadComposite } function TFuncionalidadComposite.Contains(F: TFuncionalidadComposite): boolean; begin result := (F=self);

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

end; end.

El fuente de grupos de funcionalidades seria


unit UGrupoFuncionalidades; interface uses UFuncionalidadComposite, ContNrs; type TGrupoFuncionalidades = class(TFuncionalidadComposite) private FSubFuncionalidades:TObjectlist; public procedure Add(F : TFuncionalidadComposite); procedure Remove(F : TFuncionalidadComposite); function Contains(F:TFuncionalidadComposite):boolean;override; Constructor Create; Destructor Destroy;override; end; implementation { TGrupoFuncionalidades } constructor TGrupoFuncionalidades.Create; begin Self.FSubFuncionalidades := TObjectList.Create(false); end; procedure TGrupoFuncionalidades.Add(F: TFuncionalidadComposite); begin Self.FSubFuncionalidades.Add(F); end; procedure TGrupoFuncionalidades.Remove(F: TFuncionalidadComposite); begin Self.FSubFuncionalidades.Remove(F); end; function TGrupoFuncionalidades.Contains(F: TFuncionalidadComposite): boolean; var i : integer; begin result := inherited Contains(F); for i:=0 to Self.FSubFuncionalidades.Count-1 do Begin result := result or (Self.FSubFuncionalidades[i] as TFuncionalidadComposite).Contains(F);

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

10

end; end; destructor TGrupoFuncionalidades.Destroy; begin Self.FSubFuncionalidades.Free; inherited; end; end.

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

11

Conclusiones En este articulo mostramos un esquema de seguridad que se caracteriza por su flexibilidad y que puede ser utilizado en cualquier aplicacin real que requiera administrar control de acceso por parte de los usuarios. Al mismo tiempo encontramos un ejemplo concreto para aplicar el patrn de diseo Composite.

Escrito por Hechicero (Esteban Cesar Calabria) Fecha Ultima Modificacion: 22 de Julio del 2004

12