Mostraremos como con el uso de Walruz, puedes mantener la cordura en el manejo de políticas de seguridad en tu sitio Web en Rails
Esta presentación es auspiciada por ruby.org.ve
2. Definiciones
→ Autenticaci´on != Autorizaci´on
→ Autenticaci´on: Es el proceso de verificar algo o alguien
como autentico
→ Autorizaci´on: Es el proceso de verificar los privilegios de
una entidad
3. Plugins existentes en Rails
→ Autenticaci´on
devise
warden
acts as authenticated
→ Autorizaci´on
declarative authorization
walruz
4. Definamos un escenario
c l a s s User < ActiveRecord : : Base
# a t t r i b u t e : admin , : boolean
has many : friendships
has many : albums
end
c l a s s Friendship < ActiveRecord : : Base
belongs to : friend , : class name => ’ User ’
belongs to : befriend , : class name => ’ User ’
end
c l a s s Album < ActiveRecord : : Base
belongs to : owner , : class name => ’ User ’
end
5. AlbumsController
c l a s s AlbumsController < ApplicationController
b e f o r e f i l t e r : find user
def show
@album = user . albums . find ( params [ : id ] )
render : action => ’show ’
end
protected : find user
def find user
@user = User . find ( params [ : user id ] )
end
end
6. S´olo el creador del Album
1 def show
2 i f current user == user
3 @album = user . albums . find ( params [ : id ] )
4 render : action => ’show ’
5 else
6 unauthorized
7 end
8 end
7. + Admin
1 def show
2 i f current user . admin? | | current user == user
3 @album = user . albums . find ( params [ : id ] )
4 render : action => ’show ’
5 else
6 unauthorized
7 end
8 end
8. + Amigos
1 def show
2 allowed = current user . admin? | |
3 current user == user | |
4 user . friend ?( current user )
5 i f allowed
6 @album = user . albums . find ( params [ : id ] )
7 render : action => ’show ’
8 else
9 unauthorized
10 end
11 end
9. - Amigos que esten autorizados
1 def show
2 @album = user . albums . find ( params [ : id ] )
3 allowed = current user . admin? | |
4 current user == user | |
5 ( ( f = user . friendship with ( current user ) ) &&
6 f . allow to see album ?(@album ) )
7 i f allowed
8 render : action => ’show ’
9 else
10 unauthorized
11 end
12 end
10. + Verifica que el Album sea publico
1 allowed = album . i s p u b l i c ? | |
2 current user . admin? | |
3 current user == user | |
4 ( ( f = user . friendship with ( current user ) ) &&
5 f . allow to see album ?(@album ) )
11. Observaciones
→ Estamos implementando una l´ogica que puede no
pertenecer a un solo controlador (Copy-Paste)
→ Los controladores dejan de ser skinny por tener c´odigo que
se encarga de las autorizaciones
12. Posibles Soluciones
→ ¿Mover la l´ogica de validaci´on de autorizaciones al
Modelo?
→ NO. El c´odigo estar´ıa esparcido en distintos modelos,
haciendo casi imposible mantener rastro de las distintas
autorizaciones que existen en proyectos de mediano a gran
tama˜no.
13. Usando Walruz
1 def show
2 @album = user . albums . find ( params [ : id ] )
3 # a c t o r . can ?( action , s u b j e c t )
4 i f current user . can ? ( : read , @album)
5 render : action => ’show ’
6 else
7 unauthorized
8 end
9 end
14. Removemos toda la l´ogica de autorizaci´on
→ Los controladores pasan a ser Open For Extension/Closed
For Modification
→ El codigo sigue siendo legible y claro en sus intenciones
15. ¿C´omo funciona?
c l a s s User < ActiveRecord : : Base
include Walruz : : Actor
end
c l a s s Album < ActiveRecord : : Base
include Walruz : : Subject
check authorizations
# a c t i o n => p o l i c y
: read => P o l i c i e s : : AlbumReadAuthorization
end
¿Que es Policies::AlbumReadAuthorization?
16. Policies File
# l i b / walruz / p o l i c i e s . rb
module P o l i c i e s
require ” p o l i c i e s /actor is admin ”
require ” p o l i c i e s /actor is owner ”
require ” p o l i c i e s / a c t o r i s f r i e n d ”
require ” p o l i c i e s /friendship allow read albums ”
AlbumReadAuthorization =
orP ( ActorIsAdmin ,
ActorIsOwner ,
andP( ActorIsFriend . f o r s u b j e c t ( : owner ) ,
FriendshipAllowReadAlbums )
)
end
17. ActorIsAdmin
c l a s s ActorIsAdmin < Walruz : : Policy
# c u r r e n t u s e r . can ? ( : read , @album )
# a c t o r −> c u r r e n t u s e r
# s u b j e c t −> @album
def authorized ?( actor , subject )
actor . admin?
end
end
18. ActorIsOwner
c l a s s ActorIsOwner < Walruz : : Policy
# c u r r e n t u s e r . can ? ( : read , @album )
# a c t o r −> c u r r e n t u s e r
# s u b j e c t −> @album
def authorized ?( actor , subject )
actor == subject . owner
end
end
19. ActorIsFriend
# A c t o r I s F r i e n d . f o r s u b j e c t ( : owner )
c l a s s ActorIsFriend < Walruz : : Policy
# c u r r e n t u s e r . can ? ( : read , @album )
# a c t o r −> c u r r e n t u s e r
# s u b j e c t −> @album . owner
def authorized ?( user , other user )
friendship = other user . friendship with ( user )
i f friendship
[ true , : friendship => friendship ]
else
f a l s e
end
end
end
20. FriendshipAllowReadAlbum
# andP ( A c t o r I s F r i e n d . f o r s u b j e c t ( : owner ) ,
# FriendshipAllowReadAlbum )
c l a s s FriendshipAllowReadAlbum < Walruz : : Policy
def authorized ?( actor , album )
params [ : friendship ] . allow to see album ?( album )
end
end
21. Observaciones
→ Las diferentes pol´ıticas que se implementan se mantienen
bien aisladas y simples
→ Mediante la composici´on de estas pol´ıticas podemos
definir facilmente pol´ıticas con mayor complejidad
→ Todo el sistema de seguridad se mantiene en un s´olo sitio
en el proyecto
→ El problema deja de ser, invocar las autorizaciones en el
proyecto, y pasa a ser manejar el archivo de pol´ıticas
autorizaciones
22. Desventajas
→ Esto es Ruby, no SQL
→ A medida que las pol´ıticas son mas complejas, mas tiempo
se va a tomar en ejecutar la verificaciones
→ Las colecciones de objetos no son el mejor caso de uso, pero
en el caso de que sea requerido, memcache es tu amigo
→ Por ahora, walruz-rails s´olo soporta rails 2