rm93
rm93

Reputation: 33

Grails 3.3.0 with postgresql 10.1 as database and spring-security-core gives "object references an unsaved transient instance" error

I have to make a Grails 3.3.0 web interface for my internship with PostgreSQL version 10.1 as database and spring-security-core version 3.2.0.

I've installed PostgreSQL on my Linux laptop and created the webInterfaceDev database with the user Postgres.

However, every time I want to start the project I get the error "object references an unsaved transient instance".

This is the error that I get:

2017-11-23 11:26:55.634 ERROR --- [           main] o.s.boot.SpringApplication               : Application startup failed

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.domain.auth.User
        at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:279)
        at org.hibernate.type.EntityType.getIdentifier(EntityType.java:462)
        at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:153)
        at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:2051)
        at org.hibernate.loader.Loader.bindParameterValues(Loader.java:2020)
        at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1950)
        at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1903)
        at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1881)
        at org.hibernate.loader.Loader.doQuery(Loader.java:925)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
        at org.hibernate.loader.Loader.doList(Loader.java:2622)
        at org.hibernate.loader.Loader.doList(Loader.java:2605)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2434)
        at org.hibernate.loader.Loader.list(Loader.java:2429)
        at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
        at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
        at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:716)
        at org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:706)
        at org.grails.datastore.gorm.finders.FindAllByFinder.invokeQuery(FindAllByFinder.java:54)
        at org.grails.datastore.gorm.finders.FindAllByFinder$1.doInSession(FindAllByFinder.java:48)
        at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:319)
        at org.grails.datastore.gorm.finders.AbstractFinder.execute(AbstractFinder.java:42)
        at org.grails.datastore.gorm.finders.FindAllByFinder.doInvokeInternal(FindAllByFinder.java:45)
        at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:254)
        at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:392)
        at org.grails.datastore.gorm.finders.FinderMethod$invoke$0.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:141)
        at org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:185)
        at org.grails.datastore.gorm.GormEntity$Trait$Helper.staticMethodMissing(GormEntity.groovy:756)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1446)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:899)
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:168)
        at com.domain.auth.UserRole.staticMethodMissing(UserRole.groovy)
        at com.domain.auth.UserRole.$static_methodMissing(UserRole.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
        at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1499)
        at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1487)
        at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
        at com.domain.auth.User.getAuthorities(User.groovy:22)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at org.codehaus.groovy.runtime.metaclass.MethodMetaProperty$GetBeanMethodMetaProperty.getProperty(MethodMetaProperty.java:76)
        at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:85)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
        at web_interface.BootStrap$_closure1.doCall(BootStrap.groovy:9)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1087)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
        at groovy.lang.Closure.call(Closure.java:414)
        at groovy.lang.Closure.call(Closure.java:408)
        at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:535)
        at grails.util.Environment.executeForEnvironment(Environment.java:528)
        at grails.util.Environment.executeForCurrentEnvironment(Environment.java:504)
        at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:74)
        at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:65)
        at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:53)
        at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:261)
        at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:387)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
        at grails.boot.GrailsApp$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
        at web_interface.Application.main(Application.groovy:8)


FAILURE: Build failed with an exception.

Below is the code that I used:

grails-app/conf/application.yml

 ---
grails:
    profile: web
    codegen:
        defaultPackage: web_interface
    spring:
        transactionManagement:
            proxies: false
    gorm:
        reactor:
            # Whether to translate GORM events into Reactor events
            # Disabled by default for performance reasons
            events: false
info:
    app:
        name: '@info.app.name@'
        version: '@info.app.version@'
        grailsVersion: '@info.app.grailsVersion@'
spring:
    main:
        banner-mode: "off"
    groovy:
        template:
            check-template-location: false

# Spring Actuator Endpoints are Disabled by Default
endpoints:
    enabled: false
    jmx:
        enabled: true

---
grails:
    mime:
        disable:
            accept:
                header:
                    userAgents:
                        - Gecko
                        - WebKit
                        - Presto
                        - Trident
        types:
            all: '*/*'
            atom: application/atom+xml
            css: text/css
            csv: text/csv
            form: application/x-www-form-urlencoded
            html:
              - text/html
              - application/xhtml+xml
            js: text/javascript
            json:
              - application/json
              - text/json
            multipartForm: multipart/form-data
            pdf: application/pdf
            rss: application/rss+xml
            text: text/plain
            hal:
              - application/hal+json
              - application/hal+xml
            xml:
              - text/xml
              - application/xml
    urlmapping:
        cache:
            maxsize: 1000
    controllers:
        defaultScope: singleton
    converters:
        encoding: UTF-8
    views:
        default:
            codec: html
        gsp:
            encoding: UTF-8
            htmlcodec: xml
            codecs:
                expression: html
                scriptlets: html
                taglib: none
                staticparts: none
endpoints:
    jmx:
        unique-names: true

---
hibernate:
    cache:
        queries: false
        use_second_level_cache: false
        use_query_cache: false
dataSource:
    pooled: true
    jmxExport: true
    #mem database driver and password
    #driverClassName: org.h2.Driver
    #username: sa
    #password:

    #PostgreSQL driver and password
    driverClassName: org.postgresql.Driver
    username: postgres
    password: password

