diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 3c394a088..a65d26f87 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -10,8 +10,8 @@ on:
- '[3-9]+.[3-9]+.x'
workflow_dispatch:
env:
- GIT_USER_NAME: puneetbehl
- GIT_USER_EMAIL: behlp@unityfoundation.io
+ GIT_USER_NAME: grails-build
+ GIT_USER_EMAIL: grails-build@users.noreply.github.com
jobs:
core-tests:
@@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v2
- uses: actions/setup-java@v4
- with: { java-version: 11, distribution: temurin }
+ with: { java-version: 17, distribution: temurin }
- name: Run Tests
uses: gradle/actions/setup-gradle@v3
env:
@@ -29,6 +29,7 @@ jobs:
with:
arguments: |
check
+ --refresh-dependencies
-Dgeb.env=chromeHeadless
functional-test:
@@ -36,11 +37,11 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- test-config: [ 'static', 'annotation', 'requestmap', 'basic', 'misc', 'putWithParams', 'bcrypt', 'issue503' ]
+ test-config: [ 'static', 'annotation', 'requestmap', 'basic', 'basicCacheUsers', 'misc', 'putWithParams', 'bcrypt', 'issue503' ]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
- with: { java-version: 11, distribution: temurin }
+ with: { java-version: 17, distribution: temurin }
- name: Run Tests
uses: gradle/actions/setup-gradle@v3
env:
@@ -58,7 +59,7 @@ jobs:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v2
- uses: actions/setup-java@v4
- with: { java-version: 11, distribution: temurin }
+ with: { java-version: 17, distribution: temurin }
- name: Run Build
id: build
uses: gradle/actions/setup-gradle@v3
@@ -67,7 +68,9 @@ jobs:
with:
arguments: |
spring-security-core:build
+ --refresh-dependencies
-Dgeb.env=chromeHeadless
+ -x javadoc
- name: Publish Snapshot artifacts to Artifactory (repo.grails.org)
uses: gradle/actions/setup-gradle@v3
@@ -80,6 +83,7 @@ jobs:
arguments: |
-Dorg.gradle.internal.publish.checksums.insecure=true
spring-security-core:publish
+ -x javadoc
- name: Generate Snapshot Documentation
if: success()
diff --git a/.sdkmanrc b/.sdkmanrc
new file mode 100644
index 000000000..215786fc3
--- /dev/null
+++ b/.sdkmanrc
@@ -0,0 +1 @@
+java=17.0.12-librca
diff --git a/README.md b/README.md
index 6f96b4b3e..1eb0bac67 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,24 @@ See [documentation](https://grails-plugins.github.io/grails-spring-security-core
### Branch structure
+- `7.0.x` compatible with Grails 7
- `6.0.x` compatible with Grails 6
- `5.0.x` compatible with Grails 5
- `4.0.x` compatible with Grails 4
- `3.3.x` compatible with Grails 3.3.x
- `3.2.x` compatible with Grails 3.2.x
+
+Grails 7 requires disabling any Spring Security Auto Configurations you may have in your classpath. This can be done via annotation or `application.yml`
+e.g.
+```yml
+spring:
+ autoconfigure:
+ exclude:
+ - org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
+ - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
+ - org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
+```
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index f8da12941..034a10fa8 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -4,12 +4,13 @@ repositories {
}
dependencies {
+ implementation platform("org.grails:grails-bom:7.0.0-SNAPSHOT")
implementation buildsrcLibs.asciidoctorj
implementation buildsrcLibs.asset.pipeline.gradle
implementation buildsrcLibs.grails.gradle.plugin, {
// Grails Gradle plugin leaks groovy-xml onto compile classpath
// which is causes a version conflict for Gradle
- exclude group: 'org.codehaus.groovy', module: 'groovy-xml'
+ exclude group: 'org.apache.groovy', module: 'groovy-xml'
}
implementation buildsrcLibs.webdriver.binaries.gradle.plugin
diff --git a/examples/functional-test-app/build.gradle b/examples/functional-test-app/build.gradle
index 9b471fcc7..8185ded74 100644
--- a/examples/functional-test-app/build.gradle
+++ b/examples/functional-test-app/build.gradle
@@ -8,6 +8,12 @@ plugins {
group = 'examples.test'
+configurations {
+ all {
+ exclude group: 'io.micronaut', module:'micronaut-inject-groovy'
+ }
+}
+
dependencies {
implementation project(':spring-security-core')
@@ -23,6 +29,7 @@ dependencies {
implementation libs.spring.security.core
implementation libs.spring.web
+ runtimeOnly libs.micronaut.jackson.databind
runtimeOnly libs.gorm.hibernate5
runtimeOnly libs.grails.asset.pipeline
runtimeOnly libs.grails.i18n
@@ -35,9 +42,8 @@ dependencies {
runtimeOnly libs.h2database
runtimeOnly libs.tomcat.jdbc
- compileOnly libs.micronaut.inject.groovy
- compileOnly libs.javax.annotation.api
- compileOnly libs.javax.servlet.api
+ compileOnly libs.jakarta.annotation.api
+ compileOnly libs.jakarta.servlet.api
compileOnly libs.slf4j.nop // Prevent warnings about missing SLF4j implementation during GSP compilation
}
diff --git a/examples/functional-test-app/grails-app/conf/application.groovy b/examples/functional-test-app/grails-app/conf/application.groovy
index 10fef5123..15f928f2a 100644
--- a/examples/functional-test-app/grails-app/conf/application.groovy
+++ b/examples/functional-test-app/grails-app/conf/application.groovy
@@ -49,6 +49,18 @@ switch (testconfig) {
]
break
+ case 'basicCacheUsers':
+ grails.plugin.springsecurity.securityConfigType = 'Annotation'
+ grails.plugin.springsecurity.useBasicAuth = true
+ grails.plugin.springsecurity.basic.realmName = 'Grails Spring Security Basic Test Realm'
+ grails.plugin.springsecurity.filterChain.chainMap = [
+ [pattern: '/secureclassannotated/**', filters: 'JOINED_FILTERS,-exceptionTranslationFilter'],
+ [pattern: '/**', filters: 'JOINED_FILTERS,-basicAuthenticationFilter,-basicExceptionTranslationFilter']
+ ]
+ grails.plugin.springsecurity.cacheUsers = true
+ grails.plugin.springsecurity.providerManager.eraseCredentialsAfterAuthentication = false
+ break
+
case 'bcrypt':
grails.plugin.springsecurity.securityConfigType = 'Annotation'
grails.plugin.springsecurity.password.algorithm = 'bcrypt'
diff --git a/examples/functional-test-app/grails-app/views/error.gsp b/examples/functional-test-app/grails-app/views/error.gsp
index 419d66668..06820cf89 100644
--- a/examples/functional-test-app/grails-app/views/error.gsp
+++ b/examples/functional-test-app/grails-app/views/error.gsp
@@ -6,8 +6,8 @@
-
-
+
+
diff --git a/examples/functional-test-app/src/integration-test/groovy/specs/BasicAuthCacheUsersSecuritySpec.groovy b/examples/functional-test-app/src/integration-test/groovy/specs/BasicAuthCacheUsersSecuritySpec.groovy
new file mode 100644
index 000000000..2be33d916
--- /dev/null
+++ b/examples/functional-test-app/src/integration-test/groovy/specs/BasicAuthCacheUsersSecuritySpec.groovy
@@ -0,0 +1,151 @@
+package specs
+
+import org.springframework.security.core.userdetails.UserCache
+import pages.LoginPage
+import pages.role.CreateRolePage
+import pages.role.ListRolePage
+import pages.role.ShowRolePage
+import pages.user.CreateUserPage
+import pages.user.ListUserPage
+import pages.user.ShowUserPage
+import spock.lang.IgnoreIf
+
+@IgnoreIf({ System.getProperty('TESTCONFIG') != 'basicCacheUsers' })
+class BasicAuthCacheUsersSecuritySpec extends AbstractSecuritySpec {
+
+ private HttpURLConnection connection
+ UserCache userCache
+
+ void 'create roles'() {
+ when:
+ to ListRolePage
+
+ then:
+ roleRows.size() == 0
+
+ when:
+ newRoleButton.click()
+
+ then:
+ at CreateRolePage
+
+ when:
+ authority = 'ROLE_ADMIN'
+ createButton.click()
+
+ then:
+ at ShowRolePage
+
+ when:
+ to ListRolePage
+
+ then:
+ roleRows.size() == 1
+
+ when:
+ newRoleButton.click()
+
+ then:
+ at CreateRolePage
+
+ when:
+ authority = 'ROLE_ADMIN2'
+ createButton.click()
+
+ then:
+ at ShowRolePage
+
+ when:
+ to ListRolePage
+
+ then:
+ roleRows.size() == 2
+ }
+
+ void 'create users'() {
+ when:
+ to ListUserPage
+
+ then:
+ userRows.size() == 0
+
+ when:
+ newUserButton.click()
+
+ then:
+ at CreateUserPage
+
+ when:
+ username = 'admin1'
+ password = 'password1'
+ $('#enabled').click()
+ $('#ROLE_ADMIN').click()
+ createButton.click()
+
+ then:
+ at ShowUserPage
+
+ when:
+ to ListUserPage
+
+ then:
+ userRows.size() == 1
+
+ when:
+ newUserButton.click()
+
+ then:
+ at CreateUserPage
+
+ when:
+ username = 'admin2'
+ password = 'password2'
+ $('#enabled').click()
+ $('#ROLE_ADMIN').click()
+ $('#ROLE_ADMIN2').click()
+ createButton.click()
+
+ then:
+ at ShowUserPage
+
+ when:
+ to ListUserPage
+
+ then:
+ userRows.size() == 2
+ }
+
+ @IgnoreIf({ !System.getProperty('geb.env') })
+ void 'check userDetails caching'() {
+
+ when:
+ go 'secureAnnotated'
+
+ then:
+ at LoginPage
+
+ when:
+ login 'admin1', 'password1'
+
+ then:
+ assertContentContains 'you have ROLE_ADMIN'
+
+ and:
+ userCache.getUserFromCache('admin1')
+
+ cleanup:
+ logout()
+ }
+
+ protected void logout() {
+ super.logout()
+ // cheesy, but the 'Authentication' header from basic auth
+ // isn't cleared, so this forces an invalid header
+ getWithAuth '', 'not_a_valid_username', ''
+ }
+
+ private void getWithAuth(String path, String username, String password) {
+ String uri = new URI(baseUrlRequired).resolve(new URI(path))
+ go uri.replace('http://', 'http://' + username + ':' + password + '@')
+ }
+}
diff --git a/examples/functional-test-app/src/integration-test/groovy/specs/RoleSpec.groovy b/examples/functional-test-app/src/integration-test/groovy/specs/RoleSpec.groovy
index 1a23ab9a4..950c13855 100644
--- a/examples/functional-test-app/src/integration-test/groovy/specs/RoleSpec.groovy
+++ b/examples/functional-test-app/src/integration-test/groovy/specs/RoleSpec.groovy
@@ -9,6 +9,7 @@ import spock.lang.IgnoreIf
@IgnoreIf({ !(
System.getProperty('TESTCONFIG') == 'annotation' ||
System.getProperty('TESTCONFIG') == 'basic' ||
+ System.getProperty('TESTCONFIG') == 'basicCacheUsers' ||
System.getProperty('TESTCONFIG') == 'requestmap' ||
System.getProperty('TESTCONFIG') == 'static')
})
diff --git a/examples/functional-test-app/src/integration-test/groovy/specs/UserSpec.groovy b/examples/functional-test-app/src/integration-test/groovy/specs/UserSpec.groovy
index b8415c099..77729618f 100644
--- a/examples/functional-test-app/src/integration-test/groovy/specs/UserSpec.groovy
+++ b/examples/functional-test-app/src/integration-test/groovy/specs/UserSpec.groovy
@@ -9,6 +9,7 @@ import spock.lang.IgnoreIf
@IgnoreIf({ !(
System.getProperty('TESTCONFIG') == 'annotation' ||
System.getProperty('TESTCONFIG') == 'basic' ||
+ System.getProperty('TESTCONFIG') == 'basicCacheUsers' ||
System.getProperty('TESTCONFIG') == 'requestmap' ||
System.getProperty('TESTCONFIG') == 'static')
})
diff --git a/examples/functional-test-app/src/main/groovy/com/testapp/MaintenanceModeFilter.groovy b/examples/functional-test-app/src/main/groovy/com/testapp/MaintenanceModeFilter.groovy
index 570d910b3..1eb8a71ab 100644
--- a/examples/functional-test-app/src/main/groovy/com/testapp/MaintenanceModeFilter.groovy
+++ b/examples/functional-test-app/src/main/groovy/com/testapp/MaintenanceModeFilter.groovy
@@ -3,12 +3,12 @@ package com.testapp
import groovy.util.logging.Slf4j
import org.springframework.web.filter.GenericFilterBean
-import javax.servlet.FilterChain
-import javax.servlet.ServletException
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
/**
* If registered, this filter results in an HttpStatus of 500 being returned to the client
diff --git a/examples/functional-test-app/src/main/groovy/com/testapp/TestUserPasswordEncoderListener.groovy b/examples/functional-test-app/src/main/groovy/com/testapp/TestUserPasswordEncoderListener.groovy
index f7551f43c..2e8fbd9f5 100644
--- a/examples/functional-test-app/src/main/groovy/com/testapp/TestUserPasswordEncoderListener.groovy
+++ b/examples/functional-test-app/src/main/groovy/com/testapp/TestUserPasswordEncoderListener.groovy
@@ -7,7 +7,7 @@ import org.grails.datastore.mapping.engine.event.PreUpdateEvent
import org.springframework.beans.factory.annotation.Autowired
import grails.events.annotation.gorm.Listener
import groovy.transform.CompileStatic
-import javax.annotation.PostConstruct
+import jakarta.annotation.PostConstruct
@CompileStatic
class TestUserPasswordEncoderListener {
diff --git a/examples/integration-test-app/build.gradle b/examples/integration-test-app/build.gradle
index 1432dfa39..4c7dac804 100644
--- a/examples/integration-test-app/build.gradle
+++ b/examples/integration-test-app/build.gradle
@@ -33,7 +33,7 @@ dependencies {
runtimeOnly libs.tomcat.jdbc
compileOnly libs.micronaut.inject.groovy
- compileOnly libs.javax.servlet.api
+ compileOnly libs.jakarta.servlet.api
compileOnly libs.slf4j.nop
testImplementation libs.spock.core
diff --git a/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SecurityTagLibSpec.groovy b/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SecurityTagLibSpec.groovy
index 893bf58cf..477da685b 100644
--- a/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SecurityTagLibSpec.groovy
+++ b/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SecurityTagLibSpec.groovy
@@ -34,8 +34,8 @@ import org.springframework.web.context.request.RequestContextHolder
import spock.lang.Ignore
import spock.lang.Shared
-import javax.servlet.FilterChain
-import javax.servlet.ServletContext
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletContext
import java.security.Principal
/**
diff --git a/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SpringSecurityUtilsIntegrationSpec.groovy b/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SpringSecurityUtilsIntegrationSpec.groovy
index 81fa0d968..718821070 100644
--- a/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SpringSecurityUtilsIntegrationSpec.groovy
+++ b/examples/integration-test-app/src/integration-test/groovy/grails/plugin/springsecurity/SpringSecurityUtilsIntegrationSpec.groovy
@@ -36,9 +36,9 @@ import test.TestRole
import test.TestUser
import test.TestUserRole
-import javax.servlet.FilterChain
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
/**
* Integration tests for SpringSecurityUtils
.
@@ -87,15 +87,15 @@ class SpringSecurityUtilsIntegrationSpec extends AbstractIntegrationSpec {
expect:
10 == map.size()
map[Integer.MIN_VALUE + 10] instanceof SecurityRequestHolderFilter
- map[300] instanceof SecurityContextPersistenceFilter
- map[400] instanceof MutableLogoutFilter
- map[800] instanceof GrailsUsernamePasswordAuthenticationFilter
- map[1400] instanceof SecurityContextHolderAwareRequestFilter
- map[1500] instanceof GrailsRememberMeAuthenticationFilter
- map[1600] instanceof GrailsAnonymousAuthenticationFilter
- map[1800] instanceof FormContentFilter
- map[1900] instanceof ExceptionTranslationFilter
- map[2000] instanceof FilterSecurityInterceptor
+ map[SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order] instanceof SecurityContextPersistenceFilter
+ map[SecurityFilterPosition.LOGOUT_FILTER.order] instanceof MutableLogoutFilter
+ map[SecurityFilterPosition.FORM_LOGIN_FILTER.order] instanceof GrailsUsernamePasswordAuthenticationFilter
+ map[SecurityFilterPosition.SERVLET_API_SUPPORT_FILTER.order] instanceof SecurityContextHolderAwareRequestFilter
+ map[SecurityFilterPosition.REMEMBER_ME_FILTER.order] instanceof GrailsRememberMeAuthenticationFilter
+ map[SecurityFilterPosition.ANONYMOUS_FILTER.order] instanceof GrailsAnonymousAuthenticationFilter
+ map[SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order-10] instanceof FormContentFilter
+ map[SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order] instanceof ExceptionTranslationFilter
+ map[SecurityFilterPosition.FILTER_SECURITY_INTERCEPTOR.order] instanceof FilterSecurityInterceptor
when:
SpringSecurityUtils.clientRegisterFilter 'foo', SecurityFilterPosition.LOGOUT_FILTER
@@ -123,7 +123,7 @@ class SpringSecurityUtilsIntegrationSpec extends AbstractIntegrationSpec {
then:
11 == map.size()
- map[410] instanceof DummyFilter
+ map[SecurityFilterPosition.LOGOUT_FILTER.order + 10] instanceof DummyFilter
when:
def filters = securityFilterChains[0].filters
diff --git a/examples/integration-test-app/src/main/groovy/com/test/AdditionalLogoutHandler.groovy b/examples/integration-test-app/src/main/groovy/com/test/AdditionalLogoutHandler.groovy
index 59da3b1bd..9a9c5ffea 100644
--- a/examples/integration-test-app/src/main/groovy/com/test/AdditionalLogoutHandler.groovy
+++ b/examples/integration-test-app/src/main/groovy/com/test/AdditionalLogoutHandler.groovy
@@ -1,7 +1,7 @@
package com.test
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.logout.LogoutHandler
diff --git a/gradle/buildsrc.libs.versions.toml b/gradle/buildsrc.libs.versions.toml
index 3177c3c6e..71c3ce95e 100644
--- a/gradle/buildsrc.libs.versions.toml
+++ b/gradle/buildsrc.libs.versions.toml
@@ -1,7 +1,7 @@
[versions]
-asciidoctorj = '4.0.2'
-asset-pipeline-gradle = '4.4.0'
-grails-gradle-plugin = '6.1.2'
+asciidoctorj = '4.0.3'
+asset-pipeline-gradle = '5.0.1'
+grails-gradle-plugin = '7.0.0-SNAPSHOT'
webdriver-binaries = '3.2'
spock = '2.3-groovy-3.0'
diff --git a/gradle/groovy-config.gradle b/gradle/groovy-config.gradle
index e40f8102f..362a10c4b 100644
--- a/gradle/groovy-config.gradle
+++ b/gradle/groovy-config.gradle
@@ -1,8 +1,9 @@
configurations.configureEach {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
- if (details.requested.group == 'org.codehaus.groovy') {
+ if ((details.requested.group == 'org.codehaus.groovy' || details.requested.group == 'org.apache.groovy') && details.requested.name != 'groovy-bom') {
String groovyVersion = findProperty('groovyVersion') ?: libs.versions.groovy.get()
- details.useVersion(groovyVersion)
+ details.useTarget(group: 'org.apache.groovy', name: details.requested.name, version: groovyVersion)
+ details.because "The dependency coordinates are changed in Apache Groovy 4, plus ensure version"
}
}
}
diff --git a/gradle/java-config.gradle b/gradle/java-config.gradle
index 0bad9f3ac..3132d5647 100644
--- a/gradle/java-config.gradle
+++ b/gradle/java-config.gradle
@@ -1,5 +1,5 @@
java {
- sourceCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
withJavadocJar()
withSourcesJar()
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 0dbdae2e1..079807dfc 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,32 +1,32 @@
[versions]
-asset-pipeline = '4.3.0'
-commons-lang = '2.6'
-ehcache = '2.10.9.2'
-geb = '6.0'
-gorm-hibernate5 = '8.0.3'
-grails = '6.1.2'
-grails-async-and-events = '5.0.2'
-grails-datamapping = '8.0.3'
-grails-gsp = '6.2.0'
-grails-converters = '4.0.1'
-grails-testing-support = '3.1.2'
-groovy = '3.0.21'
-h2database = '2.2.224'
-javax-annotation-api = '1.3.2'
-javax-servlet-api = '4.0.1'
-micronaut = '3.10.4'
-selenium = '4.18.1'
-selenium-safari = '4.18.1'
-slf4j = '1.7.36'
-spock = '2.0-groovy-3.0'
-spring = '5.3.33'
-springboot = '2.7.18'
-spring-security = '5.8.11'
-tomcat = '9.0.87'
+asset-pipeline = '5.0.1'
+commons-text = '1.12.0'
+ehcache = '3.10.8'
+geb = '7.0'
+gorm-hibernate5 = '9.0.0-SNAPSHOT'
+grails = '7.0.0-SNAPSHOT'
+grails-async-and-events = '7.0.0-SNAPSHOT'
+grails-datamapping = '9.0.0-SNAPSHOT'
+grails-gsp = '7.0.0-SNAPSHOT'
+grails-converters = '6.0.0-SNAPSHOT'
+grails-testing-support = '4.0.0-SNAPSHOT'
+groovy = '4.0.22'
+h2database = '2.3.232'
+jakarta-annotation-api = '3.0.0'
+jakarta-servlet-api = '6.0.0'
+micronaut = '4.5.3'
+selenium = '4.19.1'
+selenium-safari = '4.19.1'
+slf4j = '2.0.16'
+spock = '2.3-groovy-4.0'
+spring = '6.1.12'
+springboot = '3.3.3'
+spring-security = '6.3.3'
+tomcat = '10.1.29'
[libraries]
-commons-lang = { module = 'commons-lang:commons-lang', version.ref = 'commons-lang' }
-ehcache = { module = 'net.sf.ehcache:ehcache', version.ref = 'ehcache' }
+commons-text = { module = 'org.apache.commons:commons-text', version.ref = 'commons-text' }
+ehcache = { module = 'org.ehcache:ehcache', version.ref = 'ehcache' }
geb-core = { module = 'org.gebish:geb-core', version.ref = 'geb' }
geb-spock = { module = 'org.gebish:geb-spock', version.ref = 'geb' }
gorm-hibernate5 = { module = 'org.grails.plugins:hibernate5', version.ref = 'gorm-hibernate5' }
@@ -39,7 +39,6 @@ grails-datastore-gorm = { module = 'org.grails:grails-datastore-gorm', version.r
grails-domain = { module = 'org.grails:grails-plugin-domain-class', version.ref = 'grails' }
grails-events-transform = { module = 'org.grails:grails-events-transform', version.ref = 'grails-async-and-events' }
grails-gsp = { module = 'org.grails.plugins:gsp', version.ref = 'grails-gsp' }
-grails-gorm-testing-support = { module = 'org.grails:grails-gorm-testing-support', version.ref = 'grails-testing-support' }
grails-i18n = { module = 'org.grails:grails-plugin-i18n', version.ref = 'grails' }
grails-interceptors = { module = 'org.grails:grails-plugin-interceptors', version.ref = 'grails' }
grails-mimetypes = { module = 'org.grails:grails-plugin-mimetypes', version.ref = 'grails' }
@@ -51,14 +50,14 @@ grails-testing-support-web = { module = 'org.grails:grails-web-testing-support',
grails-urlmappings = { module = 'org.grails:grails-plugin-url-mappings', version.ref = 'grails' }
grails-validation = { module = 'org.grails:grails-plugin-validation', version.ref = 'grails' }
grails-web-common = { module = 'org.grails:grails-web-common', version.ref = 'grails' }
-grails-web-testing-support = { module = 'org.grails:grails-web-testing-support', version.ref = 'grails-testing-support' }
grails-web-urlmappings = { module = 'org.grails:grails-web-url-mappings', version.ref = 'grails' }
-groovy-core = { module = 'org.codehaus.groovy:groovy', version.ref = 'groovy' }
-javax-annotation-api = { module = 'javax.annotation:javax.annotation-api', version.ref = 'javax-annotation-api' }
-javax-servlet-api = { module = 'javax.servlet:javax.servlet-api', version.ref = 'javax-servlet-api' }
+groovy-core = { module = 'org.apache.groovy:groovy', version.ref = 'groovy' }
+jakarta-annotation-api = { module = 'jakarta.annotation:jakarta.annotation-api', version.ref = 'jakarta-annotation-api' }
+jakarta-servlet-api = { module = 'jakarta.servlet:jakarta.servlet-api', version.ref = 'jakarta-servlet-api' }
h2database = { module = 'com.h2database:h2', version.ref = 'h2database' }
micronaut-httpclient = { module = 'io.micronaut:micronaut-http-client', version.ref = 'micronaut' }
micronaut-inject-groovy = { module = 'io.micronaut:micronaut-inject-groovy', version.ref = 'micronaut' }
+micronaut-jackson-databind = { module = 'io.micronaut:micronaut-jackson-databind', version.ref = 'micronaut' }
selenium-api = { module = 'org.seleniumhq.selenium:selenium-api', version.ref = 'selenium' }
selenium-chrome-driver = { module = 'org.seleniumhq.selenium:selenium-chrome-driver', version.ref = 'selenium' }
selenium-chromium-driver = { module = 'org.seleniumhq.selenium:selenium-chromium-driver', version.ref = 'selenium' }
@@ -77,6 +76,7 @@ spring-context-core = { module = 'org.springframework:spring-context', version.r
spring-context-support = { module = 'org.springframework:spring-context-support', version.ref = 'spring' }
spring-expression = { module = 'org.springframework:spring-expression', version.ref = 'spring' }
spring-security-core = { module = 'org.springframework.security:spring-security-core', version.ref = 'spring-security' }
+spring-security-config = { module = 'org.springframework.security:spring-security-config', version.ref = 'spring-security' }
spring-security-crypto = { module = 'org.springframework.security:spring-security-crypto', version.ref = 'spring-security' }
spring-security-web = { module = 'org.springframework.security:spring-security-web', version.ref = 'spring-security' }
spring-test = { module = 'org.springframework:spring-test', version.ref = 'spring' }
@@ -85,10 +85,11 @@ spring-web = { module = 'org.springframework:spring-web', version.ref = 'spring'
springboot-autoconfigure = { module = 'org.springframework.boot:spring-boot-autoconfigure', version.ref = 'springboot' }
springboot-core = { module = 'org.springframework.boot:spring-boot', version.ref = 'springboot' }
springboot-starter-logging = { module = 'org.springframework.boot:spring-boot-starter-logging', version.ref = 'springboot' }
+springboot-starter-test = { module = 'org.springframework.boot:spring-boot-starter-test', version.ref = 'springboot' }
springboot-starter-tomcat = { module = 'org.springframework.boot:spring-boot-starter-tomcat', version.ref = 'springboot' }
tomcat-jdbc = { module = 'org.apache.tomcat:tomcat-jdbc', version.ref = 'tomcat' }
[bundles]
geb = ['geb-core', 'geb-spock']
-grails-testing-support = ['grails-testing-support-gorm', 'grails-testing-support-web']
+grails-testing-support = ['grails-testing-support-gorm', 'grails-testing-support-web', 'springboot-starter-test']
selenium = ['selenium-api', 'selenium-chrome-driver', 'selenium-chromium-driver', 'selenium-devtools-v85', 'selenium-firefox-driver', 'selenium-http', 'selenium-json', 'selenium-remote-driver', 'selenium-safari-driver', 'selenium-support']
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c7d437bbb..c44c2304c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/plugin/build.gradle b/plugin/build.gradle
index f03a62481..5b5ca01f0 100644
--- a/plugin/build.gradle
+++ b/plugin/build.gradle
@@ -26,7 +26,7 @@ dependencies {
api libs.spring.security.web
api libs.spring.web
- implementation libs.commons.lang
+ implementation libs.commons.text
implementation libs.ehcache
implementation libs.grails.bootstrap
implementation libs.grails.converters
@@ -36,14 +36,16 @@ dependencies {
implementation libs.spring.core
implementation libs.spring.security.crypto
implementation libs.spring.tx
+ compileOnly "jline:jline" // for shell commands
compileOnly libs.groovy.core // Compile-time annotations
- compileOnly libs.javax.servlet.api // Provided
+ compileOnly libs.jakarta.servlet.api // Provided
compileOnly libs.slf4j.nop // Prevents warnings about missing slf4j implementation during compilation
testImplementation libs.bundles.grails.testing.support
testImplementation libs.spock.core
testImplementation libs.spring.test
+ testImplementation libs.spring.security.config
testRuntimeOnly libs.slf4j.nop // Prevents warnings about missing slf4j implementation during tests
}
diff --git a/plugin/grails-app/controllers/grails/plugin/springsecurity/LoginController.groovy b/plugin/grails-app/controllers/grails/plugin/springsecurity/LoginController.groovy
index 1be4bdc64..b58b0b9d3 100644
--- a/plugin/grails-app/controllers/grails/plugin/springsecurity/LoginController.groovy
+++ b/plugin/grails-app/controllers/grails/plugin/springsecurity/LoginController.groovy
@@ -15,6 +15,7 @@
package grails.plugin.springsecurity
import grails.converters.JSON
+import org.grails.web.servlet.mvc.GrailsWebRequest
import org.springframework.context.MessageSource
import org.springframework.security.access.annotation.Secured
import org.springframework.security.authentication.AccountExpiredException
@@ -27,7 +28,7 @@ import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.WebAttributes
import org.springframework.security.web.authentication.session.SessionAuthenticationException
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletResponse
@Secured('permitAll')
class LoginController {
@@ -104,18 +105,19 @@ class LoginController {
String msg = ''
def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
if (exception) {
+ def locale = GrailsWebRequest.lookup().getLocale() ?: Locale.getDefault()
if (exception instanceof AccountExpiredException) {
- msg = messageSource.getMessage('springSecurity.errors.login.expired', null, "Account Expired", request.locale)
+ msg = messageSource.getMessage('springSecurity.errors.login.expired', null, "Account Expired", locale)
} else if (exception instanceof CredentialsExpiredException) {
- msg = messageSource.getMessage('springSecurity.errors.login.passwordExpired', null, "Password Expired", request.locale)
+ msg = messageSource.getMessage('springSecurity.errors.login.passwordExpired', null, "Password Expired", locale)
} else if (exception instanceof DisabledException) {
- msg = messageSource.getMessage('springSecurity.errors.login.disabled', null, "Account Disabled", request.locale)
+ msg = messageSource.getMessage('springSecurity.errors.login.disabled', null, "Account Disabled", locale)
} else if (exception instanceof LockedException) {
- msg = messageSource.getMessage('springSecurity.errors.login.locked', null, "Account Locked", request.locale)
+ msg = messageSource.getMessage('springSecurity.errors.login.locked', null, "Account Locked", locale)
} else if (exception instanceof SessionAuthenticationException) {
- msg = messageSource.getMessage('springSecurity.errors.login.max.sessions.exceeded', null, "Sorry, you have exceeded your maximum number of open sessions.", request.locale)
+ msg = messageSource.getMessage('springSecurity.errors.login.max.sessions.exceeded', null, "Sorry, you have exceeded your maximum number of open sessions.", locale)
} else {
- msg = messageSource.getMessage('springSecurity.errors.login.fail', null, "Authentication Failure", request.locale)
+ msg = messageSource.getMessage('springSecurity.errors.login.fail', null, "Authentication Failure", locale)
}
}
diff --git a/plugin/grails-app/controllers/grails/plugin/springsecurity/LogoutController.groovy b/plugin/grails-app/controllers/grails/plugin/springsecurity/LogoutController.groovy
index 7540a20cc..864062bbe 100644
--- a/plugin/grails-app/controllers/grails/plugin/springsecurity/LogoutController.groovy
+++ b/plugin/grails-app/controllers/grails/plugin/springsecurity/LogoutController.groovy
@@ -17,7 +17,7 @@ package grails.plugin.springsecurity
import org.springframework.security.access.annotation.Secured
import org.springframework.security.web.RedirectStrategy
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletResponse
@Secured('permitAll')
class LogoutController {
diff --git a/plugin/grails-app/services/grails/plugin/springsecurity/SpringSecurityService.groovy b/plugin/grails-app/services/grails/plugin/springsecurity/SpringSecurityService.groovy
index c66111007..1f2f8bc00 100644
--- a/plugin/grails-app/services/grails/plugin/springsecurity/SpringSecurityService.groovy
+++ b/plugin/grails-app/services/grails/plugin/springsecurity/SpringSecurityService.groovy
@@ -22,7 +22,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolver
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder as SCH
-import javax.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletRequest
/**
* Utility methods.
diff --git a/plugin/grails-app/taglib/grails/plugin/springsecurity/SecurityTagLib.groovy b/plugin/grails-app/taglib/grails/plugin/springsecurity/SecurityTagLib.groovy
index 923635c12..f0042a43b 100644
--- a/plugin/grails-app/taglib/grails/plugin/springsecurity/SecurityTagLib.groovy
+++ b/plugin/grails-app/taglib/grails/plugin/springsecurity/SecurityTagLib.groovy
@@ -25,7 +25,7 @@ import org.springframework.security.core.Authentication
import org.springframework.security.web.FilterInvocation
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator
-import javax.servlet.FilterChain
+import jakarta.servlet.FilterChain
/**
* Security tags.
diff --git a/plugin/src/docs/code/s2-quickstart-old/grails-app/views/error.gsp b/plugin/src/docs/code/s2-quickstart-old/grails-app/views/error.gsp
index 9a3bb8aa3..a2c4235ab 100644
--- a/plugin/src/docs/code/s2-quickstart-old/grails-app/views/error.gsp
+++ b/plugin/src/docs/code/s2-quickstart-old/grails-app/views/error.gsp
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/plugin/src/docs/code/s2-quickstart-requestmap/grails-app/views/error.gsp b/plugin/src/docs/code/s2-quickstart-requestmap/grails-app/views/error.gsp
index 9a3bb8aa3..a2c4235ab 100644
--- a/plugin/src/docs/code/s2-quickstart-requestmap/grails-app/views/error.gsp
+++ b/plugin/src/docs/code/s2-quickstart-requestmap/grails-app/views/error.gsp
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/plugin/src/docs/code/s2-quickstart-rolegroup/grails-app/views/error.gsp b/plugin/src/docs/code/s2-quickstart-rolegroup/grails-app/views/error.gsp
index 9a3bb8aa3..a2c4235ab 100644
--- a/plugin/src/docs/code/s2-quickstart-rolegroup/grails-app/views/error.gsp
+++ b/plugin/src/docs/code/s2-quickstart-rolegroup/grails-app/views/error.gsp
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/plugin/src/docs/code/s2-quickstart/grails-app/views/error.gsp b/plugin/src/docs/code/s2-quickstart/grails-app/views/error.gsp
index 9a3bb8aa3..a2c4235ab 100644
--- a/plugin/src/docs/code/s2-quickstart/grails-app/views/error.gsp
+++ b/plugin/src/docs/code/s2-quickstart/grails-app/views/error.gsp
@@ -10,8 +10,8 @@
-
-
+
+
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/SecurityFilterPosition.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/SecurityFilterPosition.java
similarity index 55%
rename from plugin/src/main/groovy/grails/plugin/springsecurity/SecurityFilterPosition.groovy
rename to plugin/src/main/groovy/grails/plugin/springsecurity/SecurityFilterPosition.java
index 543770d25..9676edd65 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/SecurityFilterPosition.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/SecurityFilterPosition.java
@@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package grails.plugin.springsecurity
+package grails.plugin.springsecurity;
/**
* Stores the default order numbers of all Spring Security filters for use in configuration.
@@ -22,64 +22,100 @@
*
* @author Burt Beckwith
*/
-enum SecurityFilterPosition {
- /** First */
+enum SecurityFilterPosition {
+
FIRST(Integer.MIN_VALUE),
- /** HTTP/HTTPS channel filter */
+
+ DISABLE_ENCODE_URL_FILTER,
+
+ FORCE_EAGER_SESSION_FILTER,
+
CHANNEL_FILTER,
- /** Concurrent Sessions */
- CONCURRENT_SESSION_FILTER,
- /** Populates the SecurityContextHolder */
+
SECURITY_CONTEXT_FILTER,
- /** Logout */
+
+ CONCURRENT_SESSION_FILTER,
+
+ WEB_ASYNC_MANAGER_FILTER,
+
+ HEADERS_FILTER,
+
+ CORS_FILTER,
+
+ SAML2_LOGOUT_REQUEST_FILTER,
+
+ SAML2_LOGOUT_RESPONSE_FILTER,
+
+ CSRF_FILTER,
+
+ SAML2_LOGOUT_FILTER,
+
LOGOUT_FILTER,
- /** x509 certs */
+
+ OAUTH2_AUTHORIZATION_REQUEST_FILTER,
+
+ SAML2_AUTHENTICATION_REQUEST_FILTER,
+
X509_FILTER,
- /** Pre-auth */
+
PRE_AUTH_FILTER,
- /** CAS */
+
CAS_FILTER,
- /** UsernamePasswordAuthenticationFilter */
+
+ OAUTH2_LOGIN_FILTER,
+
+ SAML2_AUTHENTICATION_FILTER,
+
FORM_LOGIN_FILTER,
- /** OpenID */
- OPENID_FILTER,
- /** Not used, generates a dynamic login form */
+
LOGIN_PAGE_FILTER,
- /** Digest auth */
+
+ LOGOUT_PAGE_FILTER,
+
DIGEST_AUTH_FILTER,
- /** Basic Auth */
+
+ BEARER_TOKEN_AUTH_FILTER,
+
BASIC_AUTH_FILTER,
- /** saved request filter */
+
REQUEST_CACHE_FILTER,
- /** SecurityContextHolderAwareRequestFilter */
+
SERVLET_API_SUPPORT_FILTER,
- /** Remember-me cookie */
+
+ JAAS_API_SUPPORT_FILTER,
+
REMEMBER_ME_FILTER,
- /** Anonymous auth */
+
ANONYMOUS_FILTER,
- /** SessionManagementFilter */
+
+ OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER,
+
+ WELL_KNOWN_CHANGE_PASSWORD_REDIRECT_FILTER,
+
SESSION_MANAGEMENT_FILTER,
- /** Spring FormContentFilter allows www-url-form-encoded content-types to provide params in PUT requests */
- FORM_CONTENT_FILTER,
- /** ExceptionTranslationFilter */
+
EXCEPTION_TRANSLATION_FILTER,
- /** FilterSecurityInterceptor */
+
FILTER_SECURITY_INTERCEPTOR,
- /** Switch user */
+
SWITCH_USER_FILTER,
- /** Last */
- LAST(Integer.MAX_VALUE)
- private static final int INTERVAL = 100
+ LAST(Integer.MAX_VALUE);
+
+ private static final int INTERVAL = 100;
- /** The position in the chain. */
- final int order
+ private final int order;
- private SecurityFilterPosition() {
- order = ordinal() * INTERVAL
+ SecurityFilterPosition() {
+ this.order = ordinal() * INTERVAL;
}
- private SecurityFilterPosition(int filterOrder) {
- order = filterOrder
+ SecurityFilterPosition(int order) {
+ this.order = order;
}
+
+ public int getOrder() {
+ return this.order;
+ }
+
}
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityCoreGrailsPlugin.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityCoreGrailsPlugin.groovy
index 1d32096de..0c1f90f73 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityCoreGrailsPlugin.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityCoreGrailsPlugin.groovy
@@ -20,6 +20,7 @@ import grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionMan
import grails.plugin.springsecurity.access.vote.ClosureVoter
import grails.plugin.springsecurity.authentication.GrailsAnonymousAuthenticationProvider
import grails.plugin.springsecurity.authentication.NullAuthenticationEventPublisher
+import grails.plugin.springsecurity.cache.SpringUserCacheFactoryBean
import grails.plugin.springsecurity.userdetails.DefaultPostAuthenticationChecks
import grails.plugin.springsecurity.userdetails.DefaultPreAuthenticationChecks
import grails.plugin.springsecurity.userdetails.GormUserDetailsService
@@ -56,10 +57,10 @@ import grails.plugins.Plugin
import grails.util.Metadata
import groovy.util.logging.Slf4j
import org.grails.web.mime.HttpServletResponseExtension
+import org.springframework.boot.autoconfigure.security.SecurityProperties
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean
-import org.springframework.cache.ehcache.EhCacheFactoryBean
-import org.springframework.cache.ehcache.EhCacheManagerFactoryBean
+import org.springframework.cache.jcache.JCacheCacheManager
import org.springframework.core.Ordered
import org.springframework.expression.spel.standard.SpelExpressionParser
import org.springframework.security.access.event.LoggerListener
@@ -79,7 +80,6 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper
-import org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache
import org.springframework.security.core.userdetails.cache.NullUserCache
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
@@ -131,7 +131,7 @@ import org.springframework.security.web.session.HttpSessionEventPublisher
import org.springframework.security.web.util.matcher.AnyRequestMatcher
import org.springframework.web.filter.FormContentFilter
-import javax.servlet.DispatcherType
+import jakarta.servlet.DispatcherType
/**
* @author Burt Beckwith
@@ -222,17 +222,7 @@ class SpringSecurityCoreGrailsPlugin extends Plugin {
filter = ref('springSecurityFilterChain')
urlPatterns = ['/*']
dispatcherTypes = EnumSet.of(DispatcherType.ERROR, DispatcherType.REQUEST)
-
- // The filter chain has to be after grailsWebRequestFilter, but its order changed
- // in 3.1 (from Ordered.HIGHEST_PRECEDENCE + 30 (-2147483618) to
- // FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER + 30 (30))
- String grailsVersion = Metadata.current.getGrailsVersion()
- if (grailsVersion.startsWith('3.0')) {
- order = Ordered.HIGHEST_PRECEDENCE + 100
- }
- else {
- order = 100 // FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER + 100
- }
+ order = SecurityProperties.DEFAULT_FILTER_ORDER
}
if (conf.useHttpSessionEventPublisher) {
@@ -600,16 +590,11 @@ to default to 'Annotation'; setting value to 'Annotation'
// user details cache
if (conf.cacheUsers) {
log.trace 'Configuring user cache'
- userCache(classFor('userCache', EhCacheBasedUserCache)) {
- cache = ref('securityUserCache')
- }
- securityUserCache(classFor('securityUserCache', EhCacheFactoryBean)) {
+ userCache(classFor('userCache', SpringUserCacheFactoryBean)) {
cacheManager = ref('cacheManager')
cacheName = 'userCache'
}
- cacheManager(classFor('cacheManager', EhCacheManagerFactoryBean)) {
- cacheManagerName = 'spring-security-core-user-cache-' + UUID.randomUUID()
- }
+ cacheManager(classFor('cacheManager', JCacheCacheManager))
}
else {
userCache(classFor('userCache', NullUserCache))
@@ -679,6 +664,13 @@ to default to 'Annotation'; setting value to 'Annotation'
// build filters here to give dependent plugins a chance to register some
SortedMap filterNames = ReflectionUtils.findFilterChainNames(conf)
def securityFilterChains = applicationContext.securityFilterChains
+
+ // if sitemesh 3 is installed, the filter should be applied a second time
+ // as part of the security filter chain so that pages are decorated using the security context
+ if (applicationContext.containsBean('sitemesh')) {
+ filterNames[SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order - 10] = 'sitemesh'
+ }
+
SpringSecurityUtils.buildFilterChains filterNames, conf.filterChain.chainMap ?: [], securityFilterChains, applicationContext
log.trace 'Filter chain: {}', securityFilterChains
@@ -1122,9 +1114,9 @@ to default to 'Annotation'; setting value to 'Annotation'
(ENCODING_ID_MD4): new Md4PasswordEncoder(),
(ENCODING_ID_MD5): messageDigestPasswordEncoderMD5,
(ENCODING_ID_NOOP): NoOpPasswordEncoder.getInstance(),
- (ENCODING_ID_PBKDF2): new Pbkdf2PasswordEncoder(),
- (ENCODING_ID_SCRYPT): new SCryptPasswordEncoder(),
- (ENCODING_ID_ARGON2): new Argon2PasswordEncoder(),
+ (ENCODING_ID_PBKDF2): Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8(),
+ (ENCODING_ID_SCRYPT): SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8(),
+ (ENCODING_ID_ARGON2): Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8(),
(ENCODING_ID_SHA1): messageDigestPasswordEncoderSHA1,
(ENCODING_IDSHA256): messageDigestPasswordEncoderSHA256,
"sha256": new StandardPasswordEncoder()]
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityUtils.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityUtils.groovy
index 116b18408..a9074c14e 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityUtils.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/SpringSecurityUtils.groovy
@@ -21,7 +21,8 @@ import grails.util.Environment
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
-import org.apache.commons.lang.StringEscapeUtils
+import org.apache.commons.text.StringEscapeUtils
+import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.ApplicationContext
import org.springframework.security.access.hierarchicalroles.RoleHierarchy
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
@@ -40,9 +41,9 @@ import org.springframework.security.web.savedrequest.SavedRequest
import org.springframework.util.StringUtils
import org.springframework.web.multipart.MultipartHttpServletRequest
-import javax.servlet.Filter
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpSession
+import jakarta.servlet.Filter
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpSession
import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY
@@ -420,11 +421,14 @@ final class SpringSecurityUtils {
assert !oldFilter,
"Cannot register filter '$beanName' at position $order; '$oldFilter' is already registered in that position"
- Filter filter = getBean(beanName)
- configuredOrderedFilters[order] = filter
+ def filter = getBean(beanName)
+ if (filter instanceof FilterRegistrationBean) {
+ filter = ((FilterRegistrationBean) filter).filter
+ }
+ configuredOrderedFilters[order] = (Filter) filter
List filterChains = getBean('securityFilterChains', List)
- mergeFilterChains configuredOrderedFilters, filter, beanName, order, filterChains
+ mergeFilterChains configuredOrderedFilters, (Filter) filter, beanName, order, filterChains
log.trace 'Client registered bean "{}" as a filter at order {}', beanName, order
log.trace 'Updated filter chain: {}', filterChains
@@ -613,7 +617,7 @@ final class SpringSecurityUtils {
static String getLastUsername(HttpSession session) {
String username = (String)session.getAttribute(SPRING_SECURITY_LAST_USERNAME_KEY)
if (username) {
- username = StringEscapeUtils.unescapeHtml(username)
+ username = StringEscapeUtils.unescapeHtml4(username)
}
username
}
@@ -758,7 +762,7 @@ final class SpringSecurityUtils {
orderedNames[SecurityFilterPosition.SWITCH_USER_FILTER.order] = 'switchUserProcessingFilter'
}
- orderedNames[SecurityFilterPosition.FORM_CONTENT_FILTER.order] = 'formContentFilter'
+ orderedNames[SecurityFilterPosition.EXCEPTION_TRANSLATION_FILTER.order-10] = 'formContentFilter'
// add in filters contributed by secondary plugins
orderedNames << SpringSecurityUtils.orderedFilters
@@ -774,9 +778,12 @@ final class SpringSecurityUtils {
def allConfiguredFilters = [:]
filterNames.each { Integer order, String name ->
- Filter filter = applicationContext.getBean(name, Filter)
- allConfiguredFilters[name] = filter
- SpringSecurityUtils.configuredOrderedFilters[order] = filter
+ def filter = applicationContext.getBean(name)
+ if (filter instanceof FilterRegistrationBean) {
+ filter = ((FilterRegistrationBean) filter).filter
+ }
+ allConfiguredFilters[name] = (Filter) filter
+ SpringSecurityUtils.configuredOrderedFilters[order] = (Filter) filter
}
log.trace 'Ordered filters: {}', SpringSecurityUtils.configuredOrderedFilters
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/cache/SpringUserCacheFactoryBean.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/cache/SpringUserCacheFactoryBean.groovy
new file mode 100644
index 000000000..5f2a51e26
--- /dev/null
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/cache/SpringUserCacheFactoryBean.groovy
@@ -0,0 +1,58 @@
+/* Copyright 2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package grails.plugin.springsecurity.cache
+
+import groovy.transform.CompileStatic
+import org.springframework.beans.factory.FactoryBean
+import org.springframework.beans.factory.InitializingBean
+import org.springframework.cache.jcache.JCacheCache
+import org.springframework.cache.jcache.JCacheCacheManager
+import org.springframework.security.core.userdetails.User
+import org.springframework.security.core.userdetails.cache.SpringCacheBasedUserCache
+import org.springframework.util.Assert
+
+import javax.cache.configuration.Configuration
+import javax.cache.configuration.MutableConfiguration
+
+@CompileStatic
+class SpringUserCacheFactoryBean implements FactoryBean, InitializingBean {
+
+ JCacheCacheManager cacheManager
+ String cacheName
+ Configuration cacheConfig
+ private SpringCacheBasedUserCache springUserCache
+
+ @Override
+ SpringCacheBasedUserCache getObject() throws Exception {
+ springUserCache
+ }
+
+ @Override
+ Class> getObjectType() {
+ SpringCacheBasedUserCache
+ }
+
+ @Override
+ void afterPropertiesSet() throws Exception {
+ Assert.notNull(cacheManager, "cacheManager mandatory")
+ Assert.notNull(cacheName, "cacheName mandatory")
+ if (!cacheConfig) {
+ cacheConfig = new MutableConfiguration()
+ .setTypes(String, User)
+ .setStoreByValue(false)
+ }
+ springUserCache = new SpringCacheBasedUserCache(new JCacheCache(cacheManager.cacheManager.createCache(cacheName, cacheConfig)))
+ }
+}
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsRedirectStrategy.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsRedirectStrategy.groovy
index d04bc050d..ba5569ee8 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsRedirectStrategy.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsRedirectStrategy.groovy
@@ -20,8 +20,8 @@ import org.springframework.security.web.PortResolver
import org.springframework.security.web.RedirectStrategy
import org.springframework.security.web.util.UrlUtils
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
/**
* Builds absolute urls when using header check channel security to prevent the
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsSecurityFilterChain.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsSecurityFilterChain.groovy
index 461fb095e..bb463ec82 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsSecurityFilterChain.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/GrailsSecurityFilterChain.groovy
@@ -20,8 +20,8 @@ import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.util.matcher.AntPathRequestMatcher
import org.springframework.security.web.util.matcher.RequestMatcher
-import javax.servlet.Filter
-import javax.servlet.http.HttpServletRequest
+import jakarta.servlet.Filter
+import jakarta.servlet.http.HttpServletRequest
/**
* Based on org.springframework.security.web.DefaultSecurityFilterChain which is final.
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolder.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolder.groovy
index 41d9e308d..5db996234 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolder.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolder.groovy
@@ -14,8 +14,8 @@
*/
package grails.plugin.springsecurity.web
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import groovy.transform.CompileStatic
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolderFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolderFilter.groovy
index fa207e969..7450f69ad 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolderFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/SecurityRequestHolderFilter.groovy
@@ -20,13 +20,13 @@ import org.springframework.security.web.PortMapper
import org.springframework.security.web.PortResolver
import org.springframework.web.filter.GenericFilterBean
-import javax.servlet.FilterChain
-import javax.servlet.ServletException
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletRequestWrapper
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletRequestWrapper
+import jakarta.servlet.http.HttpServletResponse
/**
* Stores the request and response in the {@link SecurityRequestHolder}. Also wraps the request in a
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/UpdateRequestContextHolderExceptionTranslationFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/UpdateRequestContextHolderExceptionTranslationFilter.groovy
index f5c3e0c1e..72e8c9396 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/UpdateRequestContextHolderExceptionTranslationFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/UpdateRequestContextHolderExceptionTranslationFilter.groovy
@@ -23,12 +23,12 @@ import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.savedrequest.RequestCache
import org.springframework.web.context.request.RequestContextHolder
-import javax.servlet.FilterChain
-import javax.servlet.ServletException
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
/**
* Replaces the current GrailsWebRequest with one that delegates to the real current instance but uses the request and
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.groovy
index f2269d711..a9f94403b 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.groovy
@@ -14,9 +14,9 @@
*/
package grails.plugin.springsecurity.web.access
-import javax.servlet.ServletException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.beans.factory.InitializingBean
import org.springframework.security.access.AccessDeniedException
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/DefaultThrowableAnalyzer.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/DefaultThrowableAnalyzer.groovy
index 89107f397..59cae7008 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/DefaultThrowableAnalyzer.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/DefaultThrowableAnalyzer.groovy
@@ -14,7 +14,7 @@
*/
package grails.plugin.springsecurity.web.access
-import javax.servlet.ServletException
+import jakarta.servlet.ServletException
import org.springframework.security.web.util.ThrowableAnalyzer
import org.springframework.security.web.util.ThrowableCauseExtractor
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.groovy
index 266b9fac4..659e9c2b2 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.groovy
@@ -20,11 +20,11 @@ import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
-import javax.servlet.FilterChain
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.access.ConfigAttribute
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AbstractFilterInvocationDefinition.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AbstractFilterInvocationDefinition.groovy
index 7a4dc7e72..1651549a2 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AbstractFilterInvocationDefinition.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AbstractFilterInvocationDefinition.groovy
@@ -19,7 +19,7 @@ import org.springframework.web.util.UrlPathHelper
import java.util.concurrent.CopyOnWriteArrayList
-import javax.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletRequest
import org.springframework.context.support.MessageSourceAccessor
import org.springframework.http.HttpMethod
@@ -175,11 +175,11 @@ abstract class AbstractFilterInvocationDefinition implements FilterInvocationSec
}
/**
- * Resolve the URI from {@link javax.servlet.http.HttpServletRequest}
- * @param request The {@link javax.servlet.http.HttpServletRequest}
+ * Resolve the URI from {@link jakarta.servlet.http.HttpServletRequest}
+ * @param request The {@link jakarta.servlet.http.HttpServletRequest}
*
* @return The resolved URI string
- * @deprecated Use {@link org.springframework.web.util.UrlPathHelper#getRequestUri(javax.servlet.http.HttpServletRequest request)} and {@link #stripContextPath} instead
+ * @deprecated Use {@link org.springframework.web.util.UrlPathHelper#getRequestUri(jakarta.servlet.http.HttpServletRequest request)} and {@link #stripContextPath} instead
*/
@Deprecated
protected String calculateUri(HttpServletRequest request) {
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AnnotationFilterInvocationDefinition.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AnnotationFilterInvocationDefinition.groovy
index e66478712..02e0795f9 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AnnotationFilterInvocationDefinition.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/access/intercept/AnnotationFilterInvocationDefinition.groovy
@@ -44,9 +44,11 @@ import org.springframework.util.ReflectionUtils
import org.springframework.util.StringUtils
import org.springframework.web.context.ServletContextAware
-import javax.servlet.ServletContext
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.RequestDispatcher
+import jakarta.servlet.ServletContext
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
+
import java.lang.annotation.Annotation
import java.lang.reflect.AccessibleObject
import java.lang.reflect.Constructor
@@ -93,7 +95,7 @@ class AnnotationFilterInvocationDefinition extends AbstractFilterInvocationDefin
existingRequest = WebUtils.retrieveGrailsWebRequest()
}
catch (IllegalStateException e) {
- if (request.getAttribute('javax.servlet.error.status_code') == 404) {
+ if (request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) == 404) {
ERROR404
}
else {
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.groovy
index 4cbadcdf9..b02f3fe2c 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.groovy
@@ -14,9 +14,9 @@
*/
package grails.plugin.springsecurity.web.authentication
-import javax.servlet.ServletException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.RedirectStrategy
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.groovy
index c21483549..65e83c0c7 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.groovy
@@ -14,9 +14,9 @@
*/
package grails.plugin.springsecurity.web.authentication
-import javax.servlet.ServletException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.beans.factory.InitializingBean
import org.springframework.security.core.AuthenticationException
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.groovy
index 90ac41ec6..06beb6ff3 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.groovy
@@ -14,9 +14,9 @@
*/
package grails.plugin.springsecurity.web.authentication
-import javax.servlet.ServletException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/FilterProcessUrlRequestMatcher.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/FilterProcessUrlRequestMatcher.groovy
index ca6fe7b91..15072c8c2 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/FilterProcessUrlRequestMatcher.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/FilterProcessUrlRequestMatcher.groovy
@@ -14,7 +14,7 @@
*/
package grails.plugin.springsecurity.web.authentication
-import javax.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletRequest
import org.springframework.security.web.util.UrlUtils
import org.springframework.security.web.util.matcher.RequestMatcher
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/GrailsUsernamePasswordAuthenticationFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/GrailsUsernamePasswordAuthenticationFilter.groovy
index ae135ecac..071af5284 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/GrailsUsernamePasswordAuthenticationFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/GrailsUsernamePasswordAuthenticationFilter.groovy
@@ -20,9 +20,9 @@ import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
-import javax.servlet.http.HttpSession
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpSession
/**
* Extends the default {@link UsernamePasswordAuthenticationFilter} to store the
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.groovy
index 0a41a67e6..02ed25e66 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.groovy
@@ -14,8 +14,8 @@
*/
package grails.plugin.springsecurity.web.authentication
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.NullRememberMeServices
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.groovy
index 7accbd451..7a6f5cbb2 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.groovy
@@ -16,12 +16,12 @@ package grails.plugin.springsecurity.web.authentication.logout
import groovy.util.logging.Slf4j
-import javax.servlet.FilterChain
-import javax.servlet.ServletException
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationFailureHandler.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationFailureHandler.groovy
index 9d1955b3f..2f4ae2f15 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationFailureHandler.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationFailureHandler.groovy
@@ -18,9 +18,9 @@ import groovy.transform.CompileStatic
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.AuthenticationFailureHandler
-import javax.servlet.ServletException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
/**
* @author Burt Beckwith
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationSuccessHandler.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationSuccessHandler.groovy
index e738bada7..59367f9fd 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationSuccessHandler.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/authentication/preauth/x509/NullAuthenticationSuccessHandler.groovy
@@ -18,9 +18,9 @@ import groovy.transform.CompileStatic
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
-import javax.servlet.ServletException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.ServletException
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
/**
* @author Burt Beckwith
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/DebugFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/DebugFilter.groovy
index 587254938..7dc65a2a0 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/DebugFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/DebugFilter.groovy
@@ -22,11 +22,11 @@ import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.util.UrlUtils
import org.springframework.web.filter.GenericFilterBean
-import javax.servlet.*
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletRequestWrapper
-import javax.servlet.http.HttpServletResponse
-import javax.servlet.http.HttpSession
+import jakarta.servlet.*
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletRequestWrapper
+import jakarta.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpSession
/**
* Based on the package-scope org.springframework.security.config.debug.DebugFilter.
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsAnonymousAuthenticationFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsAnonymousAuthenticationFilter.groovy
index cb58c892f..01590d1e2 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsAnonymousAuthenticationFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsAnonymousAuthenticationFilter.groovy
@@ -16,11 +16,11 @@ package grails.plugin.springsecurity.web.filter
import groovy.util.logging.Slf4j
-import javax.servlet.FilterChain
-import javax.servlet.ServletException
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
import org.springframework.security.authentication.AuthenticationDetailsSource
import org.springframework.security.core.Authentication
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsRememberMeAuthenticationFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsRememberMeAuthenticationFilter.groovy
index 84f4ff66b..789933522 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsRememberMeAuthenticationFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/GrailsRememberMeAuthenticationFilter.groovy
@@ -14,8 +14,8 @@
*/
package grails.plugin.springsecurity.web.filter
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.core.Authentication
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/HttpMethodOverrideDetector.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/HttpMethodOverrideDetector.groovy
index 7dc6cc1e5..8938d76f9 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/HttpMethodOverrideDetector.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/HttpMethodOverrideDetector.groovy
@@ -3,7 +3,7 @@ package grails.plugin.springsecurity.web.filter
import groovy.transform.CompileStatic
import org.springframework.util.Assert
-import javax.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletRequest
@CompileStatic
class HttpMethodOverrideDetector {
diff --git a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/IpAddressFilter.groovy b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/IpAddressFilter.groovy
index e63d1680e..63aa8f81d 100644
--- a/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/IpAddressFilter.groovy
+++ b/plugin/src/main/groovy/grails/plugin/springsecurity/web/filter/IpAddressFilter.groovy
@@ -24,12 +24,12 @@ import org.springframework.security.web.util.matcher.IpAddressMatcher
import org.springframework.util.AntPathMatcher
import org.springframework.web.filter.GenericFilterBean
-import javax.servlet.FilterChain
-import javax.servlet.ServletException
-import javax.servlet.ServletRequest
-import javax.servlet.ServletResponse
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
+import jakarta.servlet.FilterChain
+import jakarta.servlet.ServletException
+import jakarta.servlet.ServletRequest
+import jakarta.servlet.ServletResponse
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
/**
* Blocks access to protected resources based on IP address. Sends 404 rather than
diff --git a/plugin/src/main/scripts/s2-create-persistent-token.groovy b/plugin/src/main/scripts/s2-create-persistent-token.groovy
new file mode 100644
index 000000000..3ff7fdc2b
--- /dev/null
+++ b/plugin/src/main/scripts/s2-create-persistent-token.groovy
@@ -0,0 +1,42 @@
+/* Copyright 2006-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import grails.codegen.model.Model
+
+description 'Creates a persistent token domain class for the Spring Security Core plugin', {
+ usage '''
+grails s2-create-persistent-token [DOMAIN CLASS NAME]
+
+Example: grails s2-create-persistent-token com.yourapp.PersistentLogin
+'''
+
+ argument name: 'Domain class name', description: 'The domain class full name with package'
+}
+
+String fullClassName = args[0]
+Model model = model(fullClassName)
+
+addStatus "\nCreating persistent token class $fullClassName"
+
+render template: template('PersistentLogin.groovy.template'),
+ destination: file("grails-app/domain/$model.packagePath/${model.simpleName}.groovy"),
+ model: model, overwrite: false
+
+file('grails-app/conf/application.groovy').withWriterAppend { BufferedWriter writer ->
+ writer.newLine()
+ writer.writeLine 'grails.plugin.springsecurity.rememberMe.persistent = true'
+ writer.writeLine "grails.plugin.springsecurity.rememberMe.persistentToken.domainClassName = '$fullClassName'"
+ writer.newLine()
+}
diff --git a/plugin/src/main/scripts/s2-create-role-hierarchy-entry.groovy b/plugin/src/main/scripts/s2-create-role-hierarchy-entry.groovy
new file mode 100644
index 000000000..669f17b3f
--- /dev/null
+++ b/plugin/src/main/scripts/s2-create-role-hierarchy-entry.groovy
@@ -0,0 +1,46 @@
+/* Copyright 2015-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import grails.codegen.model.Model
+
+/**
+ * @author fpape
+ * @author Burt Beckwith
+ */
+
+description 'Creates a domain class for a persistent role hierarchy for the Spring Security Core plugin', {
+ usage '''
+grails s2-create-role-hierarchy-entry [DOMAIN CLASS NAME]
+
+Example: grails s2-create-role-hierarchy-entry com.yourapp.RoleHierarchyEntry
+'''
+
+ argument name: 'Domain class name', description: 'The domain class full name with package'
+}
+
+String fullClassName = args[0]
+Model model = model(fullClassName)
+
+addStatus "\nCreating role hierarchy entry class $fullClassName"
+
+render template: template('RoleHierarchyEntry.groovy.template'),
+ destination: file("grails-app/domain/$model.packagePath/${model.simpleName}.groovy"),
+ model: model, overwrite: false
+
+file('grails-app/conf/application.groovy').withWriterAppend { BufferedWriter writer ->
+ writer.newLine()
+ writer.writeLine "grails.plugin.springsecurity.roleHierarchyEntryClassName = '$fullClassName'"
+ writer.newLine()
+}
diff --git a/plugin/src/main/scripts/s2-quickstart.groovy b/plugin/src/main/scripts/s2-quickstart.groovy
new file mode 100644
index 000000000..3d02fadc0
--- /dev/null
+++ b/plugin/src/main/scripts/s2-quickstart.groovy
@@ -0,0 +1,284 @@
+/* Copyright 2006-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import grails.codegen.model.Model
+import groovy.transform.Field
+
+@Field String usageMessage = '''
+ grails s2-quickstart [requestmap-class-name] [--groupClassName=group-class-name]
+or grails s2-quickstart --uiOnly
+
+Example: grails s2-quickstart com.yourapp User Role
+Example: grails s2-quickstart com.yourapp User Role --groupClassName=RoleGroup
+Example: grails s2-quickstart com.yourapp Person Authority Requestmap
+Example: grails s2-quickstart --uiOnly
+'''
+
+@Field Map templateAttributes
+@Field boolean uiOnly
+@Field boolean salt
+
+description 'Creates domain classes and updates config settings for the Spring Security plugin', {
+
+ usage usageMessage
+
+ argument name: 'Domain class package', description: 'The package to use for the domain classes', required: false
+ argument name: 'User class name', description: 'The name of the User/Person class', required: false
+ argument name: 'Role class name', description: 'The name of the Role class', required: false
+ argument name: 'Requestmap class name', description: 'The name of the Requestmap class', required: false
+
+ flag name: 'groupClassName', description: 'If specified, role/group classes will also be generated using the flag value as the role-group name'
+ flag name: 'uiOnly', description: 'If specified, no domain classes are created but the plugin settings are initialized (useful with LDAP, Mock, Shibboleth, etc.)'
+}
+
+Model userModel
+Model roleModel
+Model requestmapModel
+Model groupModel
+uiOnly = flag('uiOnly')
+salt = flag('salt')
+if (uiOnly) {
+ addStatus '\nConfiguring Spring Security; not generating domain classes'
+}
+else {
+
+ if (args.size() < 3) {
+ error 'Usage:' + usageMessage
+ return false
+ }
+
+ String packageName = args[0]
+ String groupClassName = flag('groupClassName')
+ String groupClassNameMessage = ''
+ if (groupClassName) {
+ groupModel = model(packageName + '.' + groupClassName)
+ groupClassNameMessage = ", and role/group classes for '" + groupModel.simpleName + "'"
+ }
+
+ userModel = model(packageName + '.' + args[1])
+ roleModel = model(packageName + '.' + args[2])
+
+ String message = "Creating User class '" + userModel.simpleName + "'"
+ if (4 == args.size()) {
+ requestmapModel = model(packageName + '.' + args[3])
+ message += ", Role class '" + roleModel.simpleName + "', and Requestmap class '" + requestmapModel.simpleName + "'" + groupClassNameMessage
+ }
+ else {
+ message += " and Role class '" + roleModel.simpleName + "'" + groupClassNameMessage
+ }
+ message += " in package '" + packageName + "'"
+ addStatus message
+
+ templateAttributes = [
+ packageName: userModel.packageName,
+ userClassName: userModel.simpleName,
+ userClassProperty: userModel.modelName,
+ roleClassName: roleModel.simpleName,
+ roleClassProperty: roleModel.modelName,
+ requestmapClassName: requestmapModel?.simpleName,
+ groupClassName: groupModel?.simpleName,
+ groupClassProperty: groupModel?.modelName]
+
+ createDomains userModel, roleModel, requestmapModel, groupModel
+}
+
+updateConfig userModel?.simpleName, roleModel?.simpleName, requestmapModel?.simpleName, userModel?.packageName, groupModel != null
+
+if (uiOnly) {
+ addStatus '''
+************************************************************
+* Your grails-app/conf/application.groovy has been updated *
+* with security settings; please verify that the *
+* values are correct. *
+************************************************************
+'''
+}
+else {
+ addStatus '''
+************************************************************
+* Created security-related domain classes. Your *
+* grails-app/conf/application.groovy has been updated with *
+* the class names of the configured domain classes; *
+* please verify that the values are correct. *
+************************************************************
+'''
+}
+
+private Map extractVersion(String versionString) {
+ def arr = versionString.split('\\.')
+ def v = [mayor: 0, minor: 0, bug: 0]
+ try {
+ if ( arr.size() >= 1) {
+ v.mayor = arr[0].toInteger()
+ }
+ if ( arr.size() >= 2) {
+ v.minor = arr[1].toInteger()
+ }
+ if ( arr.size() >= 3) {
+ v.bug = arr[2].toInteger()
+ }
+ } catch ( Exception e ) {
+ v = [mayor: 0, minor: 0, bug: 0]
+ }
+ v
+}
+
+private boolean versionAfterOrEqualsToThreshold(String threshold, String value) {
+ if ( value == null ) {
+ return false
+ }
+ if ( value.startsWith(threshold) ) {
+ return true
+ }
+
+ def va = extractVersion(value)
+ def vb = extractVersion(threshold)
+ def l = [va, vb]
+ l.sort { Map a, Map b ->
+ def compare = a.mayor <=> b.mayor
+ if ( compare != 0 ) {
+ return compare
+ }
+ compare = a.minor <=> b.minor
+ if ( compare != 0 ) {
+ return compare
+ }
+ a.bug <=> b.bug
+ }
+ def sortedValue = l[0].collect { k, v -> v }.join('.')
+ threshold.startsWith(sortedValue)
+}
+
+private void createDomains(Model userModel, Model roleModel, Model requestmapModel, Model groupModel) {
+
+ def props = new Properties()
+ file("gradle.properties")?.withInputStream { props.load(it) }
+
+ final threshold = '6.0.10'
+
+ boolean gormVersionAfterThreshold = versionAfterOrEqualsToThreshold(threshold, props.gormVersion ?: props.getProperty("gorm.version"))
+
+ if ( gormVersionAfterThreshold ) {
+ generateFile 'PersonWithoutInjection', userModel.packagePath, userModel.simpleName
+ if ( salt ) {
+ generateFile 'PersonPasswordEncoderListenerWithSalt', userModel.packagePath, userModel.simpleName, "${userModel.simpleName}PasswordEncoderListener", 'src/main/groovy'
+ } else {
+ generateFile 'PersonPasswordEncoderListener', userModel.packagePath, userModel.simpleName, "${userModel.simpleName}PasswordEncoderListener", 'src/main/groovy'
+ }
+ def beansList = [[import: "import ${userModel.packageName}.${userModel.simpleName}PasswordEncoderListener", definition: "${userModel.propertyName}PasswordEncoderListener(${userModel.simpleName}PasswordEncoderListener)"]]
+ addBeans(beansList, 'grails-app/conf/spring/resources.groovy')
+
+ } else {
+ if ( salt ) {
+ generateFile 'PersonWithSalt', userModel.packagePath, userModel.simpleName
+ } else {
+ generateFile 'Person', userModel.packagePath, userModel.simpleName
+ }
+ }
+
+ generateFile 'Authority', roleModel.packagePath, roleModel.simpleName
+ generateFile 'PersonAuthority', roleModel.packagePath, userModel.simpleName + roleModel.simpleName
+
+ if (requestmapModel) {
+ generateFile 'Requestmap', requestmapModel.packagePath, requestmapModel.simpleName
+ }
+
+ if (groupModel) {
+ generateFile 'AuthorityGroup', groupModel.packagePath, groupModel.simpleName
+ generateFile 'PersonAuthorityGroup', groupModel.packagePath, userModel.simpleName + groupModel.simpleName
+ generateFile 'AuthorityGroupAuthority', groupModel.packagePath, groupModel.simpleName + roleModel.simpleName
+ }
+}
+
+private void updateConfig(String userClassName, String roleClassName, String requestmapClassName, String packageName, boolean useRoleGroups) {
+
+ file('grails-app/conf/application.groovy').withWriterAppend { BufferedWriter writer ->
+ writer.newLine()
+ writer.newLine()
+ writer.writeLine '// Added by the Spring Security Core plugin:'
+ if (!uiOnly) {
+ writer.writeLine "grails.plugin.springsecurity.userLookup.userDomainClassName = '${packageName}.$userClassName'"
+ writer.writeLine "grails.plugin.springsecurity.userLookup.authorityJoinClassName = '${packageName}.$userClassName$roleClassName'"
+ writer.writeLine "grails.plugin.springsecurity.authority.className = '${packageName}.$roleClassName'"
+ }
+ if (useRoleGroups) {
+ writer.writeLine "grails.plugin.springsecurity.authority.groupAuthorityNameField = 'authorities'"
+ writer.writeLine 'grails.plugin.springsecurity.useRoleGroups = true'
+ }
+ if (requestmapClassName) {
+ writer.writeLine "grails.plugin.springsecurity.requestMap.className = '${packageName}.$requestmapClassName'"
+ writer.writeLine "grails.plugin.springsecurity.securityConfigType = 'Requestmap'"
+ }
+ writer.writeLine 'grails.plugin.springsecurity.controllerAnnotations.staticRules = ['
+ writer.writeLine "\t[pattern: '/', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/error', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/index', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/index.gsp', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/shutdown', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/assets/**', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/**/js/**', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/**/css/**', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/**/images/**', access: ['permitAll']],"
+ writer.writeLine "\t[pattern: '/**/favicon.ico', access: ['permitAll']]"
+ writer.writeLine ']'
+ writer.newLine()
+
+ writer.writeLine 'grails.plugin.springsecurity.filterChain.chainMap = ['
+ writer.writeLine "\t[pattern: '/assets/**', filters: 'none'],"
+ writer.writeLine "\t[pattern: '/**/js/**', filters: 'none'],"
+ writer.writeLine "\t[pattern: '/**/css/**', filters: 'none'],"
+ writer.writeLine "\t[pattern: '/**/images/**', filters: 'none'],"
+ writer.writeLine "\t[pattern: '/**/favicon.ico', filters: 'none'],"
+ writer.writeLine "\t[pattern: '/**', filters: 'JOINED_FILTERS']"
+ writer.writeLine ']'
+ writer.newLine()
+ }
+}
+
+private void generateFile(String templateName, String packagePath, String className, String fileName = null, String folder = 'grails-app/domain') {
+ render template(templateName + '.groovy.template'),
+ file("${folder}/$packagePath/${fileName ?: className}.groovy"),
+ templateAttributes, false
+}
+
+private void addBeans(List