From 8ab0d1b8f55d229d3da33e1b588e619fe92476da Mon Sep 17 00:00:00 2001 From: David Estes Date: Sun, 5 Oct 2025 19:12:31 -0400 Subject: [PATCH 1/5] enhance gradle s2-quickstart to handle running in a web-plugin profile --- .../src/docs/introduction/gettingStarted.adoc | 5 ++- .../S2QuickstartCommand.groovy | 45 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/plugin-core/docs/src/docs/introduction/gettingStarted.adoc b/plugin-core/docs/src/docs/introduction/gettingStarted.adoc index 116c18513..2b36e56cf 100644 --- a/plugin-core/docs/src/docs/introduction/gettingStarted.adoc +++ b/plugin-core/docs/src/docs/introduction/gettingStarted.adoc @@ -40,6 +40,9 @@ After installation, execute the `s2-quickstart` initialization script. This sets ./gradlew runCommand -Pargs="s2-quickstart com.yourapp User Role" ---- +If you are installing into a Grails plugin instead of an application, you must make sure you are using the `web-plugin` profile. Otherwise dependncies will not be met. +Running the same command will inject the spring beans into your `GrailsPlugin` classes `doWithSpring` method. + === Plugin Configuration and Setup The Spring Security plugin streamlines configuration and setup through a combination of steps: @@ -52,4 +55,4 @@ The Spring Security plugin streamlines configuration and setup through a combina The plugin configures Spring beans within the application context to implement various functionality components. Dependency management automatically handles the selection of appropriate jar files. -By following these steps, your Grails application will be ready to leverage the Spring Security plugin for enhanced security. While in-depth knowledge of Spring Security isn't mandatory, having a basic understanding of its underlying implementation can be helpful. For more details, refer to the [Spring Security documentation](https://{htmlsingle}). \ No newline at end of file +By following these steps, your Grails application will be ready to leverage the Spring Security plugin for enhanced security. While in-depth knowledge of Spring Security isn't mandatory, having a basic understanding of its underlying implementation can be helpful. For more details, refer to the [Spring Security documentation](https://{htmlsingle}). diff --git a/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy b/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy index 95c06bfd0..078a82ace 100644 --- a/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy +++ b/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy @@ -205,7 +205,16 @@ Example: ./grailsw s2-quickstart --uiOnly List> beans = [] beans.add([import : "import ${userModel.packageName}.${userModel.simpleName}PasswordEncoderListener".toString(), definition: "${userModel.propertyName}PasswordEncoderListener(${userModel.simpleName}PasswordEncoderListener)".toString()]) - addBeans(beans, 'grails-app/conf/spring/resources.groovy') + + if(new File('grails-app/conf/spring/resources.groovy').exists()) { + addBeans(beans, 'grails-app/conf/spring/resources.groovy') + } else { + //we could be generating this in a plugin... we should look for a Plugin class + File pluginClassFile = findPluginClass() + if(pluginClassFile != null) { + addBeansToPlugin(beans, pluginClassFile) + } + } generateFile('Authority', roleModel.packagePath, roleModel.simpleName) @@ -301,5 +310,39 @@ Example: ./grailsw s2-quickstart --uiOnly } } + private void addBeansToPlugin(List> beans, File pluginClassFile) { + List lines = [] + if (pluginClassFile.exists()) { + pluginClassFile.eachLine { line, nb -> + lines << line + if(line.contains('package')) { + beans.forEach(bean -> lines.add(bean.import)) + } + if (line.contains('doWithSpring()')) { + beans.each { Map bean -> + lines << ' ' + bean.definition + } + } + } + } + + pluginClassFile.withWriter('UTF-8') { writer -> + lines.each { String line -> + writer.write "${line}${System.lineSeparator()}" + } + } + } + + + private File findPluginClass() { + File pluginClass = null + new File("src/main/groovy").eachFileRecurse { fl -> + if (fl.isFile() && fl.name.endsWith("GrailsPlugin.groovy")) { + pluginClass = fl + } + } + return pluginClass + } + } From 99999b02ea50b36b957228235ba0d2ac4f3fea9e Mon Sep 17 00:00:00 2001 From: David Estes Date: Sun, 5 Oct 2025 19:18:32 -0400 Subject: [PATCH 2/5] Update plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../grails.plugin.springsecurity/S2QuickstartCommand.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy b/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy index 078a82ace..79b9a8511 100644 --- a/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy +++ b/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy @@ -315,7 +315,7 @@ Example: ./grailsw s2-quickstart --uiOnly if (pluginClassFile.exists()) { pluginClassFile.eachLine { line, nb -> lines << line - if(line.contains('package')) { + if(line.trim().startsWith('package ')) { beans.forEach(bean -> lines.add(bean.import)) } if (line.contains('doWithSpring()')) { From 34995494125312b500a7400e0f6f596d7c35f1fc Mon Sep 17 00:00:00 2001 From: David Estes Date: Sun, 5 Oct 2025 19:18:46 -0400 Subject: [PATCH 3/5] Update plugin-core/docs/src/docs/introduction/gettingStarted.adoc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- plugin-core/docs/src/docs/introduction/gettingStarted.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-core/docs/src/docs/introduction/gettingStarted.adoc b/plugin-core/docs/src/docs/introduction/gettingStarted.adoc index 2b36e56cf..c5879d7f1 100644 --- a/plugin-core/docs/src/docs/introduction/gettingStarted.adoc +++ b/plugin-core/docs/src/docs/introduction/gettingStarted.adoc @@ -41,7 +41,7 @@ After installation, execute the `s2-quickstart` initialization script. This sets ---- If you are installing into a Grails plugin instead of an application, you must make sure you are using the `web-plugin` profile. Otherwise dependncies will not be met. -Running the same command will inject the spring beans into your `GrailsPlugin` classes `doWithSpring` method. +Running the same command will inject the spring beans into your `GrailsPlugin` classes `doWithSpring` method. === Plugin Configuration and Setup From 7c7dc22b18f5562cb7efc612bc169c503fada409 Mon Sep 17 00:00:00 2001 From: David Estes Date: Sun, 5 Oct 2025 20:26:53 -0400 Subject: [PATCH 4/5] detect if we are using application.yml vs groovy and inject spring configuration in the yml instead --- .../S2QuickstartCommand.groovy | 81 ++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy b/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy index 79b9a8511..b1c2a93e0 100644 --- a/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy +++ b/plugin-core/plugin/grails-app/commands/grails.plugin.springsecurity/S2QuickstartCommand.groovy @@ -77,8 +77,12 @@ Example: ./grailsw s2-quickstart --uiOnly initializeTemplateAttributes() createDomains(userModel, roleModel, requestmapModel, roleGroupModel) } - - updateConfig(userModel?.simpleName, roleModel?.simpleName, requestmapModel?.simpleName, userModel?.packageName, roleGroupModel != null) + if (new File('grails-app/conf/application.yml').exists()) { + consoleLogger.addStatus('\nConfiguring Spring Security; Updating YAML Application Config') + updateYmlConfig(userModel?.simpleName, roleModel?.simpleName, requestmapModel?.simpleName, userModel?.packageName, roleGroupModel != null) + } else { + updateConfig(userModel?.simpleName, roleModel?.simpleName, requestmapModel?.simpleName, userModel?.packageName, roleGroupModel != null) + } logStatus() return SUCCESS } @@ -276,6 +280,79 @@ Example: ./grailsw s2-quickstart --uiOnly } } + private void updateYmlConfig(String userClassName, String roleClassName, String requestmapClassName, String packageName, boolean useRoleGroups) { + //I mean, we could use SNAKE YAML TO GENERATE THIS BUT I DIGRESS + file('grails-app/conf/application.yml').withWriterAppend { BufferedWriter writer -> + writer.newLine() + writer.writeLine('---') + writer.writeLine('# Added by the Spring Security Core plugin:') + writer.writeLine('grails:') + writer.writeLine(' plugin:') + writer.writeLine(' springsecurity:') + if (!uiOnly) { + writer.writeLine(' userLookup:') + writer.writeLine(" userDomainClassName: '${packageName}.$userClassName'") + writer.writeLine(" authorityJoinClassName: '${packageName}.$userClassName$roleClassName'") + } + if(!uiOnly || useRoleGroups) { + writer.writeLine(' authority:') + if(!uiOnly) { + writer.writeLine(" className: '${packageName}.$roleClassName'") + } + if(useRoleGroups) { + writer.writeLine(" groupAuthorityNameField: authorities") + } + } + + if (useRoleGroups) { + writer.writeLine(' useRoleGroups: true') + } + if (requestmapClassName) { + writer.writeLine(" requestMap.className: '${packageName}.$requestmapClassName'") + writer.writeLine(" securityConfigType: Requestmap") + } + writer.writeLine(' controllerAnnotations:') + writer.writeLine(' staticRules:') + writer.writeLine(' - pattern: /') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /error') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /index') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /index.gsp') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /shutdown') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /assets/**') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /**/js/**') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /**/css/**') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /**/images/**') + writer.writeLine(' access: [\'permitAll\']') + writer.writeLine(' - pattern: /**/favicon.ico') + writer.writeLine(' access: [\'permitAll\']') + writer.newLine() + + writer.writeLine(' filterChain:') + writer.writeLine(' chainMap:') + writer.writeLine(' - pattern: /assets/**') + writer.writeLine(' filters: none') + writer.writeLine(' - pattern: /**/js/**') + writer.writeLine(' filters: none') + writer.writeLine(' - pattern: /**/css/**') + writer.writeLine(' filters: none') + writer.writeLine(' - pattern: /**/images/**') + writer.writeLine(' filters: none') + writer.writeLine(' - pattern: /**/favicon.ico') + writer.writeLine(' filters: none') + writer.writeLine(' - pattern: /**') + writer.writeLine(' filters: JOINED_FILTERS') + 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"), From 7ecf9c5bd8c3fd60f0b8a54f8702f2f4ad44b821 Mon Sep 17 00:00:00 2001 From: James Daugherty Date: Wed, 15 Oct 2025 09:53:27 -0400 Subject: [PATCH 5/5] feedback: spelling fixes Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- plugin-core/docs/src/docs/introduction/gettingStarted.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-core/docs/src/docs/introduction/gettingStarted.adoc b/plugin-core/docs/src/docs/introduction/gettingStarted.adoc index c5879d7f1..09a8c7a72 100644 --- a/plugin-core/docs/src/docs/introduction/gettingStarted.adoc +++ b/plugin-core/docs/src/docs/introduction/gettingStarted.adoc @@ -40,7 +40,7 @@ After installation, execute the `s2-quickstart` initialization script. This sets ./gradlew runCommand -Pargs="s2-quickstart com.yourapp User Role" ---- -If you are installing into a Grails plugin instead of an application, you must make sure you are using the `web-plugin` profile. Otherwise dependncies will not be met. +If you are installing into a Grails plugin instead of an application, you must make sure you are using the `web-plugin` profile. Otherwise dependencies will not be met. Running the same command will inject the spring beans into your `GrailsPlugin` classes `doWithSpring` method. === Plugin Configuration and Setup