Experto en desarrollo de aplicaciones web con JavaEE y Javascript

Framework Grails

Sesión 7: Seguridad con Spring Security

Índice

  • Instalación y configuración
  • Clases de dominio
  • Asegurar peticiones
  • Controladores
  • Librerías adicionales
  • Otros aspectos interesantes

Instalación

  • spring-security-core
  • Mantenido por Spring Source
  • Ampliamente documentado: http://grails-plugins.github.io/grails-spring-security-core/guide/index.html
  • Plugins adicionales: OpenID, LDAP, Kerberos
  • Autor: Burt Beckwith (@burtbeckwith)

Instalación en Grails

BuildConfig.groovy

				
plugins {
	...
	compile ":spring-security-core:2.0-RC4"	
}
				
			

Inicialización

s2-quickstart

  • paquete
  • clase de dominio para los usuarios
  • clase de dominio para los roles
  • clase de dominio para el mapeo de peticiones

Inicialización

				
grails s2-quickstart es.ua.expertojava.todo Person Role RequestMap
				
			

Configuración del plugin

Config.groovy

				
// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'es.ua.expertojava.todo.Person'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'es.ua.expertojava.todo.PersonRole'
grails.plugin.springsecurity.authority.className = 'es.ua.expertojava.todo.Role'
grails.plugin.springsecurity.requestMap.className = 'es.ua.expertojava.todo.RequestMap'
grails.plugin.springsecurity.securityConfigType = 'Requestmap'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
	'/':                              ['permitAll'],
	'/index':                         ['permitAll'],
	'/index.gsp':                     ['permitAll'],
	'/assets/**':                     ['permitAll'],
	'/**/js/**':                      ['permitAll'],
	'/**/css/**':                     ['permitAll'],
	'/**/images/**':                  ['permitAll'],
	'/**/favicon.ico':                ['permitAll'],
	'/login/**':						['permitAll'],
	'/logout/**':						['permitAll']
]
				
			

Configuración del plugin

Config.groovy

				
grails.plugin.springsecurity.password.algorithm='SHA-512'
				
			

Clases de dominio

  • Person
  • Role
  • PersonRole
  • RequestMap

Clase de dominio Person

				
package es.ua.expertojava.todo

class Person {

	transient springSecurityService

	String username
	String password
	boolean enabled = true
	boolean accountExpired
	boolean accountLocked
	boolean passwordExpired

	static transients = ['springSecurityService']

	static constraints = {
		username blank: false, unique: true
		password blank: false
	}

	static mapping = {
		password column: '`password`'
	}

	Set getAuthorities() {
		PersonRole.findAllByPerson(this).collect { it.role }
	}

	def beforeInsert() {
		encodePassword()
	}

	def beforeUpdate() {
		if (isDirty('password')) {
			encodePassword()
		}
	}

	protected void encodePassword() {
		password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
	}
}
				
			

Clase de dominio Person

				
package es.ua.expertojava.todo
     
class User extends Person{
	String name
	String surnames
	String confirmPassword
	String email
	Date dateOfBirth
	String description

	static hasMany = [todos:Todo]
	     
	static constraints = {
		name(blank:false)
		surnames(blank:false)
		confirmPassword(blank:false, password:true)
		email(blank:false, email:true)
		dateOfBirth(nullable:true, validator: {
			if (it?.compareTo(new Date()) < 0)
				return true
			return false
		})
		description(maxSize:1000,nullable:true)
	}

	static transients = ["confirmPassword"]

	String toString(){
		"@${username}"
	}
}
				
			

Clase de dominio Person

				
package es.ua.expertojava.todo

class Todo {
	...

	User user
	
	...
}
				
			

Clase de dominio Person

				
grails generate-all es.ua.expertojava.todo.User
				
			

Clase de dominio Role

  • Roles en la aplicación
  • Usuarios sin rol: ROLE_NO_ROLES

Clase de dominio Role

				
package es.ua.expertojava.todo

class Role {

	String authority

	static mapping = {
		cache true
	}

	static constraints = {
		authority blank: false, unique: true
	}
}
				
			

Clase de dominio PersonRole

				
package es.ua.expertojava.todo

import org.apache.commons.lang.builder.HashCodeBuilder

class PersonRole implements Serializable {

	private static final long serialVersionUID = 1

	Person person
	Role role

	boolean equals(other) {
		if (!(other instanceof PersonRole)) {
			return false
		}

		other.person?.id == person?.id &&
		other.role?.id == role?.id
	}