environments:
    development:
        dataSource:
            dbCreate: update #use create-drop or update
            #Use for mem database
            #url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE

            #Use for PostgreSQL database
            url: jdbc:postgresql://localhost:5432/webInterfaceDev
    test:
        dataSource:
            dbCreate: update
            url: jdbc:postgresql:webInterfaceDev
    production:
        dataSource:
            dbCreate: update
            url: jdbc:postgresql:webInterfaceDev
            properties:
                jmxEnabled: true
                initialSize: 5
                maxActive: 50
                minIdle: 5
                maxIdle: 25
                maxWait: 10000
                maxAge: 600000
                timeBetweenEvictionRunsMillis: 5000
                minEvictableIdleTimeMillis: 60000
                validationQuery: SELECT 1
                validationQueryTimeout: 3
                validationInterval: 15000
                testOnBorrow: true
                testWhileIdle: true
                testOnReturn: false
                jdbcInterceptors: ConnectionState
                defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED

Below is the build.gradle code:

buildscript {
    repositories {
        mavenLocal()
        maven { url "https://repo.grails.org/grails/core" }
    }
    dependencies {
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}"
        classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.2"
    }
}

version "0.1"
group "web_interface"

apply plugin:"eclipse"
apply plugin:"idea"
apply plugin:"war"
apply plugin:"org.grails.grails-web"
apply plugin:"asset-pipeline"
apply plugin:"org.grails.grails-gsp"

repositories {
    mavenLocal()
    maven { url "https://repo.grails.org/grails/core" }
}

dependencies {
    //plugins needed to make the user system
    compile 'org.grails.plugins:spring-security-core:3.2.0'
    compile 'org.grails.plugins:spring-security-ui:3.1.1'
    //end of the plugins needed
    //postgresql
    compile 'org.postgresql:postgresql:42.1.4.jre7'
    //end
    compile "org.springframework.boot:spring-boot-starter-logging"
    compile "org.springframework.boot:spring-boot-autoconfigure"
    compile "org.grails:grails-core"
    compile "org.springframework.boot:spring-boot-starter-actuator"
    compile "org.springframework.boot:spring-boot-starter-tomcat"
    compile "org.grails:grails-web-boot"
    compile "org.grails:grails-logging"
    compile "org.grails:grails-plugin-rest"
    compile "org.grails:grails-plugin-databinding"
    compile "org.grails:grails-plugin-i18n"
    compile "org.grails:grails-plugin-services"
    compile "org.grails:grails-plugin-url-mappings"
    compile "org.grails:grails-plugin-interceptors"
    compile "org.grails.plugins:cache"
    compile "org.grails.plugins:async"
    compile "org.grails.plugins:scaffolding"
    compile "org.grails.plugins:events"
    compile "org.grails.plugins:hibernate5"
    compile "org.hibernate:hibernate-core:5.1.5.Final"
    compile "org.grails.plugins:gsp"
    console "org.grails:grails-console"
    profile "org.grails.profiles:web"
    runtime "org.glassfish.web:el-impl:2.1.2-b03"
    runtime "com.h2database:h2"
    runtime "org.apache.tomcat:tomcat-jdbc"
    runtime "com.bertramlabs.plugins:asset-pipeline-grails:2.14.2"
    testCompile "org.grails:grails-gorm-testing-support"
    testCompile "org.grails.plugins:geb"
    testCompile "org.grails:grails-web-testing-support"
    testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
    testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}

bootRun {
    jvmArgs('-Dspring.output.ansi.enabled=always')
    addResources = true
}


assets {
    minifyJs = true
    minifyCss = true
}

Below is the User.groovy code:

package com.domain.auth

import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable {

    private static final long serialVersionUID = 1

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

    Set<Role> getAuthorities() {
        (UserRole.findAllByUser(this) as List<UserRole>)*.role as Set<Role>
    }

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

    static mapping = {
        table '`User`' //user is properity for postgresql insted i use now User as table name
        password column: '`password`'
    }
}

Bootstrap.groovy code:

package web_interface
import com.domain.auth.*

//class BootStrap {
//    def passwordEncoder
//
//    def init = { servletContext ->
//        def adminRole = Role.findOrSaveWhere(authority:"ROLE_ADMIN")
//        def user = User.findOrSaveWhere(username:"admin", password: "password").save(flush: true)
//        if(!user.authorities.contains(adminRole)){
//            UserRole.create(user,adminRole,true)
//        }
//    }
//    def destroy = {
//    }
//}


class BootStrap{
    def init = { servletContext ->

        if(User.count() == 0){

            def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)

            def admin = new User(username: 'admin', password: 'password').save(flush:true)

            UserRole.create admin, adminRole

            // as we call to create, flush the session explicitly ..
            UserRole.withSession {
                it.flush()
                it.clear()
            }

            // instead you can put >
            // new UserRole(admin, adminRole).save(flush:true)

            // Do more stuff with admin user

        }
    }
    def destroy = {

    }
}

UserRole.groovy code:

package com.domain.auth

