diff --git a/grails-app/conf/BuildConfig.groovy b/grails-app/conf/BuildConfig.groovy index 8e4245d..329961d 100644 --- a/grails-app/conf/BuildConfig.groovy +++ b/grails-app/conf/BuildConfig.groovy @@ -37,6 +37,8 @@ grails.project.dependency.resolution = { // runtime 'mysql:mysql-connector-java:5.1.27' // runtime 'org.postgresql:postgresql:9.3-1100-jdbc41' test "org.grails:grails-datastore-test-support:1.0-grails-2.3" + compile 'joda-time:joda-time:2.7' + compile 'joda-time:joda-time-hibernate:1.4' } plugins { @@ -66,5 +68,7 @@ grails.project.dependency.resolution = { //compile ":coffee-asset-pipeline:1.5.0" //compile ":handlebars-asset-pipeline:1.3.0.1" compile ':spring-security-core:2.0-RC4' + compile ':audit-logging:1.0.4' + compile ":joda-time:1.5" } } diff --git a/grails-app/domain/com/mapaxe/security/Bitacora.groovy b/grails-app/domain/com/mapaxe/security/Bitacora.groovy new file mode 100644 index 0000000..a84fe87 --- /dev/null +++ b/grails-app/domain/com/mapaxe/security/Bitacora.groovy @@ -0,0 +1,25 @@ +package com.mapaxe.security + +import org.joda.time.DateTime +import org.joda.time.contrib.hibernate.PersistentDateTime + +class Bitacora { + String usuario + String tipoAccion + DateTime fechaAccion + String descripcion + String tabla + Long tablaId + + static constraints = { + usuario nullable: false + tipoAccion nullable: false + tabla nullable: true + tablaId nullable: true + } + + static mapping = { + descripcion sqlType: 'clob' + fechaAccion type: PersistentDateTime + } +} diff --git a/grails-app/domain/com/mapaxe/security/Role.groovy b/grails-app/domain/com/mapaxe/security/Role.groovy index edcdf45..c09971c 100644 --- a/grails-app/domain/com/mapaxe/security/Role.groovy +++ b/grails-app/domain/com/mapaxe/security/Role.groovy @@ -1,8 +1,12 @@ package com.mapaxe.security -class Role { +import security.bitacora.AuditLogging - String authority +class Role extends AuditLogging { + String authority + + static auditable = [handlersOnly:true] + static transients = ['bitacoraService'] static mapping = { cache true @@ -11,4 +15,6 @@ class Role { static constraints = { authority blank: false, unique: true } + + } diff --git a/grails-app/domain/com/mapaxe/security/User.groovy b/grails-app/domain/com/mapaxe/security/User.groovy index 8f39e3b..c1b6c89 100644 --- a/grails-app/domain/com/mapaxe/security/User.groovy +++ b/grails-app/domain/com/mapaxe/security/User.groovy @@ -1,9 +1,8 @@ package com.mapaxe.security -class User { - - transient springSecurityService +import security.bitacora.AuditLogging +class User extends AuditLogging { String username String password boolean enabled = true @@ -11,7 +10,9 @@ class User { boolean accountLocked boolean passwordExpired - static transients = ['springSecurityService'] + transient springSecurityService + static auditable = [handlersOnly:true] + static transients = ['springSecurityService', 'bitacoraService'] static constraints = { username blank: false, unique: true @@ -39,4 +40,9 @@ class User { protected void encodePassword() { password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password } -} + + @Override + public String toString() { + return username + } +} \ No newline at end of file diff --git a/grails-app/services/securitygrailexample/BitacoraService.groovy b/grails-app/services/securitygrailexample/BitacoraService.groovy new file mode 100644 index 0000000..023f78e --- /dev/null +++ b/grails-app/services/securitygrailexample/BitacoraService.groovy @@ -0,0 +1,26 @@ +package securitygrailexample + +import com.mapaxe.security.Bitacora +import com.mapaxe.security.User +import org.joda.time.DateTime + +class BitacoraService { + def springSecurityService + def guardarAccion(String tipoAccion, String descripcion, String tabla = '', Long tablaId = 0){ + String usuario + if(springSecurityService.currentUser != null){ + usuario = ((User)springSecurityService.currentUser).toString() + }else{ + usuario = 'ANONIMO' + } + DateTime fechaAccion = new DateTime(new Date().getTime()) + Bitacora bitacora = new Bitacora( + fechaAccion: fechaAccion, + usuario: usuario, + tipoAccion: tipoAccion, + descripcion: descripcion, + tabla: tabla, + tablaId: tablaId) + bitacora.save(flush:true, failOnError: true) + } +} diff --git a/src/groovy/security/bitacora/AuditLogging.groovy b/src/groovy/security/bitacora/AuditLogging.groovy new file mode 100644 index 0000000..6e9ce63 --- /dev/null +++ b/src/groovy/security/bitacora/AuditLogging.groovy @@ -0,0 +1,65 @@ +package security.bitacora + +import securitygrailexample.BitacoraService + +/** + * Created with IntelliJ IDEA. + * User: JA Verde. + * Date: 13/05/15 + * Time: 16:09 + */ +abstract class AuditLogging { + BitacoraService bitacoraService + + private BitacoraService getBitacoraservice () { + if (!bitacoraService) + bitacoraService = new BitacoraService() + + bitacoraService + } + + def onSave = {newState -> + String descripcion = '' + Long identificador = 0 + newState.each{key, value -> + descripcion = descripcion + ' * ' + key + " : " + value + '\n' + if(key.equals('id')){ + identificador = value + } + } + this.withNewSession { + getBitacoraservice().guardarAccion('Crear', descripcion, this.domainClass.getName(), identificador) + } + } + + def onDelete = {oldState -> + String descripcion = '' + Long identificador = 0 + oldState.each{key, value -> + descripcion = descripcion + ' * ' + key + " : " + value + '\n' + if(key.equals('id')){ + identificador = value + } + } + this.withNewSession { + getBitacoraservice().guardarAccion('Eliminar', descripcion, this.domainClass.getName(), identificador) + } + } + + def onChange = { oldMap,newMap -> + String descripcion = '' + Long identificador = 0 + oldMap.each({ key, value -> + if(value != newMap[key]) { + + descripcion = descripcion + ' * ' + key + ' cambio de ' + value + ' a ' + newMap[key] + '\n' + } + if(newMap['id']){ + identificador = value + } + }) + this.withNewSession { + getBitacoraservice().guardarAccion('Editar', descripcion, this.domainClass.getName(), identificador) + } + } +}