	int hashCode() {
		def builder = new HashCodeBuilder()
		if (person) builder.append(person.id)
		if (role) builder.append(role.id)
		builder.toHashCode()
	}

	static PersonRole get(long personId, long roleId) {
		PersonRole.where {
			person == Person.load(personId) &&
			role == Role.load(roleId)
		}.get()
	}

	static boolean exists(long personId, long roleId) {
		PersonRole.where {
			person == Person.load(personId) &&
			role == Role.load(roleId)
		}.count() > 0
	}

	static PersonRole create(Person person, Role role, boolean flush = false) {
		def instance = new PersonRole(person: person, role: role)
		instance.save(flush: flush, insert: true)
		instance
	}

	static boolean remove(Person u, Role r, boolean flush = false) {
		if (u == null || r == null) return false

		int rowCount = PersonRole.where {
			person == Person.load(u.id) &&
			role == Role.load(r.id)
		}.deleteAll()

		if (flush) { PersonRole.withSession { it.flush() } }

		rowCount > 0
	}

	static void removeAll(Person u, boolean flush = false) {
		if (u == null) return

		PersonRole.where {
			person == Person.load(u.id)
		}.deleteAll()

		if (flush) { PersonRole.withSession { it.flush() } }
	}

	static void removeAll(Role r, boolean flush = false) {
		if (r == null) return

		PersonRole.where {
			role == Role.load(r.id)
		}.deleteAll()

		if (flush) { PersonRole.withSession { it.flush() } }
	}

	static constraints = {
		role validator: { Role r, PersonRole ur ->
			if (ur.person == null) return
			boolean existing = false
			PersonRole.withNewSession {
				existing = PersonRole.exists(ur.person.id, r.id)
			}
			if (existing) {
				return 'userRole.exists'
			}
		}
	}

	static mapping = {
		id composite: ['role', 'person']
		version false
	}
}
				
			

Clase de dominio PersonRole

				
Person user = ...
Role role = ...
//Asignación de rol a un usuario
PersonRole.create user, role
//Asignación de un rol a un usuario indicándole el atributo flush
PersonRole.create user, role, true

//Revocación de un rol a un usuario
Person user = ...
Role role = ...
PersonRole.remove user, role
//Revocación de un rol a un usuario indicándole el atributo flush
PersonRole.remove user, role, true
				
			

Clase de dominio RequestMap

				
package es.ua.expertojava.todo

import org.springframework.http.HttpMethod

class RequestMap {

	String url
	String configAttribute
	HttpMethod httpMethod

	static mapping = {
		cache true
	}

	static constraints = {
		url blank: false, unique: 'httpMethod'
		configAttribute blank: false
		httpMethod nullable: true
	}
}
				
			

Asegurar peticiones

  • Anotaciones
  • Archivo de configuración Config.groovy
  • Instancias de la clase RequestMap
  • Expresiones específicas

A tener en cuenta

  • Aplicaciones públicas por defecto
  • Aproximación pesimista con grails.plugin.springsecurity.rejectIfNoRule = true

Tokens predefinidos

  • IS_AUTHENTICATED_ANONYMOUSLY
  • IS_AUTHENTICATED_REMEMBERED
  • IS_AUTHENTICATED_FULLY

Anotaciones

				
grails.plugin.springsecurity.securityConfigType = "Annotation"
				
			

Anotaciones

				
package com.mycompany.myapp
import grails.plugin.springsecurity.annotation.Secured

class SecureAnnotatedController {

   @Secured(['ROLE_ADMIN'])
   def index() {
      render 'you have ROLE_ADMIN'
   }

   @Secured(['ROLE_ADMIN', 'ROLE_SUPERUSER'])
   def adminEither() {
      render 'you have ROLE_ADMIN or SUPERUSER'
   }

   def anybody() {
      render 'anyone can see this'
   }
}
				
			

Anotaciones

				
package com.mycompany.myapp
import grails.plugin.springsecurity.annotation.Secured

@Secured(['ROLE_ADMIN'])
class SecureClassAnnotatedController {

   def index() {
      render 'index: you have ROLE_ADMIN'
   }

   def otherAction() {
      render 'otherAction: you have ROLE_ADMIN'
   }

   @Secured(['ROLE_SUPERUSER'])
   def super() {
      render 'super: you have ROLE_SUPERUSER'
   }
}
				
			