import grails.gorm.DetachedCriteria
import groovy.transform.ToString

import org.codehaus.groovy.util.HashCodeHelper
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
@ToString(cache=true, includeNames=true, includePackage=false)
class UserRole implements Serializable {

    private static final long serialVersionUID = 1

    User user
    Role role

    @Override
    boolean equals(other) {
        if (other instanceof UserRole) {
            other.userId == user?.id && other.roleId == role?.id
        }
    }

    @Override
    int hashCode() {
        int hashCode = HashCodeHelper.initHash()
        if (user) {
            hashCode = HashCodeHelper.updateHash(hashCode, user.id)
        }
        if (role) {
            hashCode = HashCodeHelper.updateHash(hashCode, role.id)
        }
        hashCode
    }

    static UserRole get(long userId, long roleId) {
        criteriaFor(userId, roleId).get()
    }

    static boolean exists(long userId, long roleId) {
        criteriaFor(userId, roleId).count()
    }

    private static DetachedCriteria criteriaFor(long userId, long roleId) {
        UserRole.where {
            user == User.load(userId) &&
            role == Role.load(roleId)
        }
    }

    static UserRole create(User user, Role role, boolean flush = false) {
        def instance = new UserRole(user: user, role: role)
        instance.save(flush: flush)
        instance
    }

    static boolean remove(User u, Role r) {
        if (u != null && r != null) {
            UserRole.where { user == u && role == r }.deleteAll()
        }
    }

    static int removeAll(User u) {
        u == null ? 0 : UserRole.where { user == u }.deleteAll() as int
    }

    static int removeAll(Role r) {
        r == null ? 0 : UserRole.where { role == r }.deleteAll() as int
    }

    static constraints = {
        user nullable: false, unique: true
        role nullable: false, validator: { Role r, UserRole ur ->
            if (ur.user?.id) {
                if (UserRole.exists(ur.user.id, r.id)) {
                    return ['userRole.exists']
                }
            }
        user.save()
        }
    }

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

Role.groovy code:

package com.domain.auth

import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
@EqualsAndHashCode(includes='authority')
@ToString(includes='authority', includeNames=true, includePackage=false)
class Role implements Serializable {

    private static final long serialVersionUID = 1

    String authority

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

    static mapping = {
        cache true
    }
}

Upvotes: 0

Views: 846

Answers (2)

devbd
devbd

Reputation: 431

In your Bootstrap.groovy, try simple thing as below

def init = { servletContext ->

  if(User.count() == 0){

        def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush:true)

        def admin = new User(username: 'admin', password: 'testpassed').save(flush:true)

        UserRole.create admin, adminRole

        // as we call to create, flush the session explicitly .. 
        UserRole.withSession {
            it.flush()
            it.clear()
        }

        // instead you can put > 
        // new UserRole(admin, adminRole).save(flush:true)

        // Do more stuff with admin user

    }
}

Just a small thing, put your db url in your application.yml

url: jdbc:postgresql://localhost:5432/yourDBName

Upvotes: 0

devbd
devbd

Reputation: 431

Long story in short

Your User.findOrSaveWhere(username:"admin", password:"password") is the problem. If you try without password:"password" your code will run considering setting the password user.password='password' while initiating new User.

The saved password in the DB is hashed and it doesn't match with your given password. So, everytime you run the app, it doesn't find matching user and tries to save a new User with same username violating the unique constraints.

Deatils -

I tried with below codes -

    def xadminRole = Role.findOrSaveWhere(authority:"XYZROLE_XADMIN")
    def xuser = User.findOrSaveWhere(username:"xxzadmin", password:"password")
    if(!xuser.authorities.contains(xadminRole)){
        UserRole.create(xuser,xadminRole,true)
    }

First time its working fine and inserting the User

2nd time I ran the app i got user instance has below errors

Field error in object 'com.xxx.ovr.User' on field 'username': rejected value [xxzadmin]; codes [[username,class com.xxx.ovr.User,xxzadmin]; default message [Property [{0}] of class [{1}] with value [{2}] must be unique]

and finally

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.xxx.ovr.User

The user's password-

$2a$10$b1Ybjt9.XVgkDi.HRgGgpeyL7WsSFMFl0jpSWy60JfTfTDNRQH/Fu
$2a$10$8HTYeE8uJgmMzclc0lku5euUpNfqa3RUZeBBs7XaJ9Z5CpT/0Prtq

So you can not find a user with plain password - 'password' which is saved in DB after hashed (example given above). To match a user with username and password you can check the posts -

spring security encode password with bcrypt algorithm

Grails Spring-Security -how to compare passwords-

UPDATE

With @BurtBeckwith's useful comment, I corrected the answer putting "hashed" in place of "encrypted"

For Password Hash algorithm, please check 1.2 and 3.3.2 section of https://grails-plugins.github.io/grails-spring-security-core/latest/

Related post

Using BCrypt password hashing with Spring Security Grails plugin

For difference between Hash and Encryption please check

Difference between Hashing a Password and Encrypting it

Fundamental difference between Hashing and Encryption algorithms

Upvotes: 1

Related Questions