diff --git a/docs/src/docs/installing.adoc b/docs/src/docs/installing.adoc index d75970a..e25adf8 100644 --- a/docs/src/docs/installing.adoc +++ b/docs/src/docs/installing.adoc @@ -15,14 +15,25 @@ dependencies { Different Branches are built for different versions of Grails -* master: Grails 4 -* 3.3.x: Grails 3.3+ +* 5.0.x: Grails 7 +* 4.0: Grails 4 through Grails 6 +* 3.3.x: Grails 3.3 * grails_32: Grails 3.2 * 2.x: Grails 2 -Current version (master) is for Grails 4 only. -Previous version (3.3.x) is only compatible with Grails 3.3.x or higher. +Current version (5.0.x) is for Grails 7 only. + +For Grails 3.3.x use: + +[source, groovy] +.build.gradle +---- +dependencies { + ... + compile 'org.grails.plugins:spring-security-acl:3.2.1' + ... +---- For previous Grails 3 versions ( 3.0.x, 3.1.x and 3.2.x ) use: diff --git a/docs/src/docs/installing/distribution.adoc b/docs/src/docs/installing/distribution.adoc index f1b1a3f..f15e6a2 100644 --- a/docs/src/docs/installing/distribution.adoc +++ b/docs/src/docs/installing/distribution.adoc @@ -1,5 +1,5 @@ [[Distribution]] === Distribution -Grails Spring Security ACL plugin is https://bintray.com/grails/plugins/spring-security-acl[distributed in bintray]. +Grails Spring Security ACL plugin is https://repo.grails.org/ui/native/core/org/grails/plugins/spring-security-acl/[distributed in repo.grails.org]. diff --git a/docs/src/docs/installing/snapshots.adoc b/docs/src/docs/installing/snapshots.adoc index ff63307..61026fa 100644 --- a/docs/src/docs/installing/snapshots.adoc +++ b/docs/src/docs/installing/snapshots.adoc @@ -1,11 +1,11 @@ [[Snapshots]] === Snapshots -Snapshots are published automatically to https://oss.jfrog.org/[Artifactory OSS] on every successful build. +Snapshots are published automatically to https://repo.grails.org/ui/native/core/org/grails/plugins/spring-security-acl/[repo.grails.org] on every successful build. You can use them by defining this Maven repository inside the `repositories` block in your `build.gradle`: [source, groovy] ---- -maven { url "https://oss.jfrog.org/artifactory/oss-snapshot-local" } +maven { url "https://repo.grails.org/grails/core" } ---- \ No newline at end of file diff --git a/docs/src/docs/introduction.adoc b/docs/src/docs/introduction.adoc index af096a8..6330109 100644 --- a/docs/src/docs/introduction.adoc +++ b/docs/src/docs/introduction.adoc @@ -1,10 +1,10 @@ [[introduction]] == Introduction to the Spring Security ACL Plugin -The ACL plugin adds Domain Object Security support to a Grails application that uses Spring Security. It depends on the http://grails.org/plugin/spring-security-core[Spring Security Core plugin]. +The ACL plugin adds Domain Object Security support to a Grails application that uses Spring Security. It depends on the https://github.com/grails/grails-spring-security-core[Spring Security Core plugin]. The core plugin and other extension plugins support restricting access to URLs via rules that include checking a user's authentication status, roles, etc. and the ACL plugin extends this by adding support for restricting access to individual domain class instances. The access can be very fine-grained and can define which actions can be taken on an object - these typically include Read, Create, Write, Delete, and Administer but you're free to define whatever actions you like. To learn about using ACLs in Grails, you can follow the <> and in addition you can download and run a complete Grails application that uses the plugin. Installing and running the application are described in <>. -In addition to this document, you should read the http://docs.spring.io/spring-security/site/docs/5.0.x/reference/htmlsingle/#domain-acls[Spring Security documentation]. \ No newline at end of file +In addition to this document, you should read the https://docs.spring.io/spring-security/reference/servlet/authorization/acls.html[Spring Security documentation]. \ No newline at end of file diff --git a/docs/src/docs/tutorial.adoc b/docs/src/docs/tutorial.adoc index 6fa2a5d..c49d114 100644 --- a/docs/src/docs/tutorial.adoc +++ b/docs/src/docs/tutorial.adoc @@ -26,7 +26,7 @@ and run the `compile` command to resolve the dependencies: $ grails compile .... -This will transitively install the http://grails.org/plugin/spring-security-core[Spring Security Core] plugin, so you'll need to configure that by running the `s2-quickstart` script: +This will transitively install the https://github.com/grails/grails-spring-security-core[Spring Security Core] plugin, so you'll need to configure that by running the `s2-quickstart` script: .... $ grails s2-quickstart com.testacl User Role @@ -76,6 +76,7 @@ import org.springframework.security.acls.model.AccessControlEntry import org.springframework.security.acls.model.MutableAcl import org.springframework.security.acls.model.Permission import org.springframework.security.acls.model.Sid +import org.springframework.security.core.parameters.P import grails.compiler.GrailsCompileStatic import grails.plugin.springsecurity.SpringSecurityService @@ -97,7 +98,7 @@ class ReportService { @PreAuthorize('hasPermission(#report, admin)') @Transactional - void addPermission(Report report, String username, Permission permission) { + void addPermission(@P("report") Report report, String username, Permission permission) { aclUtilService.addPermission report, username, permission } @@ -113,7 +114,7 @@ class ReportService { } @PreAuthorize('hasPermission(#id, "com.testacl.Report", read) or hasPermission(#id, "com.testacl.Report", admin)') - Report get(long id) { + Report get(@P("id") long id) { Report.get id } @@ -129,13 +130,13 @@ class ReportService { @Transactional @PreAuthorize('hasPermission(#report, write) or hasPermission(#report, admin)') - void update(Report report, String name) { + void update(@P("report") Report report, String name) { report.name = name } @Transactional @PreAuthorize('hasPermission(#report, delete) or hasPermission(#report, admin)') - void delete(Report report) { + void delete(@P("report") Report report) { report.delete() // Delete the ACL information as well @@ -144,7 +145,7 @@ class ReportService { @Transactional @PreAuthorize('hasPermission(#report, admin)') - void deletePermission(Report report, Sid recipient, Permission permission) { + void deletePermission(@P("report") Report report, Sid recipient, Permission permission) { MutableAcl acl = (MutableAcl)aclUtilService.readAcl(report) // Remove all permissions associated with this particular diff --git a/docs/src/docs/usage/acls.adoc b/docs/src/docs/usage/acls.adoc index 54a4082..41a3cf2 100644 --- a/docs/src/docs/usage/acls.adoc +++ b/docs/src/docs/usage/acls.adoc @@ -3,7 +3,7 @@ ==== Suggested application changes -To properly display access denied exceptions (e.g. when a user tries to perform an action but doesn't have a grant authorizing it), you should create a mapping in `grails-app/controllers/UrlMappings.groovy` for error code 403. In addition, it's possible to trigger a http://docs.spring.io/spring-security/site/docs/5.0.x/apidocs/org/springframework/security/acls/model/NotFoundException.html[NotFoundException] which will create an error 500, but should be treated like a 403 error, so you should add mappings for these conditions: +To properly display access denied exceptions (e.g. when a user tries to perform an action but doesn't have a grant authorizing it), you should create a mapping in `grails-app/controllers/UrlMappings.groovy` for error code 403. In addition, it's possible to trigger a https://docs.spring.io/spring-security/site/docs/6.4.1/api/org/springframework/security/acls/model/NotFoundException.html[NotFoundException] which will create an error 500, but should be treated like a 403 error, so you should add mappings for these conditions: [source,java] ---- diff --git a/docs/src/docs/usage/configuration.adoc b/docs/src/docs/usage/configuration.adoc index f8bd84a..2045903 100644 --- a/docs/src/docs/usage/configuration.adoc +++ b/docs/src/docs/usage/configuration.adoc @@ -27,7 +27,7 @@ grails.plugin.springsecurity.acl.authority. ==== Run-As Authentication Replacement -There are also two options to configure http://docs.spring.io/spring-security/site/docs/5.0.x/reference/htmlsingle/#runas[Run-As Authentication Replacement]: +There are also two options to configure https://docs.spring.io/spring-security/reference/servlet/authentication/runas.html[Run-As Authentication Replacement]: [width="100%",options="header"] |==================== diff --git a/docs/src/docs/usage/customPermissions.adoc b/docs/src/docs/usage/customPermissions.adoc index c352c54..c72ecff 100644 --- a/docs/src/docs/usage/customPermissions.adoc +++ b/docs/src/docs/usage/customPermissions.adoc @@ -61,7 +61,7 @@ Once this is done you can use the permission like any other, specifying its quot [source,java] ---- @PreAuthorize("hasPermission(#id, 'com.testacl.Report', 'approve')") -Report get(long id) { +Report get(@P("id") long id) { Report.get id } ---- diff --git a/docs/src/docs/usage/domainClasses.adoc b/docs/src/docs/usage/domainClasses.adoc index 8f9676e..945097e 100644 --- a/docs/src/docs/usage/domainClasses.adoc +++ b/docs/src/docs/usage/domainClasses.adoc @@ -57,7 +57,7 @@ By default it's assumed that domain classes have a numeric primary key, but that Finally, the `AclEntry` domain class contains entries representing grants (or denials) of a permission on an object instance to a recipient. The `aclObjectIdentity` field references the domain class instance (since an instance can have many granted permissions). The `sid` field references the recipient. The `granting` field determines whether the entry grants the permission (`true`) or denies it (`false`). The `aceOrder` field specifies the position of the entry, which is important because the entries are evaluated in order and the first matching entry determines whether access is allowed. `auditSuccess` and `auditFailure` determine whether to log success and/or failure events (these both default to `false`). -The `mask` field holds the permission. This can be a source of confusion because the name (and the Spring Security documentation) indicates that it's a bit mask. A value of 1 indicates permission A, a value of 2 indicates permission B, a value of 4 indicates permission C, a value of 8 indicates permission D, etc. So you would think that a value of 5 would indicate a grant of both permission A and C. Unfortunately this is not the case. There is a http://docs.spring.io/spring-security/site/docs/5.0.x/apidocs/org/springframework/security/acls/domain/CumulativePermission.html[CumulativePermission] class that supports this, but the standard classes don't support it (`AclImpl.isGranted()` checks for == rather than using | (bitwise or) so a combined entry would never match). So rather than grouping all permissions for one recipient on one instances into a bit mask, you must create individual records for each. +The `mask` field holds the permission. This can be a source of confusion because the name (and the Spring Security documentation) indicates that it's a bit mask. A value of 1 indicates permission A, a value of 2 indicates permission B, a value of 4 indicates permission C, a value of 8 indicates permission D, etc. So you would think that a value of 5 would indicate a grant of both permission A and C. Unfortunately this is not the case. There is a https://docs.spring.io/spring-security/site/docs/6.4.1/api/org/springframework/security/acls/domain/CumulativePermission.html[CumulativePermission] class that supports this, but the standard classes don't support it (`AclImpl.isGranted()` checks for == rather than using | (bitwise or) so a combined entry would never match). So rather than grouping all permissions for one recipient on one instances into a bit mask, you must create individual records for each. [source,groovy] ---- diff --git a/docs/src/docs/usage/runAs.adoc b/docs/src/docs/usage/runAs.adoc index e570a9c..3a202d6 100644 --- a/docs/src/docs/usage/runAs.adoc +++ b/docs/src/docs/usage/runAs.adoc @@ -1,7 +1,7 @@ [[runAs]] === Run-As Authentication Replacement -Although not strictly related to ACLs, the plugin implements http://docs.spring.io/spring-security/site/docs/5.0.x/reference/htmlsingle/#runas[Run-As Authentication Replacement] since it's related to method security in general. This feature is similar to the Switch User feature of the Spring Security Core plugin, but instead of running as another user until you choose to revert to your original `Authentication`, the temporary authentication switch only lasts for one method invocation. +Although not strictly related to ACLs, the plugin implements https://docs.spring.io/spring-security/reference/servlet/authentication/runas.html[Run-As Authentication Replacement] since it's related to method security in general. This feature is similar to the Switch User feature of the Spring Security Core plugin, but instead of running as another user until you choose to revert to your original `Authentication`, the temporary authentication switch only lasts for one method invocation. For example, in this service `someMethod()` requires that the authenticated user have `ROLE_ADMIN` and will also be granted `ROLE_RUN_AS_SUPERUSER` for the duration of the method only: diff --git a/docs/src/docs/usage/serviceMethods.adoc b/docs/src/docs/usage/serviceMethods.adoc index 3b2d273..78c1666 100644 --- a/docs/src/docs/usage/serviceMethods.adoc +++ b/docs/src/docs/usage/serviceMethods.adoc @@ -5,12 +5,12 @@ There are two primary use cases for ACL security: determining whether a user is There are four annotations: -* http://docs.spring.io/spring-security/site/docs/5.0.x/apidocs/org/springframework/security/access/prepost/PreAuthorize.html[@PreAuthorize] -* http://docs.spring.io/spring-security/site/docs/5.0.x/apidocs/org/springframework/security/access/prepost/PreFilter.html[@PreFilter] -* http://docs.spring.io/spring-security/site/docs/5.0.x/apidocs/org/springframework/security/access/prepost/PostAuthorize.html[@PostAuthorize] -* http://docs.spring.io/spring-security/site/docs/5.0.x/apidocs/org/springframework/security/access/prepost/PostFilter.html[@PostFilter] +* https://docs.spring.io/spring-security/site/docs/6.4.1/api/org/springframework/security/access/prepost/PreAuthorize.html[@PreAuthorize] +* https://docs.spring.io/spring-security/site/docs/6.4.1/api/org/springframework/security/access/prepost/PreFilter.html[@PreFilter] +* https://docs.spring.io/spring-security/site/docs/6.4.1/api/org/springframework/security/access/prepost/PostAuthorize.html[@PostAuthorize] +* https://docs.spring.io/spring-security/site/docs/6.4.1/api/org/springframework/security/access/prepost/PostFilter.html[@PostFilter] -The annotations use security-specific Spring expression language (SpEL) expressions - see http://docs.spring.io/spring-security/site/docs/5.0.x/reference/htmlsingle/#el-access[the documentation] for the available standard and method expressions. +The annotations use security-specific Spring expression language (SpEL) expressions - see https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html#authorization-expressions[the documentation] for the available standard and method expressions. Here's an example service that manages a `Report` domain class and uses these annotations and expressions: @@ -18,6 +18,7 @@ Here's an example service that manages a `Report` domain class and uses these an ---- import org.springframework.security.access.prepost.PostFilter import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.security.core.parameters.P import grails.gorm.transactions.Transactional import com.yourapp.Report @@ -26,7 +27,7 @@ class ReportService { @PreAuthorize("hasPermission(#id, 'com.yourapp.Report', read) or " + "hasPermission(#id, 'com.yourapp.Report', admin)") - Report getReport(long id) { + Report getReport(@P("id") long id) { Report.get(id) } @@ -53,7 +54,7 @@ class ReportService { @Transactional @PreAuthorize("hasPermission(#report, write) or " + "hasPermission(#report, admin)") - Report updateReport(Report report, params) { + Report updateReport(@P("report") Report report, params) { report.properties = params report.save() report @@ -62,7 +63,7 @@ class ReportService { @Transactional @PreAuthorize("hasPermission(#report, delete) or " + "hasPermission(#report, admin)") - void deleteReport(Report report) { + void deleteReport(@P("report") Report report) { report.delete() } }