Anotaciones

				
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
   '/js/admin/**': ['ROLE_ADMIN'],
   '/images/**': ['ROLE_ADMIN']
]
				
			

Archivo de configuración Config.groovy

				
grails.plugin.springsecurity.securityConfigType = "InterceptUrlMap"
				
			

Archivo de configuración Config.groovy

				
grails.plugin.springsecurity.interceptUrlMap = [
   '/':                  ['permitAll'],
   '/index':             ['permitAll'],
   '/index.gsp':         ['permitAll'],
   '/assets/**':         ['permitAll'],
   '/**/js/**':          ['permitAll'],
   '/**/css/**':         ['permitAll'],
   '/**/images/**':      ['permitAll'],
   '/**/favicon.ico':    ['permitAll'],
   '/login/**':          ['permitAll'],
   '/logout/**':         ['permitAll'],
   '/secure/**':         ['ROLE_ADMIN'],
   '/finance/**':        ['ROLE_FINANCE', 'isFullyAuthenticated()'],
]
				
			

Archivo de configuración Config.groovy

				
'/secure/**':              ['ROLE_ADMIN', 'ROLE_SUPERUSER'],
'/secure/reallysecure/**': ['ROLE_SUPERUSER']
				
			

Archivo de configuración Config.groovy

				
'/secure/reallysecure/**': ['ROLE_SUPERUSER']
'/secure/**':              ['ROLE_ADMIN', 'ROLE_SUPERUSER']
				
			

Instancias de la clase RequestMap

				
grails.plugin.springsecurity.securityConfigType = "Requestmap"
				
			

Instancias de la clase RequestMap

				
for (String url in [
      '/', '/index', '/index.gsp', '/**/favicon.ico',
      '/assets/**', '/**/js/**', '/**/css/**', '/**/images/**',
      '/login', '/login.*', '/login/*',
      '/logout', '/logout.*', '/logout/*']) {
   new Requestmap(url: url, configAttribute: 'permitAll').save()
}
new Requestmap(url: '/profile/**',    configAttribute: 'ROLE_USER').save()
new Requestmap(url: '/admin/**',      configAttribute: 'ROLE_ADMIN').save()
new Requestmap(url: '/admin/role/**', configAttribute: 'ROLE_SUPERVISOR').save()
new Requestmap(url: '/admin/user/**', configAttribute: 'ROLE_ADMIN,ROLE_SUPERVISOR').save()
new Requestmap(url: '/j_spring_security_switch_user',
               configAttribute: 'ROLE_SWITCH_USER,isFullyAuthenticated()').save()
  				
			

Instancias de la clase RequestMap

				
class RequestmapController {
   def springSecurityService

   ...

   def save() {
      def requestmapInstance = new Requestmap(params)
      if (!requestmapInstance.save(flush: true)) {
         render view: 'create', model: [requestmapInstance: requestmapInstance]
         return
      }

      springSecurityService.clearCachedRequestmaps()

      flash.message = "${message(code: 'default.created.message', args: [message(code: 'requestmap.label', default: 'Requestmap'), requestmapInstance.id])}"
      redirect action: 'show', id: requestmapInstance.id
   }
}
  				
			

Expresiones específicas

				
package com.yourcompany.yourapp
import grails.plugin.springsecurity.annotation.Secured

class SecureController {

   @Secured(["hasRole('ROLE_ADMIN')"])
   def someAction() {
      ...
   }

   @Secured(["authentication.name == 'ralph'"])
   def someOtherAction() {
      ...
   }
}
  				
			

Expresiones específicas

				
new Requestmap(url: "/secure/someAction",
               configAttribute: "hasRole('ROLE_ADMIN')").save()
new Requestmap(url: "/secure/someOtherAction",
               configAttribute: "authentication.name == 'ralph'").save()
  				
			

Expresiones específicas

				
grails.plugin.springsecurity.interceptUrlMap = [
   '/secure/someAction':      ["hasRole('ROLE_ADMIN')"],
   '/secure/someOtherAction': ["authentication.name == 'ralph'"]
]
  				
			

Expresiones específicas

  • hasRole(role)
  • hasAnyRole([role1,role2])
  • principal
  • authentication
  • permitAll
  • denyAll
  • isAnonymous()
  • isRememberMe()
  • isAuthenticated()
  • isFullyAuthenticated()
  • request

Equivalencias con SpEL

  • ROLE_ADMIN, hasRole('ROLE_ADMIN')
  • ROLE_USER, ROLE_ADMIN, hasAnyRole('ROLE_USER','ROLE_ADMIN')
  • ROLE_ADMIN, IS_AUTHENTICATED_FULLY, hasRole('ROLE_ADMIN') and isFullyAuthenticated()
  • IS_AUTHENTICATED_ANONYMOUSLY, permitAll
  • IS_AUTHENTICATED_REMEMBERED, isAnonymous() or isRememberMe()
  • IS_AUTHENTICATED_FULLY, isFullyAuthenticated()

A tener en cuenta

  • Controlador Login
  • Controlador Logout
  • Acceso a recursos de nuestra aplicación

Acceso a recursos de nuestra aplicación

  • Mediante anotaciones
  • Mediante instancias de la clase de dominio RequestMap
  • Mediante reglas en el archivo Config.groovy con InterceptUrlMap

Mediante anotaciones

				
grails.plugin.springsecurity.securityConfigType = 'Annotation'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
	'/':                              	['permitAll'],
	'/index':                         	['permitAll'],
	'/index.gsp':                     	['permitAll'],
	'/assets/**':                     	['permitAll'],
	'/**/js/**':                      	['permitAll'],
	'/**/css/**':                     	['permitAll'],
	'/**/images/**':                  	['permitAll'],
	'/**/favicon.ico':                	['permitAll'],
	'/login/**':						['permitAll'],
	'/logout/**':                		['permitAll'],
	'/dbconsole/**':               		['permitAll']
]
  				
			

Mediante instancias de la clase de dominio RequestMap

				
grails.plugin.springsecurity.securityConfigType = 'Requestmap'

/* Esto debe ir en el archivo BootStrap.groovy */
for (String url in [
      '/', '/index', '/index.gsp', '/assets/**',
      '/**/js/**', '/**/css/**', '/**/images/**',
      '/**/favicon.ico', '/login/**', '/logout/**', '/dbconsole/**']) {
   new RequestMap(url: url, configAttribute: 'permitAll').save()
}
  				
			

Mediante reglas en el archivo Config.groovy con InterceptUrlMap

				
grails.plugin.springsecurity.securityConfigType = 'InterceptUrlMap'
grails.plugin.springsecurity.interceptUrlMap = [
   '/':                  ['permitAll'],
   '/index':             ['permitAll'],
   '/index.gsp':         ['permitAll'],
   '/assets/**':         ['permitAll'],
   '/**/js/**':          ['permitAll'],
   '/**/css/**':         ['permitAll'],
   '/**/images/**':      ['permitAll'],
   '/**/favicon.ico':    ['permitAll'],
   '/login/**':          ['permitAll'],
   '/logout/**':         ['permitAll'],
   '/dbconsole/**':      ['permitAll']
]
  				
			

Controladores

  • LoginController
  • LogoutController

LoginController

				
package grails.plugin.springsecurity

import grails.converters.JSON

import javax.servlet.http.HttpServletResponse

import org.springframework.security.access.annotation.Secured
import org.springframework.security.authentication.AccountExpiredException
import org.springframework.security.authentication.CredentialsExpiredException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.web.WebAttributes

@Secured('permitAll')
class LoginController {

	/**
	 * Dependency injection for the authenticationTrustResolver.
	 */
	def authenticationTrustResolver

	/**
	 * Dependency injection for the springSecurityService.
	 */
	def springSecurityService

	/**
	 * Default action; redirects to 'defaultTargetUrl' if logged in, /login/auth otherwise.
	 */
	def index() {
		if (springSecurityService.isLoggedIn()) {
			redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl
		}
		else {
			redirect action: 'auth', params: params
		}
	}

	/**
	 * Show the login page.
	 */
	def auth() {

		def config = SpringSecurityUtils.securityConfig

		if (springSecurityService.isLoggedIn()) {
			redirect uri: config.successHandler.defaultTargetUrl
			return
		}

		String view = 'auth'
		String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}"
		render view: view, model: [postUrl: postUrl,
		                           rememberMeParameter: config.rememberMe.parameter]
	}

	/**
	 * The redirect action for Ajax requests.
	 */
	def authAjax() {
		response.setHeader 'Location', SpringSecurityUtils.securityConfig.auth.ajaxLoginFormUrl
		response.sendError HttpServletResponse.SC_UNAUTHORIZED
	}

	/**
	 * Show denied page.
	 */
	def denied() {
		if (springSecurityService.isLoggedIn() &&
				authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) {
			// have cookie but the page is guarded with IS_AUTHENTICATED_FULLY
			redirect action: 'full', params: params
		}
	}

	/**
	 * Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page.
	 */
	def full() {
		def config = SpringSecurityUtils.securityConfig
		render view: 'auth', params: params,
			model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication),
			        postUrl: "${request.contextPath}${config.apf.filterProcessesUrl}"]
	}

	/**
	 * Callback after a failed login. Redirects to the auth page with a warning message.
	 */
	def authfail() {

		String msg = ''
		def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
		if (exception) {
			if (exception instanceof AccountExpiredException) {
				msg = g.message(code: "springSecurity.errors.login.expired")
			}
			else if (exception instanceof CredentialsExpiredException) {
				msg = g.message(code: "springSecurity.errors.login.passwordExpired")
			}
			else if (exception instanceof DisabledException) {
				msg = g.message(code: "springSecurity.errors.login.disabled")
			}
			else if (exception instanceof LockedException) {
				msg = g.message(code: "springSecurity.errors.login.locked")
			}
			else {
				msg = g.message(code: "springSecurity.errors.login.fail")
			}
		}

		if (springSecurityService.isAjax(request)) {
			render([error: msg] as JSON)
		}
		else {
			flash.message = msg
			redirect action: 'auth', params: params
		}
	}

	/**
	 * The Ajax success redirect url.
	 */
	def ajaxSuccess() {
		render([success: true, username: springSecurityService.authentication.name] as JSON)
	}

	/**
	 * The Ajax denied redirect url.
	 */
	def ajaxDenied() {
		render([error: 'access denied'] as JSON)
	}
}
  				
			

LogoutController

				
package grails.plugin.springsecurity

import javax.servlet.http.HttpServletResponse

import org.springframework.security.access.annotation.Secured

@Secured('permitAll')
class LogoutController {

	/**
	 * Index action. Redirects to the Spring security logout uri.
	 */
	def index() {

		if (!request.post && SpringSecurityUtils.getSecurityConfig().logout.postOnly) {
			response.sendError HttpServletResponse.SC_METHOD_NOT_ALLOWED // 405
			return
		}

		// TODO put any pre-logout code here
		redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
	}
}
  				
			

Librerías adicionales

  • Librería de etiquetas: SecurityTagLib
  • Servicio: springSecurityService

Librería de etiquetas: SecurityTagLib

  • ifLoggedIn
  • ifNotLoggedIn
  • ifAllGranted
  • ifAnyGranted
  • ifNotGranted
  • loggedInUserInfo
  • username
  • access
  • noAccess

ifLoggedIn

				
<sec:ifLoggedIn>
	Welcome Back!
</sec:ifLoggedIn>
  				
			

ifNotLoggedIn

				
<sec:ifNotLoggedIn>
	<g:link controller='login' action='auth'>
		Login
	</g:link>
</sec:ifNotLoggedIn>
  				
			

ifAllGranted

				
<sec:ifAllGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">secure stuff here</sec:ifAllGranted>
  				
			

ifAnyGranted

				
<sec:ifAnyGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">secure stuff here</sec:ifAnyGranted>
  				
			

ifNotGranted

				
<sec:ifNotGranted roles="ROLE_USER">non-user stuff here</sec:ifNotGranted>
  				
			

loggedInUserInfo

				
<sec:loggedInUserInfo field="username"/>
  				
			

username

				
<sec:ifLoggedIn>
	Welcome Back <sec:username/>!
</sec:ifLoggedIn>
<sec:ifNotLoggedIn>
	<g:link controller='login' action='auth'>Login</g:link>
</sec:ifNotLoggedIn>
  				
			

access

				
<sec:access expression="hasRole('ROLE_USER')">
	You're a user
</sec:access>

<sec:access url="/admin/user">
	<g:link controller='admin' action='user'>Manage Users</g:link>
</sec:access>

<sec:access controller='admin' action='user'>
	<g:link controller='admin' action='user'>
		Manage Users
	</g:link>
</sec:access>
  				
			

noAccess

				
<sec:noAccess expression="hasRole('ROLE_USER')">
	You're not a user
</sec:noAccess>
  				
			

Servicio: springSecurityService

  • getCurrentUser()
  • isLoggedIn()
  • getAuthentication()
  • getPrincipal()
  • encodePassword()
  • updateRole()
  • deleteRole()
  • clearCachedRequestmaps()
  • reauthenticate()

getCurrentUser()

				
class SomeController {
   def springSecurityService

   def someAction() {
      def user = springSecurityService.currentUser
      ...
   }
}
  				
			

isLoggedIn()

				
class SomeController {
   def springSecurityService

   def someAction() {
      if (springSecurityService.isLoggedIn()) {
         ...
      }
      else {
         ...
      }
   }
}
  				
			

getAuthentication()

				
class SomeController {
   def springSecurityService

   def someAction() {
      def auth = springSecurityService.authentication
      String username = auth.username
      def authorities = auth.authorities // a Collection of GrantedAuthority
      boolean authenticated = auth.authenticated
      ...
   }
}
  				
			

getPrincipal()

				
class SomeController {
   def springSecurityService

   def someAction() {
      def principal = springSecurityService.principal
      String username = principal.username
      def authorities = principal.authorities // a Collection of GrantedAuthority
      boolean enabled = principal.enabled
      …
   }
}
  				
			

encodePassword()

				
class PersonController {
   def springSecurityService

   def updateAction() {
      def person = Person.get(params.id)

      params.salt = person.salt
      if (person.password != params.password) {
         params.password = springSecurityService.encodePassword(password, salt)
         def salt = … // e.g. randomly generated using some utility method
         params.salt = salt
      }
      person.properties = params
      if (!person.save(flush: true)) {
         render view: 'edit', model: [person: person]
         return
      }
      redirect action: 'show', id: person.id
   }
}
  				
			

updateRole()

				
class RoleController {
   def springSecurityService

   def update() {
      def roleInstance = Role.get(params.id)
      if (!springSecurityService.updateRole(roleInstance, params)) {
         render view: 'edit', model: [roleInstance: roleInstance]
         return
      }

      flash.message = "The role was updated"
      redirect action: show, id: roleInstance.id
   }
}
  				
			

deleteRole()

				
class RoleController {
   def springSecurityService

   def delete() {
      def roleInstance = Role.get(params.id)
      try {
         springSecurityService.deleteRole (roleInstance
         flash.message = "The role was deleted"
         redirect action: list
      }
      catch (DataIntegrityViolationException e) {
         flash.message = "Unable to delete the role"
         redirect action: show, id: params.id
      }
   }
}
  				
			

clearCachedRequestmaps()

				
class RequestmapController {
   def springSecurityService

   def save() {
      def requestmapInstance = new Requestmap(params)
      if (!requestmapInstance.save(flush: true)) {
         render view: 'create', model: [requestmapInstance: requestmapInstance]
         return
      }

      springSecurityService.clearCachedRequestmaps()
      flash.message = "Requestmap created"
      redirect action: show, id: requestmapInstance.id
   }
}
  				
			

reauthenticate()

				
class UserController {
   def springSecurityService

   def update() {
      def userInstance = User.get(params.id)

      params.salt = person.salt
      if (params.password) {
         params.password = springSecurityService.encodePassword(params.password, salt)
         def salt = … // e.g. randomly generated using some utility method
         params.salt = salt
      }
      userInstance.properties = params
      if (!userInstance.save(flush: true)) {
         render view: 'edit', model: [userInstance: userInstance]
         return
      }

      if (springSecurityService.loggedIn &&
             springSecurityService.principal.username == userInstance.username) {
         springSecurityService.reauthenticate userInstance.username
      }

      flash.message = "The user was updated"
      redirect action: show, id: userInstance.id
   }
}
  				
			

Otros aspectos importantes de Spring Security

  • Restricciones por IP
  • Internacionalización

Restricciones por IP

				
grails.plugin.springsecurity.ipRestrictions = [
   '/pattern1/**': '123.234.345.456',
   '/pattern2/**': '10.0.0.0/8',
   '/pattern3/**': ['10.10.200.42', '10.10.200.63']
]
  				
			

Internacionalización

  • springSecurity.errors.login.expired
  • springSecurity.errors.login.passwordExpired
  • springSecurity.errors.login.disabled
  • springSecurity.errors.login.locked
  • springSecurity.errors.login.fail
  • springSecurity.login.title
  • springSecurity.login.header
  • springSecurity.login.button
  • springSecurity.login.username.label
  • springSecurity.login.password.label
  • springSecurity.login.remember.me.label
  • springSecurity.denied.title
  • springSecurity.denied.message

¿Preguntas...?

Ejercicios