Compare commits
235 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85b807dea8 | |||
| 8b33d49a03 | |||
| da509a3986 | |||
| 7675320a0c | |||
| 6747e1330f | |||
| 932b084923 | |||
| 66ca1d93f2 | |||
| 8fb27d9329 | |||
| 14e3e0f0b7 | |||
| 76f33ae6e6 | |||
| b0651b97fd | |||
| 7cce996ebe | |||
| 2aa09d11e2 | |||
| 8ab8376b9c | |||
| 5699a36627 | |||
| 0f0e973c1e | |||
| 9c76f54958 | |||
| 14e4a812a1 | |||
| be0759302f | |||
| ff25799f36 | |||
| 54b28873ee | |||
| 692ac213f9 | |||
| e4e7363196 | |||
| 75e248344b | |||
| 3ae6cdf05f | |||
| a9c8b350b8 | |||
| da9eca223b | |||
| c7e18db138 | |||
| 9c181c58cb | |||
| 7b61962915 | |||
| a302106082 | |||
| fe737cc67d | |||
| d4508858f3 | |||
| 76432029c5 | |||
| 0d0afb992e | |||
| b35d7e229d | |||
| 3c81e122bd | |||
| 929a5de163 | |||
| ecac6cdfc1 | |||
| 2ad73af130 | |||
| 0aaefa2bb9 | |||
| 21c70155a3 | |||
| 7ca913dadf | |||
| 7eb87b19b3 | |||
| 1683d30c2e | |||
| adfb3ddf77 | |||
| 1ba1fb61a7 | |||
| e3a1fa2f86 | |||
| ac657a32a6 | |||
| 6c98a49010 | |||
| f2db4b6cdb | |||
| 9156d3bce3 | |||
| 327c52d650 | |||
| d98d23e5ef | |||
| f892746c00 | |||
| b95ccc211b | |||
| 820b2046fb | |||
| bde423524b | |||
| 78d8b9fa71 | |||
| 35bbccad3c | |||
| 04cc0d486b | |||
| e7b43f14c8 | |||
| 0629ecbb00 | |||
| 93557505c0 | |||
| 8facc74da2 | |||
| c0f16908a1 | |||
| 8be0691e8f | |||
| e794dcd203 | |||
| dbaeb2fdd9 | |||
| ae2809634f | |||
| 8fd5cca501 | |||
| a867f92416 | |||
| a1a61d3259 | |||
| fbf3c7d083 | |||
| 76a869995e | |||
| 702ec17a5f | |||
| ba4953b057 | |||
| b87ea1373d | |||
| 7754a11a4a | |||
| 409ef7d5e1 | |||
| d01b6fc6b1 | |||
| 0994a64830 | |||
| d3d5836da4 | |||
| b2d4fec361 | |||
| 4a7bdc1d65 | |||
| f154c7d9dc | |||
| fbac953f10 | |||
| 504c28ec01 | |||
| 613464cda0 | |||
| 6f02f690ac | |||
| 14c4ac75ec | |||
| b46f5f69ac | |||
| 28afc38c8f | |||
| 9f19541484 | |||
| df075a8c7c | |||
| ff24cd0b8c | |||
| ac93f108d6 | |||
| 6653a40ddd | |||
| 70851032e4 | |||
| 93f99d0a66 | |||
| 7cabf2774b | |||
| da17016bbd | |||
| 41a7d82211 | |||
| d4a3f1ee4d | |||
| 64682ab6b8 | |||
| 2484f72292 | |||
| 1693625acb | |||
| 0f7645aa50 | |||
| f79fe3ce46 | |||
| 853765c55c | |||
| 59ea0f0711 | |||
| 7da0c74095 | |||
| e8d58498b0 | |||
| 5802393073 | |||
| bab5b73e71 | |||
| 717bf4819b | |||
| fd31e52fb1 | |||
| 4732d08080 | |||
| 2c69092bdd | |||
| 8f671f807c | |||
| ed90e4143e | |||
| 3747a14258 | |||
| 10fec400eb | |||
| 315c0b3f03 | |||
| 43677a6964 | |||
| 6d25f479b0 | |||
| 8f03a04b9a | |||
| faefcc73e9 | |||
| dfacad020b | |||
| 0af0ee3339 | |||
| dca42b5602 | |||
| 657f0475ec | |||
| 8e9f7e2f10 | |||
| bf5a3a1aee | |||
| 201690ceba | |||
| e1f33d577f | |||
| 879adcae5f | |||
| eed8538071 | |||
| 3df9ad1e8f | |||
| dac46dc57c | |||
| b5b2e2c50e | |||
| 72c99af0d4 | |||
| 742e5fd7a9 | |||
| 795c073f48 | |||
| 58c9cbb471 | |||
| e40bc262bb | |||
| b0d865e28f | |||
| 0f7f0042ac | |||
| e0f1121d5b | |||
| ea93ed4165 | |||
| 96acf33019 | |||
| 35dbc0e6a8 | |||
| 0526c5233c | |||
| 60c011a976 | |||
| 916a19ccbd | |||
| 8138fac3f9 | |||
| 62fadfd28a | |||
| 166f48e6ab | |||
| 0f97086c86 | |||
| fe5c6d6621 | |||
| c642de537a | |||
| fd27c07b55 | |||
| e0d95c7c8a | |||
| 9d76c98791 | |||
| e923371724 | |||
| 216512bc54 | |||
| 8445e91b22 | |||
| 13ccb83d6f | |||
| 127d9eece9 | |||
| 7891787a53 | |||
| 2d8b6650db | |||
| 78995ff0a9 | |||
| 7974f3161d | |||
| c35c1c0643 | |||
| 2162221589 | |||
| 040fb6aa3c | |||
| b152218ee0 | |||
| 544e421157 | |||
| 0f612bf637 | |||
| c683bc10bf | |||
| 11ab23f4f4 | |||
| 0065b55a75 | |||
| d6f9d2e34a | |||
| 5dedbb6283 | |||
| 4cad151b57 | |||
| 72080bb5fe | |||
| 5854f00977 | |||
| 93118f4e91 | |||
| 8796850816 | |||
| cee2ea9c60 | |||
| 1159c9f302 | |||
| 6c5ce1237d | |||
| f81b58112b | |||
| 0e02b489c8 | |||
| d1669b909f | |||
| cb8041ba67 | |||
| 6f74162a1f | |||
| 99a0baadfa | |||
| 1f9a0e579f | |||
| 9e7d08c9e7 | |||
| 82168faf9d | |||
| 9d0f8977a9 | |||
| 5ae615f3b4 | |||
| d2b0077392 | |||
| 092c5aecf7 | |||
| a5d56d8724 | |||
| 7c0da854da | |||
| 0f546dcb07 | |||
| cb576d16e1 | |||
| 3b4df40f47 | |||
| 6cbf71bd72 | |||
| cd63329b63 | |||
| cc7f504f96 | |||
| a094563052 | |||
| da19435f21 | |||
| be50cd8ada | |||
| 21efbb6ba7 | |||
| c7cf6fdd73 | |||
| 8129bf2ce0 | |||
| d48079eb19 | |||
| 45f1179b52 | |||
| e11dfa7578 | |||
| 6cc0f6c054 | |||
| 22ea835643 | |||
| 9f51d68e92 | |||
| 32af1884f7 | |||
| a88035196a | |||
| 0db94b1d36 | |||
| 9e8994a2b7 | |||
| 8b2faff7ad | |||
| 469bc20e6d | |||
| 947d11f433 | |||
| b3a60a83f6 | |||
| 5bc7e4171c | |||
| 80e96b0f7b |
+6
-11
@@ -1,22 +1,17 @@
|
||||
# EditorConfig for Spring Security
|
||||
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md#mind-the-whitespace
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
charset = latin1
|
||||
|
||||
[*.{java,xml}]
|
||||
# 4 tabs indentation
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
continuation_indent_size = 8
|
||||
tab_width = 4
|
||||
|
||||
ij_smart_tabs = false
|
||||
ij_java_align_multiline_parameters = false
|
||||
|
||||
[*.gradle]
|
||||
indent_style = tab
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
<!--
|
||||
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
|
||||
-->
|
||||
|
||||
### Summary
|
||||
|
||||
<!--
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
name: Bug
|
||||
about: Create a bug report to help us improve
|
||||
title: ''
|
||||
labels: 'status: waiting-for-triage, type: bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Sample**
|
||||
|
||||
A link to a GitHub repository with a [minimal, reproducible sample](https://stackoverflow.com/help/minimal-reproducible-example).
|
||||
|
||||
Reports that include a sample will take priority over reports that do not.
|
||||
At times, we may require a sample, so it is good to try and include a sample up front.
|
||||
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Community Support
|
||||
url: https://stackoverflow.com/questions/tagged/spring-security
|
||||
about: Please ask and answer questions on StackOverflow with the tag `spring-security`.
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
name: Enhancement
|
||||
about: Suggest an enhancement for this project
|
||||
title: ''
|
||||
labels: 'status: waiting-for-triage, type: enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Expected Behavior**
|
||||
|
||||
<!--- Tell us how it should work -->
|
||||
|
||||
**Current Behavior**
|
||||
|
||||
<!--- Explain the difference from current behavior -->
|
||||
|
||||
**Context**
|
||||
|
||||
<!---
|
||||
How has this issue affected you?
|
||||
What are you trying to accomplish?
|
||||
What other alternatives have you considered?
|
||||
Are you aware of any workarounds?
|
||||
-->
|
||||
@@ -1,9 +1,3 @@
|
||||
<!--
|
||||
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
|
||||
-->
|
||||
|
||||
<!--
|
||||
Before creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.
|
||||
|
||||
Thanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).
|
||||
Thanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with #).
|
||||
-->
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
name: PR Build
|
||||
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '8'
|
||||
- name: Cache Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew clean build --continue --scan
|
||||
+2
-7
@@ -1,4 +1,3 @@
|
||||
classes/
|
||||
target/
|
||||
*/src/*/java/META-INF
|
||||
*/src/META-INF/
|
||||
@@ -8,7 +7,7 @@ target/
|
||||
.project
|
||||
.DS_Store
|
||||
.settings/
|
||||
.idea/*
|
||||
.idea/
|
||||
out/
|
||||
bin/
|
||||
intellij/
|
||||
@@ -22,9 +21,5 @@ build/
|
||||
atlassian-ide-plugin.xml
|
||||
!etc/eclipse/.checkstyle
|
||||
.checkstyle
|
||||
classes/
|
||||
s101plugin.state
|
||||
.attach_pid*
|
||||
.~lock.*#
|
||||
|
||||
!.idea/checkstyle-idea.xml
|
||||
!.idea/externalDependencies.xml
|
||||
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CheckStyle-IDEA">
|
||||
<option name="configuration">
|
||||
<map>
|
||||
<entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/etc/checkstyle/checkstyle.xml:spring-security" />
|
||||
<entry key="checkstyle-version" value="8.14" />
|
||||
<entry key="copy-libs" value="false" />
|
||||
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
|
||||
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
|
||||
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/etc/checkstyle/checkstyle.xml:spring-security" />
|
||||
<entry key="property-2.config_loc" value="$PROJECT_DIR$/etc/checkstyle" />
|
||||
<entry key="scan-before-checkin" value="false" />
|
||||
<entry key="scanscope" value="JavaOnlyWithTests" />
|
||||
<entry key="suppress-errors" value="false" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-7
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalDependencies">
|
||||
<plugin id="CheckStyle-IDEA" />
|
||||
<plugin id="org.jetbrains.plugins.gradle" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,44 @@
|
||||
= Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open
|
||||
and welcoming community, we pledge to respect all people who contribute through reporting
|
||||
issues, posting feature requests, updating documentation, submitting pull requests or
|
||||
patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for
|
||||
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission
|
||||
* Other unethical or unprofessional conduct
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments,
|
||||
commits, code, wiki edits, issues, and other contributions that are not aligned to this
|
||||
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
|
||||
that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
|
||||
consistently applying these principles to every aspect of managing this project. Project
|
||||
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
|
||||
from the project team.
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an
|
||||
individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
|
||||
contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
|
||||
be reviewed and investigated and will result in a response that is deemed necessary and
|
||||
appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
|
||||
with regard to the reporter of an incident.
|
||||
|
||||
This Code of Conduct is adapted from the
|
||||
https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
|
||||
https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
|
||||
@@ -1,225 +0,0 @@
|
||||
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
|
||||
|
||||
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
|
||||
|
||||
= Code of Conduct
|
||||
|
||||
Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct].
|
||||
|
||||
= Similar but different
|
||||
|
||||
Each Spring module is slightly different from one another in terms of team size, number of issues, etc. Therefore, each project is managed slightly different. You will notice that this document is very similar to the https://github.com/spring-projects/spring-framework/wiki/Contributor-guidelines[Spring Framework Contributor guidelines]. However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
|
||||
|
||||
= Importing into IDE
|
||||
|
||||
The following provides information on setting up a development environment that can run the sample in https://www.springsource.org/sts[Spring Tool Suite 3.6.0+]. Other IDE's should work using Gradle's IDE support, but have not been tested.
|
||||
|
||||
* IDE Setup
|
||||
** Install Spring Tool Suite 3.6.0+
|
||||
** You will need the following plugins installed (can be found on the Extensions Page)
|
||||
*** Gradle Eclipse
|
||||
*** Groovy Eclipse
|
||||
* Importing the project into Spring Tool Suite
|
||||
** File -> Import… -> Gradle Project
|
||||
|
||||
As of new versions of Spring Tool Suite, you might need to install Groovy Eclipse pointing directly to the updated plugin location. To install Groovy Eclipse on Spring Tool Suite based on Eclipse Oxigen you must do the following steps:
|
||||
|
||||
Help -> Install New Software… -> Add the following URL into _Work with_ field:
|
||||
https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/[https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/]
|
||||
|
||||
= Understand the basics
|
||||
|
||||
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent https://help.github.com/articles/using-pull-requests[help documentation first].
|
||||
|
||||
= Search GitHub issues; create an issue if necessary
|
||||
|
||||
Is there already an issue that addresses your concern? Do a bit of searching in our https://github.com/spring-projects/spring-security/issues[GitHub issues] to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
|
||||
|
||||
= Discuss non-trivial contribution ideas with committers
|
||||
|
||||
If you're considering anything more than correcting a typo or fixing a minor bug, please discuss it on the https://gitter.im/spring-projects/spring-security[Spring Security Gitter] before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
|
||||
|
||||
= Sign the Contributor License Agreement
|
||||
|
||||
If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
|
||||
|
||||
= Create your branch from master
|
||||
|
||||
Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
|
||||
|
||||
= Use short branch names
|
||||
|
||||
Branches used when submitting pull requests should preferably be named according to GitHub issues, e.g. `gh-1234` or `gh-1234-fix-npe`. Otherwise, use succinct, lower-case, dash (`-`) delimited names, such as `fix-warnings` or `fix-typo`. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
|
||||
|
||||
= Keep commits focused
|
||||
|
||||
Remember each ticket should be focused on a single item of interest since the tickets are used to produce the changelog. Since each commit should be tied to a single GitHub issue, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the GitHub is to update the library. Reviewing your commits is essential before sending a pull request.
|
||||
|
||||
= Mind the whitespace
|
||||
|
||||
Please carefully follow the whitespace and formatting conventions already present in the framework.
|
||||
|
||||
. Tabs, not spaces
|
||||
. Unix (LF), not dos (CRLF) line endings
|
||||
. Eliminate all trailing whitespace
|
||||
. Aim to wrap code at 120 characters, but favor readability over wrapping
|
||||
. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
. Search the codebase using `git grep` and other tools to discover common naming conventions, etc.
|
||||
. UTF-8 encoding for Java sources and XML files
|
||||
|
||||
Whitespace management tips
|
||||
|
||||
. You can use the https://marketplace.eclipse.org/content/anyedit-tools[AnyEdit Eclipse plugin] to ensure spaces are used and to clean up trailing whitespaces.
|
||||
. Use Git's `pre-commit.sample` hook to prevent invalid whitespace from being pushed out. You can enable it by moving `.git/hooks/pre-commit.sample` to `.git/hooks/pre-commit` and ensuring it is executable. For more information on hooks refer to https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks[https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks].
|
||||
|
||||
= Add Apache license header to all new classes
|
||||
|
||||
----
|
||||
/*
|
||||
* Copyright 2002-2020 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
|
||||
*
|
||||
* https://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 ...;
|
||||
----
|
||||
|
||||
= Update Apache license header to modified files as necessary
|
||||
|
||||
Always check the date range in the license header. For example, if you've modified a file in 2020 whose header still reads
|
||||
|
||||
----
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
----
|
||||
|
||||
then be sure to update it to the current year appropriately (e.g. 2020)
|
||||
|
||||
----
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
----
|
||||
|
||||
= Use @since tags for newly-added public API types and methods
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
/**
|
||||
* …
|
||||
*
|
||||
* @author First Last
|
||||
* @since 5.4
|
||||
* @see …
|
||||
*/
|
||||
----
|
||||
|
||||
= Submit JUnit test cases for all behavior changes
|
||||
|
||||
Search the codebase to find related unit tests and add additional `@Test` methods within.
|
||||
|
||||
. Any new tests should end in the name `Tests` (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
|
||||
. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with `@Test`.
|
||||
|
||||
= Update spring-security-x.y.rnc for schema changes
|
||||
|
||||
Update the https://www.relaxng.org[RELAX NG] schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
|
||||
|
||||
Changes to the XML schema will be overwritten by the Gradle build task.
|
||||
|
||||
= Squash commits
|
||||
|
||||
Use `git rebase --interactive`, `git add --patch` and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for `git`, there are https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History[many resources online] to help you understand how these tools work.
|
||||
|
||||
= Use real name in git commits
|
||||
|
||||
Please configure Git to use your real first and last name for any commits you intend to submit as pull requests. Make sure the name is properly capitalized as submitted to the https://cla.pivotal.io[Pivotal Contributor License Agreement]:
|
||||
|
||||
----
|
||||
First Last <user@mail.com>
|
||||
----
|
||||
|
||||
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like Git shortlog and others.
|
||||
|
||||
You can configure this globally:
|
||||
|
||||
----
|
||||
git config --global user.name "First Last"
|
||||
git config --global user.email user@example.com
|
||||
----
|
||||
|
||||
or locally for the current repository by omitting the `--global` flag:
|
||||
|
||||
----
|
||||
git config user.name "First Last"
|
||||
git config user.email user@example.com
|
||||
----
|
||||
|
||||
= Format commit messages
|
||||
|
||||
. Keep the subject line to 50 characters or less if possible
|
||||
. Do not end the subject line with a period
|
||||
. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
|
||||
. Include `Closes gh-<issue-number>` at the end if this fixes a GitHub issue
|
||||
. Avoid markdown, including back-ticks identifying code
|
||||
|
||||
Example:
|
||||
|
||||
----
|
||||
Short (50 chars or less) summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of an email and the rest of the text as the body. The blank
|
||||
line separating the summary from the body is critical (unless you omit
|
||||
the body entirely); tools like rebase can get confused if you run the
|
||||
two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded by a
|
||||
single space, with blank lines in between, but conventions vary here
|
||||
|
||||
Closes gh-123
|
||||
----
|
||||
|
||||
|
||||
= Run all tests prior to submission
|
||||
|
||||
----
|
||||
./gradlew clean build integrationTest
|
||||
----
|
||||
|
||||
= Submit your pull request
|
||||
|
||||
*Subject line:*
|
||||
|
||||
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
|
||||
|
||||
*In the body:*
|
||||
|
||||
. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
|
||||
. Add any additional information and ask questions; start a conversation, or continue one from GitHub Issues
|
||||
. Mention any GitHub Issues
|
||||
. Also mention that you have submitted the CLA as described above
|
||||
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
|
||||
|
||||
= Mention your pull request on the associated GitHub issue
|
||||
|
||||
Add a comment to the associated GitHub issue(s) linking to your new pull request.
|
||||
|
||||
= Expect discussion and rework
|
||||
|
||||
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
|
||||
|
||||
Note that you can always force push (`git push -f`) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
|
||||
|
||||
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
|
||||
|
||||
# Code of Conduct
|
||||
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.adoc).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||
|
||||
# Similar but different
|
||||
|
||||
Each Spring module is slightly different than another in terms of team size, number of issues, etc. Therefore each project is managed slightly different. You will notice that this document is very similar to the [Spring Framework Contributor guidelines](https://github.com/SpringSource/spring-framework/wiki/Contributor-guidelines). However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
|
||||
|
||||
# Importing into IDE
|
||||
|
||||
The following provides information on setting up a development environment that can run the sample in [Spring Tool Suite 3.6.0+](https://www.springsource.org/sts). Other IDE's should work using Gradle's IDE support, but have not been tested.
|
||||
|
||||
* IDE Setup
|
||||
* Install Spring Tool Suite 3.6.0+
|
||||
* You will need the following plugins installed (can be found on the Extensions Page)
|
||||
* Gradle Eclipse
|
||||
* Groovy Eclipse
|
||||
* Importing the project into Spring Tool Suite
|
||||
* File->Import...->Gradle Project
|
||||
|
||||
# Understand the basics
|
||||
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent [help documentation first](https://help.github.com/articles/using-pull-requests).
|
||||
|
||||
# Search GitHub issues; create an issue if necessary
|
||||
Is there already an issue that addresses your concern? Do a bit of searching in our [GitHub issues ](https://github.com/spring-projects/spring-security/issues) to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
|
||||
|
||||
# Discuss non-trivial contribution ideas with committers
|
||||
If you're considering anything more than correcting a typo or fixing a minor bug, please discuss it on the [Spring Security Gitter](https://gitter.im/spring-projects/spring-security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
|
||||
|
||||
# Sign the Contributor License Agreement
|
||||
|
||||
If you have not previously done so, please fill out and
|
||||
submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring).
|
||||
|
||||
# Create your branch from master
|
||||
Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
|
||||
|
||||
# Use short branch names
|
||||
Branches used when submitting pull requests should preferably be named according to GitHub issues, e.g. 'gh-1234' or 'gh-1234-fix-npe'. Otherwise, use succinct, lower-case, dash (-) delimited names, such as 'fix-warnings', 'fix-typo', etc. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
|
||||
|
||||
#Keep commits focused
|
||||
|
||||
Remember each ticket should be focused on a single item of interest since the tickets are used to produce the changelog. Since each commit should be tied to a single GitHub issue, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the GitHub is to update the library. Reviewing your commits is essential before sending a pull request.
|
||||
|
||||
# Mind the whitespace
|
||||
Please carefully follow the whitespace and formatting conventions already present in the framework.
|
||||
|
||||
1. Tabs, not spaces
|
||||
1. Unix (LF), not dos (CRLF) line endings
|
||||
1. Eliminate all trailing whitespace
|
||||
1. Aim to wrap code at 120 characters, but favor readability over wrapping
|
||||
1. Preserve existing formatting; i.e. do not reformat code for its own sake
|
||||
1. Search the codebase using git grep and other tools to discover common naming conventions, etc.
|
||||
1. Latin-1 (ISO-8859-1) encoding for Java sources; use native2ascii to convert if necessary
|
||||
|
||||
Whitespace management tips
|
||||
|
||||
1. You can use the [AnyEdit Eclipse plugin](https://marketplace.eclipse.org/content/anyedit-tools) to ensure spaces are used and to clean up trailing whitespaces.
|
||||
1. Use git's pre-commit.sample hook to prevent invalid whitespace from being pushed out. You can enable it by moving ~/spring-security/.git/hooks/pre-commit.sample to ~/spring-security/.git/hooks/pre-commit and ensuring it is executable. For more information on hooks refer to [Pro Git's Pre-Commit Hook's section](https://git-scm.com/book/cs/ch7-3.html)
|
||||
|
||||
# Add Apache license header to all new classes
|
||||
|
||||
<pre>
|
||||
/*
|
||||
* Copyright 2002-2012 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
|
||||
*
|
||||
* https://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 ...;
|
||||
</pre>
|
||||
# Update Apache license header to modified files as necessary
|
||||
Always check the date range in the license header. For example, if you've modified a file in 2012 whose header still reads
|
||||
<pre>
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
</pre>
|
||||
then be sure to update it to 2012 appropriately
|
||||
<pre>
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
</pre>
|
||||
# Use @since tags for newly-added public API types and methods
|
||||
e.g.
|
||||
<pre>
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @author First Last
|
||||
* @since 3.2
|
||||
* @see ...
|
||||
*/
|
||||
</pre>
|
||||
|
||||
# Submit JUnit test cases for all behavior changes
|
||||
Search the codebase to find related unit tests and add additional `@Test` methods within.
|
||||
|
||||
1. Any new tests should end in the name Tests (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
|
||||
2. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with @Test.
|
||||
|
||||
# Update spring-security-x.y.rnc for schema changes
|
||||
Update the [RELAX NG](https://relaxng.org/) schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
|
||||
|
||||
<pre>
|
||||
./gradlew spring-security-config:rncToXsd
|
||||
</pre>
|
||||
|
||||
Changes to the XML schema will be overwritten by the Gradle build task.
|
||||
|
||||
# Squash commits
|
||||
Use git rebase --interactive, git add --patch and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for git, there are many resources online to help you understand how these tools work. Here is one: https://book.git-scm.com/4_interactive_rebasing.html.
|
||||
|
||||
# Use real name in git commits
|
||||
Please configure git to use your real first and last name for any commits you intend to submit as pull requests. For example, this is not acceptable:
|
||||
|
||||
<pre>
|
||||
Author: Nickname <user@mail.com>
|
||||
</pre>
|
||||
Rather, please include your first and last name, properly capitalized, as submitted against the SpringSource contributor license agreement:
|
||||
<pre>
|
||||
Author: First Last <user@mail.com>
|
||||
</pre>
|
||||
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like git shortlog and others.
|
||||
|
||||
You can configure this globally via the account admin area GitHub (useful for fork-and-edit cases); globally with
|
||||
|
||||
<pre>
|
||||
git config --global user.name "First Last"
|
||||
git config --global user.email user@mail.com
|
||||
</pre>
|
||||
|
||||
or locally for the spring-security repository only by omitting the '--global' flag:
|
||||
<pre>
|
||||
cd spring-security
|
||||
git config user.name "First Last"
|
||||
git config user.email user@mail.com
|
||||
</pre>
|
||||
|
||||
# Format commit messages
|
||||
|
||||
<pre>
|
||||
Short (50 chars or less) summary of changes
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of an email and the rest of the text as the body. The blank
|
||||
line separating the summary from the body is critical (unless you omit
|
||||
the body entirely); tools like rebase can get confused if you run the
|
||||
two together.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded by a
|
||||
single space, with blank lines in between, but conventions vary here
|
||||
|
||||
Fixes gh-123
|
||||
</pre>
|
||||
|
||||
|
||||
1. Keep the subject line to 50 characters or less if possible
|
||||
2. Do not end the subject line with a period
|
||||
3. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
|
||||
3. Include Fixes gh-<issue-number> at the end if this fixes a GitHub issue
|
||||
|
||||
# Run all tests prior to submission
|
||||
|
||||
<pre>
|
||||
cd spring-security
|
||||
./gradlew clean build integrationTest
|
||||
</pre>
|
||||
|
||||
# Submit your pull request
|
||||
Subject line:
|
||||
|
||||
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
|
||||
|
||||
In the body:
|
||||
|
||||
1. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
|
||||
2. Add any additional information and ask questions; start a conversation, or continue one from GitHub Issues
|
||||
3. Mention any GitHub Issues
|
||||
4. Also mention that you have submitted the CLA as described above
|
||||
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
|
||||
|
||||
# Mention your pull request on the associated GitHub issue
|
||||
Add a comment to the associated GitHub issue(s) linking to your new pull request.
|
||||
|
||||
# Expect discussion and rework
|
||||
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
|
||||
|
||||
Note that you can always force push (git push -f) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
|
||||
Vendored
-245
@@ -1,245 +0,0 @@
|
||||
def projectProperties = [
|
||||
[$class: 'BuildDiscarderProperty',
|
||||
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
|
||||
pipelineTriggers([cron('@daily')])
|
||||
]
|
||||
properties(projectProperties)
|
||||
|
||||
def SUCCESS = hudson.model.Result.SUCCESS.toString()
|
||||
currentBuild.result = SUCCESS
|
||||
|
||||
def GRADLE_ENTERPRISE_CACHE_USER = usernamePassword(credentialsId: 'gradle_enterprise_cache_user',
|
||||
passwordVariable: 'GRADLE_ENTERPRISE_CACHE_PASSWORD',
|
||||
usernameVariable: 'GRADLE_ENTERPRISE_CACHE_USERNAME')
|
||||
def GRADLE_ENTERPRISE_SECRET_ACCESS_KEY = string(credentialsId: 'gradle_enterprise_secret_access_key',
|
||||
variable: 'GRADLE_ENTERPRISE_ACCESS_KEY')
|
||||
def SPRING_SIGNING_SECRING = file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')
|
||||
def SPRING_GPG_PASSPHRASE = string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')
|
||||
def OSSRH_CREDENTIALS = usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')
|
||||
def ARTIFACTORY_CREDENTIALS = usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')
|
||||
def JENKINS_PRIVATE_SSH_KEY = file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')
|
||||
def SONAR_LOGIN_CREDENTIALS = string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')
|
||||
|
||||
def jdkEnv(String jdk = 'jdk8') {
|
||||
def jdkTool = tool(jdk)
|
||||
return "JAVA_HOME=${ jdkTool }"
|
||||
}
|
||||
|
||||
try {
|
||||
parallel check: {
|
||||
stage('Check') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
|
||||
ARTIFACTORY_CREDENTIALS]) {
|
||||
withEnv([jdkEnv(),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew check -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: check'
|
||||
throw e
|
||||
} finally {
|
||||
junit '**/build/test-results/*/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
sonar: {
|
||||
stage('Sonar') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
withCredentials([SONAR_LOGIN_CREDENTIALS,
|
||||
GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
|
||||
ARTIFACTORY_CREDENTIALS]) {
|
||||
try {
|
||||
withEnv([jdkEnv(),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
if ("master" == env.BRANCH_NAME) {
|
||||
sh "./gradlew sonarqube -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --stacktrace"
|
||||
} else {
|
||||
sh "./gradlew sonarqube -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD -PexcludeProjects='**/samples/**' -Dsonar.projectKey='spring-security-${env.BRANCH_NAME}' -Dsonar.projectName='spring-security-${env.BRANCH_NAME}' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --stacktrace"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: sonar'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
snapshots: {
|
||||
stage('Snapshot Tests') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
|
||||
ARTIFACTORY_CREDENTIALS]) {
|
||||
withEnv([jdkEnv(),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies -PforceMavenRepositories=snapshot -PspringVersion='5.2.+' -PreactorVersion='Dysprosium-BUILD-SNAPSHOT' -PspringDataVersion='Neumann-BUILD-SNAPSHOT' -PrsocketVersion='1.0.+' -PspringBootVersion='2.3.+' -PlocksDisabled --stacktrace"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: snapshots'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
jdk11: {
|
||||
stage('JDK 11') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
|
||||
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
|
||||
ARTIFACTORY_CREDENTIALS]) {
|
||||
withEnv([jdkEnv("jdk11"),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: jdk11'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
jdk12: {
|
||||
stage('JDK 12') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
try {
|
||||
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
|
||||
ARTIFACTORY_CREDENTIALS]) {
|
||||
withEnv([jdkEnv("openjdk12"),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: jdk12'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(currentBuild.result == 'SUCCESS') {
|
||||
parallel artifacts: {
|
||||
stage('Deploy Artifacts') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
withCredentials([SPRING_SIGNING_SECRING,
|
||||
SPRING_GPG_PASSPHRASE,
|
||||
OSSRH_CREDENTIALS,
|
||||
ARTIFACTORY_CREDENTIALS,
|
||||
GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY]) {
|
||||
withEnv([jdkEnv(),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew deployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace --no-parallel"
|
||||
sh "./gradlew finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace --no-parallel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
stage('Deploy Docs') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
withCredentials([JENKINS_PRIVATE_SSH_KEY,
|
||||
SPRING_GPG_PASSPHRASE,
|
||||
OSSRH_CREDENTIALS,
|
||||
ARTIFACTORY_CREDENTIALS,
|
||||
GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY]) {
|
||||
withEnv([jdkEnv(),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
stage('Deploy Schema') {
|
||||
node {
|
||||
checkout scm
|
||||
sh "git clean -dfx"
|
||||
withCredentials([JENKINS_PRIVATE_SSH_KEY,
|
||||
SPRING_GPG_PASSPHRASE,
|
||||
OSSRH_CREDENTIALS,
|
||||
ARTIFACTORY_CREDENTIALS,
|
||||
GRADLE_ENTERPRISE_CACHE_USER,
|
||||
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY]) {
|
||||
withEnv([jdkEnv(),
|
||||
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
|
||||
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
|
||||
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
|
||||
sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: deploys'
|
||||
throw e
|
||||
} finally {
|
||||
def buildStatus = currentBuild.result
|
||||
def buildNotSuccess = !SUCCESS.equals(buildStatus)
|
||||
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
|
||||
|
||||
if(buildNotSuccess || lastBuildNotSuccess) {
|
||||
|
||||
stage('Notifiy') {
|
||||
node {
|
||||
final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
|
||||
|
||||
def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}"
|
||||
def details = """The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"""
|
||||
|
||||
emailext (
|
||||
subject: subject,
|
||||
body: details,
|
||||
recipientProviders: RECIPIENTS,
|
||||
to: "$SPRING_SECURITY_TEAM_EMAILS"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
+12
-5
@@ -1,21 +1,28 @@
|
||||
image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
|
||||
|
||||
[NOTE]
|
||||
======
|
||||
This branch of Spring Security has reached its https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions#supported-versions[End of Life], meaning that there are no further maintenance releases or security patches planned.
|
||||
Please migrate to a supported branch as soon as possible.
|
||||
======
|
||||
|
||||
= Spring Security
|
||||
|
||||
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 5.0 requires Spring 5.0 as
|
||||
a minimum and also requires Java 8.
|
||||
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 3.1 requires Spring 3.0.3 as
|
||||
a minimum and also requires Java 5.
|
||||
|
||||
For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects].
|
||||
|
||||
== Code of Conduct
|
||||
Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct]
|
||||
This project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct].
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||
|
||||
== Downloading Artifacts
|
||||
See https://github.com/spring-projects/spring-framework/wiki/Downloading-Spring-artifacts[downloading Spring artifacts] for Maven repository information.
|
||||
|
||||
== Documentation
|
||||
Be sure to read the https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference].
|
||||
Extensive JavaDoc for the Spring Security code is also available in the https://docs.spring.io/spring-security/site/docs/current/api/[Spring Security API Documentation].
|
||||
Extensive JavaDoc for the Spring Security code is also available in the https://docs.spring.io/spring-security/site/docs/current/apidocs/[Spring Security API Documentation].
|
||||
|
||||
== Quick Start
|
||||
We recommend you visit https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference] and read the "Getting Started" page.
|
||||
@@ -56,7 +63,7 @@ Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring
|
||||
https://spring.io/services[Commercial support] is available too.
|
||||
|
||||
== Contributing
|
||||
https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc[contributor guidelines] for details.
|
||||
https://help.github.com/send-pull-requests[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md[contributor guidelines] for details.
|
||||
|
||||
== License
|
||||
Spring Security is Open Source software released under the
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Acl Module build file
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion"
|
||||
|
||||
optional "net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||
|
||||
testCompile "org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context-support:$springVersion",
|
||||
"org.springframework:spring-test:$springVersion"
|
||||
|
||||
testRuntime "org.hsqldb:hsqldb:$hsqlVersion"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,26 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
antlr:antlr:2.7.7
|
||||
ch.qos.logback:logback-classic:1.2.3
|
||||
ch.qos.logback:logback-core:1.2.3
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:29.0-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.puppycrawl.tools:checkstyle:8.32
|
||||
commons-beanutils:commons-beanutils:1.9.4
|
||||
commons-collections:commons-collections:3.2.2
|
||||
info.picocli:picocli:4.2.0
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
io.spring.javaformat:spring-javaformat-checkstyle:0.0.25
|
||||
io.spring.nohttp:nohttp-checkstyle:0.0.3.RELEASE
|
||||
io.spring.nohttp:nohttp:0.0.3.RELEASE
|
||||
net.sf.saxon:Saxon-HE:9.9.1-7
|
||||
org.antlr:antlr4-runtime:4.8-1
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,15 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,15 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,15 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,8 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jacoco:org.jacoco.agent:0.8.2
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,15 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jacoco:org.jacoco.agent:0.8.2
|
||||
org.jacoco:org.jacoco.ant:0.8.2
|
||||
org.jacoco:org.jacoco.core:0.8.2
|
||||
org.jacoco:org.jacoco.report:0.8.2
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.ow2.asm:asm-analysis:6.2.1
|
||||
org.ow2.asm:asm-commons:6.2.1
|
||||
org.ow2.asm:asm-tree:6.2.1
|
||||
org.ow2.asm:asm:6.2.1
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,9 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
net.sf.ehcache:ehcache:2.10.6
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,15 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,15 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,24 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
junit:junit:4.12
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.mockito:mockito-core:3.5.15
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context-support:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-test:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,24 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
junit:junit:4.12
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.mockito:mockito-core:3.5.15
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context-support:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-test:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,7 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
@@ -1,25 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
junit:junit:4.12
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.hsqldb:hsqldb:2.5.1
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.mockito:mockito-core:3.5.15
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context-support:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-test:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,25 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
junit:junit:4.12
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.hsqldb:hsqldb:2.5.1
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.mockito:mockito-core:3.5.15
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context-support:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-test:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
@@ -1,25 +0,0 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.projectreactor:reactor-bom:Dysprosium-SR14
|
||||
junit:junit:4.12
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.hsqldb:hsqldb:2.5.1
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.20
|
||||
org.mockito:mockito-core:3.5.15
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework.data:spring-data-releasetrain:Neumann-SR5
|
||||
org.springframework:spring-aop:5.2.11.RELEASE
|
||||
org.springframework:spring-beans:5.2.11.RELEASE
|
||||
org.springframework:spring-context-support:5.2.11.RELEASE
|
||||
org.springframework:spring-context:5.2.11.RELEASE
|
||||
org.springframework:spring-core:5.2.11.RELEASE
|
||||
org.springframework:spring-expression:5.2.11.RELEASE
|
||||
org.springframework:spring-framework-bom:5.2.11.RELEASE
|
||||
org.springframework:spring-jcl:5.2.11.RELEASE
|
||||
org.springframework:spring-jdbc:5.2.11.RELEASE
|
||||
org.springframework:spring-test:5.2.11.RELEASE
|
||||
org.springframework:spring-tx:5.2.11.RELEASE
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<version>4.2.13.RELEASE</version>
|
||||
<name>spring-security-acl</name>
|
||||
<description>spring-security-acl</description>
|
||||
<url>https://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>https://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.23.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.13.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>2.10.6</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.25</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,18 +0,0 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core')
|
||||
compile 'org.springframework:spring-aop'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-core'
|
||||
compile 'org.springframework:spring-jdbc'
|
||||
compile 'org.springframework:spring-tx'
|
||||
|
||||
optional 'net.sf.ehcache:ehcache'
|
||||
|
||||
testCompile 'org.springframework:spring-beans'
|
||||
testCompile 'org.springframework:spring-context-support'
|
||||
testCompile 'org.springframework:spring-test'
|
||||
|
||||
testRuntime 'org.hsqldb:hsqldb'
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -25,7 +24,6 @@ import java.util.List;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.security.access.AuthorizationServiceException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.vote.AbstractAclVoter;
|
||||
@@ -41,7 +39,6 @@ import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -95,45 +92,59 @@ import org.springframework.util.StringUtils;
|
||||
* <p>
|
||||
* All comparisons and prefixes are case sensitive.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AclEntryVoter extends AbstractAclVoter {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
|
||||
|
||||
private final AclService aclService;
|
||||
|
||||
private final String processConfigAttribute;
|
||||
|
||||
private final List<Permission> requirePermission;
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private AclService aclService;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
private String internalMethod;
|
||||
private String processConfigAttribute;
|
||||
private List<Permission> requirePermission;
|
||||
|
||||
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public AclEntryVoter(AclService aclService, String processConfigAttribute,
|
||||
Permission[] requirePermission) {
|
||||
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||
Assert.notNull(aclService, "An AclService is mandatory");
|
||||
Assert.isTrue(!ObjectUtils.isEmpty(requirePermission), "One or more requirePermission entries is mandatory");
|
||||
|
||||
if ((requirePermission == null) || (requirePermission.length == 0)) {
|
||||
throw new IllegalArgumentException(
|
||||
"One or more requirePermission entries is mandatory");
|
||||
}
|
||||
|
||||
this.aclService = aclService;
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
this.requirePermission = Arrays.asList(requirePermission);
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Optionally specifies a method of the domain object that will be used to obtain a
|
||||
* contained domain object. That contained domain object will be used for the ACL
|
||||
* evaluation. This is useful if a domain object contains a parent that an ACL
|
||||
* evaluation should be targeted for, instead of the child domain object (which
|
||||
* perhaps is being created and as such does not yet have any ACL permissions)
|
||||
*
|
||||
* @return <code>null</code> to use the domain object, or the name of a method (that
|
||||
* requires no arguments) that should be invoked to obtain an <code>Object</code>
|
||||
* which will be the domain object used for ACL evaluation
|
||||
*/
|
||||
protected String getInternalMethod() {
|
||||
return this.internalMethod;
|
||||
return internalMethod;
|
||||
}
|
||||
|
||||
public void setInternalMethod(String internalMethod) {
|
||||
@@ -141,11 +152,13 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
}
|
||||
|
||||
protected String getProcessConfigAttribute() {
|
||||
return this.processConfigAttribute;
|
||||
return processConfigAttribute;
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
|
||||
public void setObjectIdentityRetrievalStrategy(
|
||||
ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
Assert.notNull(objectIdentityRetrievalStrategy,
|
||||
"ObjectIdentityRetrievalStrategy required");
|
||||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
@@ -154,60 +167,103 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
|
||||
return (attribute.getAttribute() != null)
|
||||
&& attribute.getAttribute().equals(getProcessConfigAttribute());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
|
||||
public int vote(Authentication authentication, MethodInvocation object,
|
||||
Collection<ConfigAttribute> attributes) {
|
||||
|
||||
for (ConfigAttribute attr : attributes) {
|
||||
if (!supports(attr)) {
|
||||
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need to make an access decision on this invocation
|
||||
// Attempt to locate the domain object instance to process
|
||||
Object domainObject = getDomainObjectInstance(object);
|
||||
|
||||
// If domain object is null, vote to abstain
|
||||
if (domainObject == null) {
|
||||
logger.debug("Voting to abstain - domainObject is null");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to abstain - domainObject is null");
|
||||
}
|
||||
|
||||
return ACCESS_ABSTAIN;
|
||||
}
|
||||
|
||||
// Evaluate if we are required to use an inner domain object
|
||||
if (StringUtils.hasText(this.internalMethod)) {
|
||||
domainObject = invokeInternalMethod(domainObject);
|
||||
if (StringUtils.hasText(internalMethod)) {
|
||||
try {
|
||||
Class<?> clazz = domainObject.getClass();
|
||||
Method method = clazz.getMethod(internalMethod, new Class[0]);
|
||||
domainObject = method.invoke(domainObject);
|
||||
}
|
||||
catch (NoSuchMethodException nsme) {
|
||||
throw new AuthorizationServiceException("Object of class '"
|
||||
+ domainObject.getClass()
|
||||
+ "' does not provide the requested internalMethod: "
|
||||
+ internalMethod);
|
||||
}
|
||||
catch (IllegalAccessException iae) {
|
||||
logger.debug("IllegalAccessException", iae);
|
||||
|
||||
throw new AuthorizationServiceException(
|
||||
"Problem invoking internalMethod: " + internalMethod
|
||||
+ " for object: " + domainObject);
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
logger.debug("InvocationTargetException", ite);
|
||||
|
||||
throw new AuthorizationServiceException(
|
||||
"Problem invoking internalMethod: " + internalMethod
|
||||
+ " for object: " + domainObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain the OID applicable to the domain object
|
||||
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy
|
||||
.getObjectIdentity(domainObject);
|
||||
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
Acl acl;
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
acl = this.aclService.readAclById(objectIdentity, sids);
|
||||
acl = aclService.readAclById(objectIdentity, sids);
|
||||
}
|
||||
catch (NotFoundException ex) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
catch (NotFoundException nfe) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
}
|
||||
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
|
||||
try {
|
||||
if (acl.isGranted(this.requirePermission, sids, false)) {
|
||||
logger.debug("Voting to grant access");
|
||||
if (acl.isGranted(requirePermission, sids, false)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to grant access");
|
||||
}
|
||||
|
||||
return ACCESS_GRANTED;
|
||||
}
|
||||
logger.debug("Voting to deny access - ACLs returned, but insufficient permissions for this principal");
|
||||
return ACCESS_DENIED;
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to deny access - ACLs returned, but insufficient permissions for this principal");
|
||||
}
|
||||
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
catch (NotFoundException ex) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
catch (NotFoundException nfe) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
}
|
||||
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
@@ -215,27 +271,4 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
// No configuration attribute matched, so abstain
|
||||
return ACCESS_ABSTAIN;
|
||||
}
|
||||
|
||||
private Object invokeInternalMethod(Object domainObject) {
|
||||
try {
|
||||
Class<?> domainObjectType = domainObject.getClass();
|
||||
Method method = domainObjectType.getMethod(this.internalMethod, new Class[0]);
|
||||
return method.invoke(domainObject);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
|
||||
+ "' does not provide the requested internalMethod: " + this.internalMethod);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
logger.debug("IllegalAccessException", ex);
|
||||
throw new AuthorizationServiceException(
|
||||
"Problem invoking internalMethod: " + this.internalMethod + " for object: " + domainObject);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
logger.debug("InvocationTargetException", ex);
|
||||
throw new AuthorizationServiceException(
|
||||
"Problem invoking internalMethod: " + this.internalMethod + " for object: " + domainObject);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-17
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -22,8 +21,6 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.access.PermissionCacheOptimizer;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
||||
@@ -41,42 +38,45 @@ import org.springframework.security.core.Authentication;
|
||||
* @since 3.1
|
||||
*/
|
||||
public class AclPermissionCacheOptimizer implements PermissionCacheOptimizer {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final AclService aclService;
|
||||
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
private ObjectIdentityRetrievalStrategy oidRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
|
||||
public AclPermissionCacheOptimizer(AclService aclService) {
|
||||
this.aclService = aclService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cachePermissionsFor(Authentication authentication, Collection<?> objects) {
|
||||
if (objects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<ObjectIdentity> oidsToCache = new ArrayList<>(objects.size());
|
||||
|
||||
List<ObjectIdentity> oidsToCache = new ArrayList<ObjectIdentity>(objects.size());
|
||||
|
||||
for (Object domainObject : objects) {
|
||||
if (domainObject != null) {
|
||||
ObjectIdentity oid = this.oidRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
oidsToCache.add(oid);
|
||||
if (domainObject == null) {
|
||||
continue;
|
||||
}
|
||||
ObjectIdentity oid = oidRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
oidsToCache.add(oid);
|
||||
}
|
||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
||||
this.logger.debug(LogMessage.of(() -> "Eagerly loading Acls for " + oidsToCache.size() + " objects"));
|
||||
this.aclService.readAclsById(oidsToCache, sids);
|
||||
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Eagerly loading Acls for " + oidsToCache.size() + " objects");
|
||||
}
|
||||
|
||||
aclService.readAclsById(oidsToCache, sids);
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
public void setObjectIdentityRetrievalStrategy(
|
||||
ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
this.oidRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -23,8 +22,6 @@ import java.util.Locale;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
@@ -54,13 +51,9 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final AclService aclService;
|
||||
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
|
||||
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
||||
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
public AclPermissionEvaluator(AclService aclService) {
|
||||
@@ -72,72 +65,101 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
* the ACL configuration. If the domain object is null, returns false (this can always
|
||||
* be overridden using a null check in the expression itself).
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
|
||||
public boolean hasPermission(Authentication authentication, Object domainObject,
|
||||
Object permission) {
|
||||
if (domainObject == null) {
|
||||
return false;
|
||||
}
|
||||
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy
|
||||
.getObjectIdentity(domainObject);
|
||||
|
||||
return checkPermission(authentication, objectIdentity, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId,
|
||||
String targetType, Object permission) {
|
||||
ObjectIdentity objectIdentity = objectIdentityGenerator.createObjectIdentity(
|
||||
targetId, targetType);
|
||||
|
||||
return checkPermission(authentication, objectIdentity, permission);
|
||||
}
|
||||
|
||||
private boolean checkPermission(Authentication authentication, ObjectIdentity oid,
|
||||
Object permission) {
|
||||
ObjectIdentity objectIdentity = this.objectIdentityGenerator.createObjectIdentity(targetId, targetType);
|
||||
return checkPermission(authentication, objectIdentity, permission);
|
||||
}
|
||||
|
||||
private boolean checkPermission(Authentication authentication, ObjectIdentity oid, Object permission) {
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
List<Permission> requiredPermission = resolvePermission(permission);
|
||||
this.logger.debug(LogMessage.of(() -> "Checking permission '" + permission + "' for object '" + oid + "'"));
|
||||
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Checking permission '" + permission + "' for object '" + oid
|
||||
+ "'");
|
||||
}
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
Acl acl = this.aclService.readAclById(oid, sids);
|
||||
Acl acl = aclService.readAclById(oid, sids);
|
||||
|
||||
if (acl.isGranted(requiredPermission, sids, false)) {
|
||||
this.logger.debug("Access is granted");
|
||||
if (debug) {
|
||||
logger.debug("Access is granted");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
this.logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
|
||||
}
|
||||
|
||||
}
|
||||
catch (NotFoundException nfe) {
|
||||
this.logger.debug("Returning false - no ACLs apply for this principal");
|
||||
if (debug) {
|
||||
logger.debug("Returning false - no ACLs apply for this principal");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
List<Permission> resolvePermission(Object permission) {
|
||||
if (permission instanceof Integer) {
|
||||
return Arrays.asList(this.permissionFactory.buildFromMask((Integer) permission));
|
||||
return Arrays.asList(permissionFactory.buildFromMask(((Integer) permission)
|
||||
.intValue()));
|
||||
}
|
||||
|
||||
if (permission instanceof Permission) {
|
||||
return Arrays.asList((Permission) permission);
|
||||
}
|
||||
|
||||
if (permission instanceof Permission[]) {
|
||||
return Arrays.asList((Permission[]) permission);
|
||||
}
|
||||
|
||||
if (permission instanceof String) {
|
||||
String permString = (String) permission;
|
||||
Permission p = buildPermission(permString);
|
||||
Permission p;
|
||||
|
||||
try {
|
||||
p = permissionFactory.buildFromName(permString);
|
||||
}
|
||||
catch (IllegalArgumentException notfound) {
|
||||
p = permissionFactory.buildFromName(permString.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
if (p != null) {
|
||||
return Arrays.asList(p);
|
||||
}
|
||||
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported permission: " + permission);
|
||||
}
|
||||
|
||||
private Permission buildPermission(String permString) {
|
||||
try {
|
||||
return this.permissionFactory.buildFromName(permString);
|
||||
}
|
||||
catch (IllegalArgumentException notfound) {
|
||||
return this.permissionFactory.buildFromName(permString.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
public void setObjectIdentityRetrievalStrategy(
|
||||
ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
@@ -152,5 +174,4 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
public void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||
this.permissionFactory = permissionFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-21
@@ -32,7 +32,6 @@ import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related
|
||||
@@ -41,52 +40,64 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
protected final AclService aclService;
|
||||
|
||||
protected String processConfigAttribute;
|
||||
|
||||
protected Class<?> processDomainObjectClass = Object.class;
|
||||
|
||||
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
|
||||
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
protected String processConfigAttribute;
|
||||
protected final List<Permission> requirePermission;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public AbstractAclProvider(AclService aclService, String processConfigAttribute,
|
||||
List<Permission> requirePermission) {
|
||||
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||
Assert.notNull(aclService, "An AclService is mandatory");
|
||||
Assert.isTrue(!ObjectUtils.isEmpty(requirePermission), "One or more requirePermission entries is mandatory");
|
||||
|
||||
if (requirePermission == null || requirePermission.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"One or more requirePermission entries is mandatory");
|
||||
}
|
||||
|
||||
this.aclService = aclService;
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
this.requirePermission = requirePermission;
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
protected Class<?> getProcessDomainObjectClass() {
|
||||
return this.processDomainObjectClass;
|
||||
return processDomainObjectClass;
|
||||
}
|
||||
|
||||
protected boolean hasPermission(Authentication authentication, Object domainObject) {
|
||||
// Obtain the OID applicable to the domain object
|
||||
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy
|
||||
.getObjectIdentity(domainObject);
|
||||
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
Acl acl = this.aclService.readAclById(objectIdentity, sids);
|
||||
return acl.isGranted(this.requirePermission, sids, false);
|
||||
Acl acl = aclService.readAclById(objectIdentity, sids);
|
||||
|
||||
return acl.isGranted(requirePermission, sids, false);
|
||||
}
|
||||
catch (NotFoundException ex) {
|
||||
catch (NotFoundException ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
|
||||
public void setObjectIdentityRetrievalStrategy(
|
||||
ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
Assert.notNull(objectIdentityRetrievalStrategy,
|
||||
"ObjectIdentityRetrievalStrategy required");
|
||||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
@@ -96,7 +107,8 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
}
|
||||
|
||||
public void setProcessDomainObjectClass(Class<?> processDomainObjectClass) {
|
||||
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
|
||||
Assert.notNull(processDomainObjectClass,
|
||||
"processDomainObjectClass cannot be set to null");
|
||||
this.processDomainObjectClass = processDomainObjectClass;
|
||||
}
|
||||
|
||||
@@ -105,20 +117,19 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return this.processConfigAttribute.equals(attribute.getAttribute());
|
||||
return processConfigAttribute.equals(attribute.getAttribute());
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports any type of class, because it does not query the
|
||||
* presented secure object.
|
||||
*
|
||||
* @param clazz the secure object
|
||||
*
|
||||
* @return always <code>true</code>
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-23
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -21,8 +20,6 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.AuthorizationServiceException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
@@ -63,21 +60,33 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
* @author Paulo Neves
|
||||
*/
|
||||
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
|
||||
public class AclEntryAfterInvocationCollectionFilteringProvider extends
|
||||
AbstractAclProvider {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
|
||||
protected static final Log logger = LogFactory
|
||||
.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService,
|
||||
List<Permission> requirePermission) {
|
||||
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
public Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
|
||||
if (returnedObject == null) {
|
||||
logger.debug("Return object is null, skipping");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -87,34 +96,44 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
|
||||
}
|
||||
|
||||
// Need to process the Collection for this invocation
|
||||
Filterer filterer = getFilterer(returnedObject);
|
||||
Filterer filterer;
|
||||
|
||||
if (returnedObject instanceof Collection) {
|
||||
filterer = new CollectionFilterer((Collection) returnedObject);
|
||||
}
|
||||
else if (returnedObject.getClass().isArray()) {
|
||||
filterer = new ArrayFilterer((Object[]) returnedObject);
|
||||
}
|
||||
else {
|
||||
throw new AuthorizationServiceException(
|
||||
"A Collection or an array (or null) was required as the "
|
||||
+ "returnedObject, but the returnedObject was: "
|
||||
+ returnedObject);
|
||||
}
|
||||
|
||||
// Locate unauthorised Collection elements
|
||||
for (Object domainObject : filterer) {
|
||||
// Ignore nulls or entries which aren't instances of the configured domain
|
||||
// object class
|
||||
if (domainObject == null || !getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
|
||||
if (domainObject == null
|
||||
|| !getProcessDomainObjectClass().isAssignableFrom(
|
||||
domainObject.getClass())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasPermission(authentication, domainObject)) {
|
||||
filterer.remove(domainObject);
|
||||
logger.debug(LogMessage.of(() -> "Principal is NOT authorised for element: " + domainObject));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Principal is NOT authorised for element: "
|
||||
+ domainObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filterer.getFilteredObject();
|
||||
}
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
private Filterer getFilterer(Object returnedObject) {
|
||||
if (returnedObject instanceof Collection) {
|
||||
return new CollectionFilterer((Collection) returnedObject);
|
||||
}
|
||||
if (returnedObject.getClass().isArray()) {
|
||||
return new ArrayFilterer((Object[]) returnedObject);
|
||||
}
|
||||
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
|
||||
+ "returnedObject, but the returnedObject was: " + returnedObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+29
-15
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -21,7 +20,6 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
@@ -60,34 +58,50 @@ import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
* <p>
|
||||
* All comparisons and prefixes are case sensitive.
|
||||
*/
|
||||
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
|
||||
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements
|
||||
MessageSourceAware {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
|
||||
protected static final Log logger = LogFactory
|
||||
.getLog(AclEntryAfterInvocationProvider.class);
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService,
|
||||
List<Permission> requirePermission) {
|
||||
this(aclService, "AFTER_ACL_READ", requirePermission);
|
||||
}
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
|
||||
List<Permission> requirePermission) {
|
||||
public AclEntryAfterInvocationProvider(AclService aclService,
|
||||
String processConfigAttribute, List<Permission> requirePermission) {
|
||||
super(aclService, processConfigAttribute, requirePermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
|
||||
if (returnedObject == null) {
|
||||
// AclManager interface contract prohibits nulls
|
||||
// As they have permission to null/nothing, grant access
|
||||
logger.debug("Return object is null, skipping");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
|
||||
logger.debug("Return object is not applicable for this provider, skipping");
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@@ -95,24 +109,24 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need to make an access decision on this invocation
|
||||
|
||||
if (hasPermission(authentication, returnedObject)) {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
logger.debug("Denying access");
|
||||
throw new AccessDeniedException(this.messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
|
||||
new Object[] { authentication.getName(), returnedObject },
|
||||
|
||||
throw new AccessDeniedException(messages.getMessage(
|
||||
"AclEntryAfterInvocationProvider.noPermission", new Object[] {
|
||||
authentication.getName(), returnedObject },
|
||||
"Authentication {0} has NO permissions to the domain object {1}"));
|
||||
}
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-38
@@ -25,8 +25,6 @@ import java.util.Set;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
|
||||
/**
|
||||
* A filter used to filter arrays.
|
||||
*
|
||||
@@ -34,70 +32,91 @@ import org.springframework.core.log.LogMessage;
|
||||
* @author Paulo Neves
|
||||
*/
|
||||
class ArrayFilterer<T> implements Filterer<T> {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);
|
||||
|
||||
private final Set<T> removeList;
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final Set<T> removeList;
|
||||
private final T[] list;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
ArrayFilterer(T[] list) {
|
||||
this.list = list;
|
||||
|
||||
// Collect the removed objects to a HashSet so that
|
||||
// it is fast to lookup them when a filtered array
|
||||
// is constructed.
|
||||
this.removeList = new HashSet<>();
|
||||
removeList = new HashSet<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#getFilteredObject()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T[] getFilteredObject() {
|
||||
// Recreate an array of same type and filter the removed objects.
|
||||
int originalSize = this.list.length;
|
||||
int sizeOfResultingList = originalSize - this.removeList.size();
|
||||
T[] filtered = (T[]) Array.newInstance(this.list.getClass().getComponentType(), sizeOfResultingList);
|
||||
for (int i = 0, j = 0; i < this.list.length; i++) {
|
||||
T object = this.list[i];
|
||||
if (!this.removeList.contains(object)) {
|
||||
int originalSize = list.length;
|
||||
int sizeOfResultingList = originalSize - removeList.size();
|
||||
T[] filtered = (T[]) Array.newInstance(list.getClass().getComponentType(),
|
||||
sizeOfResultingList);
|
||||
|
||||
for (int i = 0, j = 0; i < list.length; i++) {
|
||||
T object = list[i];
|
||||
|
||||
if (!removeList.contains(object)) {
|
||||
filtered[j] = object;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
logger.debug(LogMessage.of(() -> "Original array contained " + originalSize + " elements; now contains "
|
||||
+ sizeOfResultingList + " elements"));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Original array contained " + originalSize
|
||||
+ " elements; now contains " + sizeOfResultingList + " elements");
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
return new ArrayFiltererIterator();
|
||||
}
|
||||
return new Iterator<T>() {
|
||||
private int index = 0;
|
||||
|
||||
@Override
|
||||
public void remove(T object) {
|
||||
this.removeList.add(object);
|
||||
public boolean hasNext() {
|
||||
return index < list.length;
|
||||
}
|
||||
|
||||
public T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return list[index++];
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator for {@link ArrayFilterer} elements.
|
||||
*
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#remove(java.lang.Object)
|
||||
*/
|
||||
private class ArrayFiltererIterator implements Iterator<T> {
|
||||
|
||||
private int index = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.index < ArrayFilterer.this.list.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
if (hasNext()) {
|
||||
return ArrayFilterer.this.list[this.index++];
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
public void remove(T object) {
|
||||
removeList.add(object);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-18
@@ -16,16 +16,14 @@
|
||||
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.log.LogMessage;
|
||||
|
||||
/**
|
||||
* A filter used to filter Collections.
|
||||
*
|
||||
@@ -33,15 +31,24 @@ import org.springframework.core.log.LogMessage;
|
||||
* @author Paulo Neves
|
||||
*/
|
||||
class CollectionFilterer<T> implements Filterer<T> {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final Collection<T> collection;
|
||||
|
||||
private final Set<T> removeList;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
CollectionFilterer(Collection<T> collection) {
|
||||
this.collection = collection;
|
||||
|
||||
// We create a Set of objects to be removed from the Collection,
|
||||
// as ConcurrentModificationException prevents removal during
|
||||
// iteration, and making a new Collection to be returned is
|
||||
@@ -49,30 +56,47 @@ class CollectionFilterer<T> implements Filterer<T> {
|
||||
// to the method may not necessarily be re-constructable (as
|
||||
// the Collection(collection) constructor is not guaranteed and
|
||||
// manually adding may lose sort order or other capabilities)
|
||||
this.removeList = new HashSet<>();
|
||||
removeList = new HashSet<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#getFilteredObject()
|
||||
*/
|
||||
public Object getFilteredObject() {
|
||||
// Now the Iterator has ended, remove Objects from Collection
|
||||
Iterator<T> removeIter = this.removeList.iterator();
|
||||
int originalSize = this.collection.size();
|
||||
Iterator<T> removeIter = removeList.iterator();
|
||||
|
||||
int originalSize = collection.size();
|
||||
|
||||
while (removeIter.hasNext()) {
|
||||
this.collection.remove(removeIter.next());
|
||||
collection.remove(removeIter.next());
|
||||
}
|
||||
logger.debug(LogMessage.of(() -> "Original collection contained " + originalSize + " elements; now contains "
|
||||
+ this.collection.size() + " elements"));
|
||||
return this.collection;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Original collection contained " + originalSize
|
||||
+ " elements; now contains " + collection.size() + " elements");
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
|
||||
*/
|
||||
public Iterator<T> iterator() {
|
||||
return this.collection.iterator();
|
||||
return collection.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
*
|
||||
* @see org.springframework.security.acls.afterinvocation.Filterer#remove(java.lang.Object)
|
||||
*/
|
||||
public void remove(T object) {
|
||||
this.removeList.add(object);
|
||||
removeList.add(object);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,24 +25,27 @@ import java.util.Iterator;
|
||||
* @author Paulo Neves
|
||||
*/
|
||||
interface Filterer<T> extends Iterable<T> {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Gets the filtered collection or array.
|
||||
*
|
||||
* @return the filtered collection or array
|
||||
*/
|
||||
Object getFilteredObject();
|
||||
|
||||
/**
|
||||
* Returns an iterator over the filtered collection or array.
|
||||
*
|
||||
* @return an Iterator
|
||||
*/
|
||||
@Override
|
||||
Iterator<T> iterator();
|
||||
|
||||
/**
|
||||
* Removes the given object from the resulting list.
|
||||
*
|
||||
* @param object the object to be removed
|
||||
*/
|
||||
void remove(T object);
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -13,9 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* After-invocation providers for collection and array filtering. Consider using a
|
||||
* {@code PostFilter} annotation in preference.
|
||||
* After-invocation providers for collection and array filtering. Consider using a {@code PostFilter} annotation in
|
||||
* preference.
|
||||
*/
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
|
||||
|
||||
+30
-25
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
@@ -26,13 +25,18 @@ import org.springframework.security.acls.model.Permission;
|
||||
*/
|
||||
public abstract class AbstractPermission implements Permission {
|
||||
|
||||
protected final char code;
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
protected final char code;
|
||||
protected int mask;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
/**
|
||||
* Sets the permission mask and uses the '*' character to represent active bits when
|
||||
* represented as a bit pattern string.
|
||||
*
|
||||
* @param mask the integer bit mask for the permission
|
||||
*/
|
||||
protected AbstractPermission(int mask) {
|
||||
@@ -42,6 +46,7 @@ public abstract class AbstractPermission implements Permission {
|
||||
|
||||
/**
|
||||
* Sets the permission mask and uses the specified character for active bits.
|
||||
*
|
||||
* @param mask the integer bit mask for the permission
|
||||
* @param code the character to print for each active bit in the mask (see
|
||||
* {@link Permission#getPattern()})
|
||||
@@ -51,36 +56,36 @@ public abstract class AbstractPermission implements Permission {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public final boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Permission)) {
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
Permission other = (Permission) obj;
|
||||
return (this.mask == other.getMask());
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public final int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return AclFormattingUtils.printBinary(mask, code);
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + this.mask + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getMask() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPattern() {
|
||||
return AclFormattingUtils.printBinary(this.mask, this.code);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+45
-52
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,41 +13,42 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An immutable default implementation of <code>AccessControlEntry</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
|
||||
public class AccessControlEntryImpl implements AccessControlEntry,
|
||||
AuditableAccessControlEntry {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final Acl acl;
|
||||
|
||||
private Permission permission;
|
||||
|
||||
private final Serializable id;
|
||||
|
||||
private final Sid sid;
|
||||
|
||||
private boolean auditFailure = false;
|
||||
|
||||
private boolean auditSuccess = false;
|
||||
|
||||
private final boolean granting;
|
||||
|
||||
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||
boolean auditSuccess, boolean auditFailure) {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid,
|
||||
Permission permission, boolean granting, boolean auditSuccess,
|
||||
boolean auditFailure) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
Assert.notNull(permission, "Permission required");
|
||||
@@ -60,106 +61,99 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
this.auditFailure = auditFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (!(arg0 instanceof AccessControlEntryImpl)) {
|
||||
return false;
|
||||
}
|
||||
AccessControlEntryImpl other = (AccessControlEntryImpl) arg0;
|
||||
|
||||
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
|
||||
|
||||
if (this.acl == null) {
|
||||
if (other.getAcl() != null) {
|
||||
if (rhs.getAcl() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
}
|
||||
else {
|
||||
// this.acl is non-null
|
||||
if (other.getAcl() == null) {
|
||||
if (rhs.getAcl() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.acl and rhs.acl are non-null, so do a comparison
|
||||
if (this.acl.getObjectIdentity() == null) {
|
||||
if (other.acl.getObjectIdentity() != null) {
|
||||
if (rhs.acl.getObjectIdentity() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
}
|
||||
else {
|
||||
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
|
||||
if (!this.acl.getObjectIdentity().equals(other.getAcl().getObjectIdentity())) {
|
||||
if (!this.acl.getObjectIdentity()
|
||||
.equals(rhs.getAcl().getObjectIdentity())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.id == null) {
|
||||
if (other.id != null) {
|
||||
if (rhs.id != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.id and rhs.id are null and thus equal
|
||||
}
|
||||
else {
|
||||
// this.id is non-null
|
||||
if (other.id == null) {
|
||||
if (rhs.id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.id and rhs.id are non-null
|
||||
if (!this.id.equals(other.id)) {
|
||||
if (!this.id.equals(rhs.id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((this.auditFailure != other.isAuditFailure()) || (this.auditSuccess != other.isAuditSuccess())
|
||||
|| (this.granting != other.isGranting()) || !this.permission.equals(other.getPermission())
|
||||
|| !this.sid.equals(other.getSid())) {
|
||||
|
||||
if ((this.auditFailure != rhs.isAuditFailure())
|
||||
|| (this.auditSuccess != rhs.isAuditSuccess())
|
||||
|| (this.granting != rhs.isGranting())
|
||||
|| !this.permission.equals(rhs.getPermission())
|
||||
|| !this.sid.equals(rhs.getSid())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.permission.hashCode();
|
||||
result = 31 * result + ((this.id != null) ? this.id.hashCode() : 0);
|
||||
result = 31 * result + (this.sid.hashCode());
|
||||
result = 31 * result + (this.auditFailure ? 1 : 0);
|
||||
result = 31 * result + (this.auditSuccess ? 1 : 0);
|
||||
result = 31 * result + (this.granting ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl getAcl() {
|
||||
return this.acl;
|
||||
return acl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
return this.id;
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission getPermission() {
|
||||
return this.permission;
|
||||
return permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sid getSid() {
|
||||
return this.sid;
|
||||
return sid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuditFailure() {
|
||||
return this.auditFailure;
|
||||
return auditFailure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuditSuccess() {
|
||||
return this.auditSuccess;
|
||||
return auditSuccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGranting() {
|
||||
return this.granting;
|
||||
return granting;
|
||||
}
|
||||
|
||||
void setAuditFailure(boolean auditFailure) {
|
||||
@@ -175,7 +169,6 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("AccessControlEntryImpl[");
|
||||
@@ -186,7 +179,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
|
||||
sb.append("auditFailure: ").append(this.auditFailure);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -25,13 +25,15 @@ import org.springframework.security.acls.model.Acl;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AclAuthorizationStrategy {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
int CHANGE_OWNERSHIP = 0;
|
||||
|
||||
int CHANGE_AUDITING = 1;
|
||||
|
||||
int CHANGE_GENERAL = 2;
|
||||
|
||||
void securityCheck(Acl acl, int changeType);
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
void securityCheck(Acl acl, int changeType);
|
||||
}
|
||||
|
||||
+44
-33
@@ -16,10 +16,6 @@
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
@@ -30,6 +26,10 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link AclAuthorizationStrategy}.
|
||||
* <p>
|
||||
@@ -45,18 +45,21 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final GrantedAuthority gaGeneralChanges;
|
||||
|
||||
private final GrantedAuthority gaModifyAuditing;
|
||||
|
||||
private final GrantedAuthority gaTakeOwnership;
|
||||
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor. The only mandatory parameter relates to the system-wide
|
||||
* {@link GrantedAuthority} instances that can be held to always permit ACL changes.
|
||||
*
|
||||
* @param auths the <code>GrantedAuthority</code>s that have special permissions
|
||||
* (index 0 is the authority needed to change ownership, index 1 is the authority
|
||||
* needed to modify auditing details, index 2 is the authority needed to change other
|
||||
@@ -68,33 +71,53 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Assert.isTrue(auths != null && (auths.length == 3 || auths.length == 1),
|
||||
"One or three GrantedAuthority instances required");
|
||||
if (auths.length == 3) {
|
||||
this.gaTakeOwnership = auths[0];
|
||||
this.gaModifyAuditing = auths[1];
|
||||
this.gaGeneralChanges = auths[2];
|
||||
gaTakeOwnership = auths[0];
|
||||
gaModifyAuditing = auths[1];
|
||||
gaGeneralChanges = auths[2];
|
||||
}
|
||||
else {
|
||||
this.gaTakeOwnership = auths[0];
|
||||
this.gaModifyAuditing = auths[0];
|
||||
this.gaGeneralChanges = auths[0];
|
||||
gaTakeOwnership = gaModifyAuditing = gaGeneralChanges = auths[0];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void securityCheck(Acl acl, int changeType) {
|
||||
if ((SecurityContextHolder.getContext() == null)
|
||||
|| (SecurityContextHolder.getContext().getAuthentication() == null)
|
||||
|| !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
|
||||
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
|
||||
|| !SecurityContextHolder.getContext().getAuthentication()
|
||||
.isAuthenticated()) {
|
||||
throw new AccessDeniedException(
|
||||
"Authenticated principal required to operate with ACLs");
|
||||
}
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
|
||||
// Check if authorized by virtue of ACL ownership
|
||||
Sid currentUser = createCurrentUser(authentication);
|
||||
|
||||
if (currentUser.equals(acl.getOwner())
|
||||
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not authorized by ACL ownership; try via adminstrative permissions
|
||||
GrantedAuthority requiredAuthority = getRequiredAuthority(changeType);
|
||||
GrantedAuthority requiredAuthority;
|
||||
|
||||
if (changeType == CHANGE_AUDITING) {
|
||||
requiredAuthority = this.gaModifyAuditing;
|
||||
}
|
||||
else if (changeType == CHANGE_GENERAL) {
|
||||
requiredAuthority = this.gaGeneralChanges;
|
||||
}
|
||||
else if (changeType == CHANGE_OWNERSHIP) {
|
||||
requiredAuthority = this.gaTakeOwnership;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown change type");
|
||||
}
|
||||
|
||||
// Iterate this principal's authorities to determine right
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
|
||||
@@ -103,7 +126,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
}
|
||||
|
||||
// Try to get permission via ACEs within the ACL
|
||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
if (acl.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), sids, false)) {
|
||||
return;
|
||||
}
|
||||
@@ -112,21 +136,9 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
"Principal does not have required ACL permissions to perform requested operation");
|
||||
}
|
||||
|
||||
private GrantedAuthority getRequiredAuthority(int changeType) {
|
||||
if (changeType == CHANGE_AUDITING) {
|
||||
return this.gaModifyAuditing;
|
||||
}
|
||||
if (changeType == CHANGE_GENERAL) {
|
||||
return this.gaGeneralChanges;
|
||||
}
|
||||
if (changeType == CHANGE_OWNERSHIP) {
|
||||
return this.gaTakeOwnership;
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown change type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a principal-like sid from the authentication information.
|
||||
*
|
||||
* @param authentication the authentication information that can provide principal and
|
||||
* thus the sid's id will be dependant on the value inside
|
||||
* @return a sid with the ID taken from the authentication information
|
||||
@@ -139,5 +151,4 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
@@ -31,7 +30,9 @@ public abstract class AclFormattingUtils {
|
||||
Assert.notNull(removeBits, "Bits To Remove string required");
|
||||
Assert.isTrue(original.length() == removeBits.length(),
|
||||
"Original and Bits To Remove strings must be identical length");
|
||||
|
||||
char[] replacement = new char[original.length()];
|
||||
|
||||
for (int i = 0; i < original.length(); i++) {
|
||||
if (removeBits.charAt(i) == Permission.RESERVED_OFF) {
|
||||
replacement[i] = original.charAt(i);
|
||||
@@ -40,6 +41,7 @@ public abstract class AclFormattingUtils {
|
||||
replacement[i] = Permission.RESERVED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
return new String(replacement);
|
||||
}
|
||||
|
||||
@@ -48,7 +50,9 @@ public abstract class AclFormattingUtils {
|
||||
Assert.notNull(extraBits, "Extra Bits string required");
|
||||
Assert.isTrue(original.length() == extraBits.length(),
|
||||
"Original and Extra Bits strings must be identical length");
|
||||
|
||||
char[] replacement = new char[extraBits.length()];
|
||||
|
||||
for (int i = 0; i < extraBits.length(); i++) {
|
||||
if (extraBits.charAt(i) == Permission.RESERVED_OFF) {
|
||||
replacement[i] = original.charAt(i);
|
||||
@@ -57,6 +61,7 @@ public abstract class AclFormattingUtils {
|
||||
replacement[i] = extraBits.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return new String(replacement);
|
||||
}
|
||||
|
||||
@@ -65,7 +70,9 @@ public abstract class AclFormattingUtils {
|
||||
* bit being denoted by character '*'.
|
||||
* <p>
|
||||
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
||||
*
|
||||
* @param i the integer bit mask to print the active bits for
|
||||
*
|
||||
* @return a 32-character representation of the bit mask
|
||||
*/
|
||||
public static String printBinary(int i) {
|
||||
@@ -77,23 +84,29 @@ public abstract class AclFormattingUtils {
|
||||
* bit being denoted by the passed character.
|
||||
* <p>
|
||||
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
||||
*
|
||||
* @param mask the integer bit mask to print the active bits for
|
||||
* @param code the character to print when an active bit is detected
|
||||
*
|
||||
* @return a 32-character representation of the bit mask
|
||||
*/
|
||||
public static String printBinary(int mask, char code) {
|
||||
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_ON),
|
||||
() -> Permission.RESERVED_ON + " is a reserved character code");
|
||||
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_OFF),
|
||||
() -> Permission.RESERVED_OFF + " is a reserved character code");
|
||||
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, code);
|
||||
Assert.doesNotContain(Character.toString(code),
|
||||
Character.toString(Permission.RESERVED_ON), Permission.RESERVED_ON
|
||||
+ " is a reserved character code");
|
||||
Assert.doesNotContain(Character.toString(code),
|
||||
Character.toString(Permission.RESERVED_OFF), Permission.RESERVED_OFF
|
||||
+ " is a reserved character code");
|
||||
|
||||
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF)
|
||||
.replace(Permission.RESERVED_ON, code);
|
||||
}
|
||||
|
||||
private static String printBinary(int i, char on, char off) {
|
||||
String s = Integer.toBinaryString(i);
|
||||
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
|
||||
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
|
||||
|
||||
return temp2.replace('0', off).replace('1', on);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -32,7 +31,6 @@ import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.UnloadedSidException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of <code>Acl</code>.
|
||||
@@ -40,38 +38,35 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private Acl parentAcl;
|
||||
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
private transient PermissionGrantingStrategy permissionGrantingStrategy;
|
||||
|
||||
private final List<AccessControlEntry> aces = new ArrayList<>();
|
||||
|
||||
private final List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
|
||||
private ObjectIdentity objectIdentity;
|
||||
|
||||
private Serializable id;
|
||||
|
||||
// OwnershipAcl
|
||||
private Sid owner;
|
||||
|
||||
// includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||
private List<Sid> loadedSids = null;
|
||||
|
||||
private Sid owner; // OwnershipAcl
|
||||
private List<Sid> loadedSids = null; // includes all SIDs the WHERE clause covered,
|
||||
// even if there was no ACE for a SID
|
||||
private boolean entriesInheriting = true;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Minimal constructor, which should be used
|
||||
* {@link org.springframework.security.acls.model.MutableAclService#createAcl(ObjectIdentity)}
|
||||
* .
|
||||
*
|
||||
* @param objectIdentity the object identity this ACL relates to (required)
|
||||
* @param id the primary key assigned to this ACL (required)
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
* @param auditLogger audit logger (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
AuditLogger auditLogger) {
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
@@ -79,12 +74,14 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
this.objectIdentity = objectIdentity;
|
||||
this.id = id;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
|
||||
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(
|
||||
auditLogger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor, which should be used by persistence tools that do not provide
|
||||
* field-level access features.
|
||||
*
|
||||
* @param objectIdentity the object identity this ACL relates to
|
||||
* @param id the primary key assigned to this ACL
|
||||
* @param aclAuthorizationStrategy authorization strategy
|
||||
@@ -96,13 +93,15 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* @param entriesInheriting if ACEs from the parent should inherit into this ACL
|
||||
* @param owner the owner (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting,
|
||||
Sid owner) {
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
PermissionGrantingStrategy grantingStrategy, Acl parentAcl,
|
||||
List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(owner, "Owner required");
|
||||
|
||||
this.objectIdentity = objectIdentity;
|
||||
this.id = id;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
@@ -121,11 +120,15 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
private AclImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void deleteAce(int aceIndex) throws NotFoundException {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
synchronized (this.aces) {
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.remove(aceIndex);
|
||||
}
|
||||
}
|
||||
@@ -135,70 +138,73 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
||||
}
|
||||
if (aceIndex >= this.aces.size()) {
|
||||
throw new NotFoundException("aceIndex must refer to an index of the AccessControlEntry list. "
|
||||
+ "List size is " + this.aces.size() + ", index was " + aceIndex);
|
||||
throw new NotFoundException(
|
||||
"aceIndex must refer to an index of the AccessControlEntry list. "
|
||||
+ "List size is " + aces.size() + ", index was " + aceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid,
|
||||
boolean granting) throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.notNull(permission, "Permission required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (atIndexLocation < 0) {
|
||||
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
|
||||
throw new NotFoundException(
|
||||
"atIndexLocation must be greater than or equal to zero");
|
||||
}
|
||||
if (atIndexLocation > this.aces.size()) {
|
||||
throw new NotFoundException(
|
||||
"atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
|
||||
}
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
|
||||
synchronized (this.aces) {
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid,
|
||||
permission, granting, false, false);
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.add(atIndexLocation, ace);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessControlEntry> getEntries() {
|
||||
// Can safely return AccessControlEntry directly, as they're immutable outside the
|
||||
// ACL package
|
||||
return new ArrayList<>(this.aces);
|
||||
return new ArrayList<AccessControlEntry>(aces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectIdentity getObjectIdentity() {
|
||||
return this.objectIdentity;
|
||||
return objectIdentity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEntriesInheriting() {
|
||||
return this.entriesInheriting;
|
||||
return entriesInheriting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the {@link PermissionGrantingStrategy}.
|
||||
*
|
||||
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the
|
||||
* ACL was only loaded for a subset of SIDs
|
||||
* @see DefaultPermissionGrantingStrategy
|
||||
*/
|
||||
@Override
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids,
|
||||
boolean administrativeMode) throws NotFoundException, UnloadedSidException {
|
||||
Assert.notEmpty(permission, "Permissions required");
|
||||
Assert.notEmpty(sids, "SIDs required");
|
||||
|
||||
if (!this.isSidLoaded(sids)) {
|
||||
throw new UnloadedSidException("ACL was not loaded for one or more SID");
|
||||
}
|
||||
return this.permissionGrantingStrategy.isGranted(this, permission, sids, administrativeMode);
|
||||
|
||||
return permissionGrantingStrategy.isGranted(this, permission, sids,
|
||||
administrativeMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
// If loadedSides is null, this indicates all SIDs were loaded
|
||||
// Also return true if the caller didn't specify a SID to find
|
||||
@@ -209,13 +215,16 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
// This ACL applies to a SID subset only. Iterate to check it applies.
|
||||
for (Sid sid : sids) {
|
||||
boolean found = false;
|
||||
for (Sid loadedSid : this.loadedSids) {
|
||||
|
||||
for (Sid loadedSid : loadedSids) {
|
||||
if (sid.equals(loadedSid)) {
|
||||
// this SID is OK
|
||||
found = true;
|
||||
|
||||
break; // out of loadedSids for loop
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
@@ -224,116 +233,131 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntriesInheriting(boolean entriesInheriting) {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
this.entriesInheriting = entriesInheriting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(Sid newOwner) {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.notNull(newOwner, "Owner required");
|
||||
this.owner = newOwner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sid getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(Acl newParent) {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.isTrue(newParent == null || !newParent.equals(this),
|
||||
"Cannot be the parent of yourself");
|
||||
this.parentAcl = newParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl getParentAcl() {
|
||||
return this.parentAcl;
|
||||
return parentAcl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAce(int aceIndex, Permission permission) throws NotFoundException {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
synchronized (this.aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) this.aces.get(aceIndex);
|
||||
|
||||
synchronized (aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||
ace.setPermission(permission);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
|
||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
aclAuthorizationStrategy.securityCheck(this,
|
||||
AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
synchronized (this.aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) this.aces.get(aceIndex);
|
||||
|
||||
synchronized (aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||
ace.setAuditSuccess(auditSuccess);
|
||||
ace.setAuditFailure(auditFailure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
if (obj instanceof AclImpl) {
|
||||
AclImpl rhs = (AclImpl) obj;
|
||||
if (this.aces.equals(rhs.aces)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null)
|
||||
|| (this.parentAcl != null && this.parentAcl
|
||||
.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null)
|
||||
|| (this.objectIdentity != null && this.objectIdentity
|
||||
.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null)
|
||||
|| (this.id != null && this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null)
|
||||
|| (this.owner != null && this.owner
|
||||
.equals(rhs.owner))) {
|
||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||
return true;
|
||||
}
|
||||
if (this.loadedSids != null
|
||||
&& (this.loadedSids.size() == rhs.loadedSids
|
||||
.size())) {
|
||||
for (int i = 0; i < this.loadedSids.size(); i++) {
|
||||
if (!this.loadedSids.get(i).equals(
|
||||
rhs.loadedSids.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj == null || !(obj instanceof AclImpl)) {
|
||||
return false;
|
||||
}
|
||||
AclImpl other = (AclImpl) obj;
|
||||
boolean result = true;
|
||||
result = result && this.aces.equals(other.aces);
|
||||
result = result && ObjectUtils.nullSafeEquals(this.parentAcl, other.parentAcl);
|
||||
result = result && ObjectUtils.nullSafeEquals(this.objectIdentity, other.objectIdentity);
|
||||
result = result && ObjectUtils.nullSafeEquals(this.id, other.id);
|
||||
result = result && ObjectUtils.nullSafeEquals(this.owner, other.owner);
|
||||
result = result && this.entriesInheriting == other.entriesInheriting;
|
||||
result = result && ObjectUtils.nullSafeEquals(this.loadedSids, other.loadedSids);
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (this.parentAcl != null) ? this.parentAcl.hashCode() : 0;
|
||||
result = 31 * result + this.aclAuthorizationStrategy.hashCode();
|
||||
result = 31 * result
|
||||
+ ((this.permissionGrantingStrategy != null) ? this.permissionGrantingStrategy.hashCode() : 0);
|
||||
result = 31 * result + ((this.aces != null) ? this.aces.hashCode() : 0);
|
||||
result = 31 * result + this.objectIdentity.hashCode();
|
||||
result = 31 * result + this.id.hashCode();
|
||||
result = 31 * result + ((this.owner != null) ? this.owner.hashCode() : 0);
|
||||
result = 31 * result + ((this.loadedSids != null) ? this.loadedSids.hashCode() : 0);
|
||||
result = 31 * result + (this.entriesInheriting ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("AclImpl[");
|
||||
sb.append("id: ").append(this.id).append("; ");
|
||||
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
||||
sb.append("owner: ").append(this.owner).append("; ");
|
||||
|
||||
int count = 0;
|
||||
for (AccessControlEntry ace : this.aces) {
|
||||
|
||||
for (AccessControlEntry ace : aces) {
|
||||
count++;
|
||||
|
||||
if (count == 1) {
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
sb.append(ace).append("\n");
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
sb.append("no ACEs; ");
|
||||
}
|
||||
|
||||
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
|
||||
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
|
||||
sb.append("parent: ").append(
|
||||
(this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity()
|
||||
.toString());
|
||||
sb.append("; ");
|
||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy)
|
||||
.append("; ");
|
||||
sb.append("permissionGrantingStrategy: ").append(this.permissionGrantingStrategy);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
@@ -22,9 +21,11 @@ import org.springframework.security.acls.model.AccessControlEntry;
|
||||
* Used by <code>AclImpl</code> to log audit events.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public interface AuditLogger {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
void logIfNeeded(boolean granted, AccessControlEntry ace);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
@@ -29,15 +28,10 @@ import org.springframework.security.acls.model.Permission;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class BasePermission extends AbstractPermission {
|
||||
|
||||
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
|
||||
|
||||
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
|
||||
|
||||
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
|
||||
|
||||
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
|
||||
|
||||
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
||||
|
||||
protected BasePermission(int mask) {
|
||||
@@ -47,5 +41,4 @@ public class BasePermission extends AbstractPermission {
|
||||
protected BasePermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -26,12 +26,15 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ConsoleAuditLogger implements AuditLogger {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@Override
|
||||
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
|
||||
Assert.notNull(ace, "AccessControlEntry required");
|
||||
|
||||
if (ace instanceof AuditableAccessControlEntry) {
|
||||
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
|
||||
|
||||
if (granted && auditableAce.isAuditSuccess()) {
|
||||
System.out.println("GRANTED due to ACE: " + ace);
|
||||
}
|
||||
@@ -40,5 +43,4 @@ public class ConsoleAuditLogger implements AuditLogger {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
@@ -38,23 +37,27 @@ public class CumulativePermission extends AbstractPermission {
|
||||
|
||||
public CumulativePermission clear(Permission permission) {
|
||||
this.mask &= ~permission.getMask();
|
||||
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
|
||||
this.pattern = AclFormattingUtils.demergePatterns(this.pattern,
|
||||
permission.getPattern());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CumulativePermission clear() {
|
||||
this.mask = 0;
|
||||
this.pattern = THIRTY_TWO_RESERVED_OFF;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CumulativePermission set(Permission permission) {
|
||||
this.mask |= permission.getMask();
|
||||
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
|
||||
this.pattern = AclFormattingUtils.mergePatterns(this.pattern,
|
||||
permission.getPattern());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
+40
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -39,10 +38,8 @@ import org.springframework.util.Assert;
|
||||
* @since 2.0.3
|
||||
*/
|
||||
public class DefaultPermissionFactory implements PermissionFactory {
|
||||
|
||||
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<>();
|
||||
|
||||
private final Map<String, Permission> registeredPermissionsByName = new HashMap<>();
|
||||
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<Integer, Permission>();
|
||||
private final Map<String, Permission> registeredPermissionsByName = new HashMap<String, Permission>();
|
||||
|
||||
/**
|
||||
* Registers the <tt>Permission</tt> fields from the <tt>BasePermission</tt> class.
|
||||
@@ -60,6 +57,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
|
||||
/**
|
||||
* Registers a map of named <tt>Permission</tt> instances.
|
||||
*
|
||||
* @param namedPermissions the map of <tt>Permission</tt>s, keyed by name.
|
||||
*/
|
||||
public DefaultPermissionFactory(Map<String, ? extends Permission> namedPermissions) {
|
||||
@@ -73,22 +71,27 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
* <p>
|
||||
* These permissions will be registered under the name of the field. See
|
||||
* {@link BasePermission} for an example.
|
||||
*
|
||||
* @param clazz a {@link Permission} class with public static fields to register
|
||||
*/
|
||||
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
|
||||
Assert.notNull(clazz, "Class required");
|
||||
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
Object fieldValue = field.get(null);
|
||||
|
||||
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||
// Found a Permission static field
|
||||
Permission perm = (Permission) fieldValue;
|
||||
String permissionName = field.getName();
|
||||
|
||||
registerPermission(perm, permissionName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,57 +99,69 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
protected void registerPermission(Permission perm, String permissionName) {
|
||||
Assert.notNull(perm, "Permission required");
|
||||
Assert.hasText(permissionName, "Permission name required");
|
||||
Integer mask = perm.getMask();
|
||||
|
||||
Integer mask = Integer.valueOf(perm.getMask());
|
||||
|
||||
// Ensure no existing Permission uses this integer or code
|
||||
Assert.isTrue(!this.registeredPermissionsByInteger.containsKey(mask),
|
||||
() -> "An existing Permission already provides mask " + mask);
|
||||
Assert.isTrue(!this.registeredPermissionsByName.containsKey(permissionName),
|
||||
() -> "An existing Permission already provides name '" + permissionName + "'");
|
||||
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask),
|
||||
"An existing Permission already provides mask " + mask);
|
||||
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName),
|
||||
"An existing Permission already provides name '" + permissionName + "'");
|
||||
|
||||
// Register the new Permission
|
||||
this.registeredPermissionsByInteger.put(mask, perm);
|
||||
this.registeredPermissionsByName.put(permissionName, perm);
|
||||
registeredPermissionsByInteger.put(mask, perm);
|
||||
registeredPermissionsByName.put(permissionName, perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission buildFromMask(int mask) {
|
||||
if (this.registeredPermissionsByInteger.containsKey(mask)) {
|
||||
if (registeredPermissionsByInteger.containsKey(Integer.valueOf(mask))) {
|
||||
// The requested mask has an exact match against a statically-defined
|
||||
// Permission, so return it
|
||||
return this.registeredPermissionsByInteger.get(mask);
|
||||
return registeredPermissionsByInteger.get(Integer.valueOf(mask));
|
||||
}
|
||||
|
||||
// To get this far, we have to use a CumulativePermission
|
||||
CumulativePermission permission = new CumulativePermission();
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int permissionToCheck = 1 << i;
|
||||
|
||||
if ((mask & permissionToCheck) == permissionToCheck) {
|
||||
Permission p = this.registeredPermissionsByInteger.get(permissionToCheck);
|
||||
Assert.state(p != null,
|
||||
() -> "Mask '" + permissionToCheck + "' does not have a corresponding static Permission");
|
||||
Permission p = registeredPermissionsByInteger.get(Integer
|
||||
.valueOf(permissionToCheck));
|
||||
|
||||
if (p == null) {
|
||||
throw new IllegalStateException("Mask '" + permissionToCheck
|
||||
+ "' does not have a corresponding static Permission");
|
||||
}
|
||||
permission.set(p);
|
||||
}
|
||||
}
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission buildFromName(String name) {
|
||||
Permission p = this.registeredPermissionsByName.get(name);
|
||||
Assert.notNull(p, "Unknown permission '" + name + "'");
|
||||
Permission p = registeredPermissionsByName.get(name);
|
||||
|
||||
if (p == null) {
|
||||
throw new IllegalArgumentException("Unknown permission '" + name + "'");
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Permission> buildFromNames(List<String> names) {
|
||||
if ((names == null) || (names.size() == 0)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Permission> permissions = new ArrayList<>(names.size());
|
||||
|
||||
List<Permission> permissions = new ArrayList<Permission>(names.size());
|
||||
|
||||
for (String name : names) {
|
||||
permissions.add(buildFromName(name));
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
|
||||
+25
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.util.List;
|
||||
@@ -62,33 +61,42 @@ public class DefaultPermissionGrantingStrategy implements PermissionGrantingStra
|
||||
* decide how to handle the permission check. Similarly, if any of the SID arguments
|
||||
* presented to the method were not loaded by the ACL,
|
||||
* <code>UnloadedSidException</code> will be thrown.
|
||||
*
|
||||
* @param permission the exact permissions to scan for (order is important)
|
||||
* @param sids the exact SIDs to scan for (order is important)
|
||||
* @param administrativeMode if <code>true</code> denotes the query is for
|
||||
* administrative purposes and no auditing will be undertaken
|
||||
*
|
||||
* @return <code>true</code> if one of the permissions has been granted,
|
||||
* <code>false</code> if one of the permissions has been specifically revoked
|
||||
*
|
||||
* @throws NotFoundException if an exact ACE for one of the permission bit masks and
|
||||
* SID combination could not be found
|
||||
*/
|
||||
@Override
|
||||
public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException {
|
||||
List<AccessControlEntry> aces = acl.getEntries();
|
||||
public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids,
|
||||
boolean administrativeMode) throws NotFoundException {
|
||||
|
||||
final List<AccessControlEntry> aces = acl.getEntries();
|
||||
|
||||
AccessControlEntry firstRejection = null;
|
||||
|
||||
for (Permission p : permission) {
|
||||
for (Sid sid : sids) {
|
||||
// Attempt to find exact match for this permission mask and SID
|
||||
boolean scanNextSid = true;
|
||||
|
||||
for (AccessControlEntry ace : aces) {
|
||||
if (isGranted(ace, p) && ace.getSid().equals(sid)) {
|
||||
|
||||
if ((ace.getPermission().getMask() == p.getMask())
|
||||
&& ace.getSid().equals(sid)) {
|
||||
// Found a matching ACE, so its authorization decision will
|
||||
// prevail
|
||||
if (ace.isGranting()) {
|
||||
// Success
|
||||
if (!administrativeMode) {
|
||||
this.auditLogger.logIfNeeded(true, ace);
|
||||
auditLogger.logIfNeeded(true, ace);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -99,11 +107,13 @@ public class DefaultPermissionGrantingStrategy implements PermissionGrantingStra
|
||||
// Store first rejection for auditing reasons
|
||||
firstRejection = ace;
|
||||
}
|
||||
|
||||
scanNextSid = false; // helps break the loop
|
||||
|
||||
break; // exit aces loop
|
||||
}
|
||||
}
|
||||
|
||||
if (!scanNextSid) {
|
||||
break; // exit SID for loop (now try next permission)
|
||||
}
|
||||
@@ -114,8 +124,9 @@ public class DefaultPermissionGrantingStrategy implements PermissionGrantingStra
|
||||
// We found an ACE to reject the request at this point, as no
|
||||
// other ACEs were found that granted a different permission
|
||||
if (!administrativeMode) {
|
||||
this.auditLogger.logIfNeeded(false, firstRejection);
|
||||
auditLogger.logIfNeeded(false, firstRejection);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,28 +135,11 @@ public class DefaultPermissionGrantingStrategy implements PermissionGrantingStra
|
||||
// We have a parent, so let them try to find a matching ACE
|
||||
return acl.getParentAcl().isGranted(permission, sids, false);
|
||||
}
|
||||
|
||||
// We either have no parent, or we're the uppermost parent
|
||||
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares an ACE Permission to the given Permission. By default, we compare the
|
||||
* Permission masks for exact match. Subclasses of this strategy can override this
|
||||
* behavior and implement more sophisticated comparisons, e.g. a bitwise comparison
|
||||
* for ACEs that grant access. <pre>{@code
|
||||
* if (ace.isGranting() && p.getMask() != 0) {
|
||||
* return (ace.getPermission().getMask() & p.getMask()) != 0;
|
||||
* } else {
|
||||
* return ace.getPermission().getMask() == p.getMask();
|
||||
* }
|
||||
* }</pre>
|
||||
* @param ace the ACE from the Acl holding the mask.
|
||||
* @param p the Permission we are checking against.
|
||||
* @return true, if the respective masks are considered to be equal.
|
||||
*/
|
||||
protected boolean isGranted(AccessControlEntry ace, Permission p) {
|
||||
return ace.getPermission().getMask() == p.getMask();
|
||||
else {
|
||||
// We either have no parent, or we're the uppermost parent
|
||||
throw new NotFoundException(
|
||||
"Unable to locate a matching ACE for passed permissions and SIDs");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+49
-26
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -39,14 +38,18 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class EhCacheBasedAclCache implements AclCache {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final Ehcache cache;
|
||||
|
||||
private PermissionGrantingStrategy permissionGrantingStrategy;
|
||||
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public EhCacheBasedAclCache(Ehcache cache,
|
||||
PermissionGrantingStrategy permissionGrantingStrategy,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy) {
|
||||
Assert.notNull(cache, "Cache required");
|
||||
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
|
||||
@@ -56,55 +59,72 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void evictFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
|
||||
MutableAcl acl = getFromCache(pk);
|
||||
|
||||
if (acl != null) {
|
||||
this.cache.remove(acl.getId());
|
||||
this.cache.remove(acl.getObjectIdentity());
|
||||
cache.remove(acl.getId());
|
||||
cache.remove(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
|
||||
MutableAcl acl = getFromCache(objectIdentity);
|
||||
|
||||
if (acl != null) {
|
||||
this.cache.remove(acl.getId());
|
||||
this.cache.remove(acl.getObjectIdentity());
|
||||
cache.remove(acl.getId());
|
||||
cache.remove(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
|
||||
Element element = null;
|
||||
|
||||
try {
|
||||
Element element = this.cache.get(objectIdentity);
|
||||
return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
|
||||
element = cache.get(objectIdentity);
|
||||
}
|
||||
catch (CacheException ex) {
|
||||
catch (CacheException ignored) {
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initializeTransientFields((MutableAcl) element.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
|
||||
Element element = null;
|
||||
|
||||
try {
|
||||
Element element = this.cache.get(pk);
|
||||
return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
|
||||
element = cache.get(pk);
|
||||
}
|
||||
catch (CacheException ex) {
|
||||
catch (CacheException ignored) {
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initializeTransientFields((MutableAcl) element.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putInCache(MutableAcl acl) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
|
||||
Assert.notNull(acl.getId(), "ID required");
|
||||
|
||||
if (this.aclAuthorizationStrategy == null) {
|
||||
if (acl instanceof AclImpl) {
|
||||
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils
|
||||
@@ -113,27 +133,30 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
.getProtectedFieldValue("permissionGrantingStrategy", acl);
|
||||
}
|
||||
}
|
||||
|
||||
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
|
||||
putInCache((MutableAcl) acl.getParentAcl());
|
||||
}
|
||||
this.cache.put(new Element(acl.getObjectIdentity(), acl));
|
||||
this.cache.put(new Element(acl.getId(), acl));
|
||||
|
||||
cache.put(new Element(acl.getObjectIdentity(), acl));
|
||||
cache.put(new Element(acl.getId(), acl));
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value,
|
||||
this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value,
|
||||
this.permissionGrantingStrategy);
|
||||
}
|
||||
|
||||
if (value.getParentAcl() != null) {
|
||||
initializeTransientFields((MutableAcl) value.getParentAcl());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCache() {
|
||||
this.cache.removeAll();
|
||||
cache.removeAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-8
@@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -31,9 +31,14 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class GrantedAuthoritySid implements Sid {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final String grantedAuthority;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public GrantedAuthoritySid(String grantedAuthority) {
|
||||
Assert.hasText(grantedAuthority, "GrantedAuthority required");
|
||||
this.grantedAuthority = grantedAuthority;
|
||||
@@ -41,33 +46,35 @@ public class GrantedAuthoritySid implements Sid {
|
||||
|
||||
public GrantedAuthoritySid(GrantedAuthority grantedAuthority) {
|
||||
Assert.notNull(grantedAuthority, "GrantedAuthority required");
|
||||
Assert.notNull(grantedAuthority.getAuthority(),
|
||||
Assert.notNull(
|
||||
grantedAuthority.getAuthority(),
|
||||
"This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()");
|
||||
this.grantedAuthority = grantedAuthority.getAuthority();
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof GrantedAuthoritySid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delegate to getGrantedAuthority() to perform actual comparison (both should be
|
||||
// identical)
|
||||
return ((GrantedAuthoritySid) object).getGrantedAuthority().equals(this.getGrantedAuthority());
|
||||
return ((GrantedAuthoritySid) object).getGrantedAuthority().equals(
|
||||
this.getGrantedAuthority());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.getGrantedAuthority().hashCode();
|
||||
}
|
||||
|
||||
public String getGrantedAuthority() {
|
||||
return this.grantedAuthority;
|
||||
return grantedAuthority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-5
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
/**
|
||||
@@ -22,9 +21,12 @@ package org.springframework.security.acls.domain;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class IdentityUnavailableException extends RuntimeException {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public IdentityUnavailableException(String msg) {
|
||||
@@ -34,11 +36,11 @@ public class IdentityUnavailableException extends RuntimeException {
|
||||
/**
|
||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause root cause
|
||||
* @param t root cause
|
||||
*/
|
||||
public IdentityUnavailableException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
public IdentityUnavailableException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+49
-33
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -32,14 +31,19 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final String type;
|
||||
|
||||
private Serializable identifier;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public ObjectIdentityImpl(String type, Serializable identifier) {
|
||||
Assert.hasText(type, "Type required");
|
||||
Assert.notNull(identifier, "identifier required");
|
||||
|
||||
this.identifier = identifier;
|
||||
this.type = type;
|
||||
}
|
||||
@@ -62,28 +66,36 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
* <p>
|
||||
* The class name of the object passed will be considered the {@link #type}, so if
|
||||
* more control is required, a different constructor should be used.
|
||||
*
|
||||
* @param object the domain object instance to create an identity for.
|
||||
*
|
||||
* @throws IdentityUnavailableException if identity could not be extracted
|
||||
*/
|
||||
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
||||
Assert.notNull(object, "object cannot be null");
|
||||
|
||||
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
|
||||
this.type = typeClass.getName();
|
||||
Object result = invokeGetIdMethod(object, typeClass);
|
||||
type = typeClass.getName();
|
||||
|
||||
Object result;
|
||||
|
||||
try {
|
||||
Method method = typeClass.getMethod("getId", new Class[] {});
|
||||
result = method.invoke(object);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IdentityUnavailableException(
|
||||
"Could not extract identity from object " + object, e);
|
||||
}
|
||||
|
||||
Assert.notNull(result, "getId() is required to return a non-null value");
|
||||
Assert.isInstanceOf(Serializable.class, result, "Getter must provide a return value of type Serializable");
|
||||
Assert.isInstanceOf(Serializable.class, result,
|
||||
"Getter must provide a return value of type Serializable");
|
||||
this.identifier = (Serializable) result;
|
||||
}
|
||||
|
||||
private Object invokeGetIdMethod(Object object, Class<?> typeClass) {
|
||||
try {
|
||||
Method method = typeClass.getMethod("getId", new Class[] {});
|
||||
return method.invoke(object);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IdentityUnavailableException("Could not extract identity from object " + object, ex);
|
||||
}
|
||||
}
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Important so caching operates properly.
|
||||
@@ -93,58 +105,62 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
* <p>
|
||||
* Numeric identities (Integer and Long values) are considered equal if they are
|
||||
* numerically equal. Other serializable types are evaluated using a simple equality.
|
||||
* @param obj object to compare
|
||||
*
|
||||
* @param arg0 object to compare
|
||||
*
|
||||
* @return <code>true</code> if the presented object matches this object
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof ObjectIdentityImpl)) {
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null || !(arg0 instanceof ObjectIdentityImpl)) {
|
||||
return false;
|
||||
}
|
||||
ObjectIdentityImpl other = (ObjectIdentityImpl) obj;
|
||||
if (this.identifier instanceof Number && other.identifier instanceof Number) {
|
||||
|
||||
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
|
||||
|
||||
if (identifier instanceof Number && other.identifier instanceof Number) {
|
||||
// Integers and Longs with same value should be considered equal
|
||||
if (((Number) this.identifier).longValue() != ((Number) other.identifier).longValue()) {
|
||||
if (((Number) identifier).longValue() != ((Number) other.identifier)
|
||||
.longValue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use plain equality for other serializable types
|
||||
if (!this.identifier.equals(other.identifier)) {
|
||||
if (!identifier.equals(other.identifier)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this.type.equals(other.type);
|
||||
|
||||
return type.equals(other.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getIdentifier() {
|
||||
return this.identifier;
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return this.type;
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Important so caching operates properly.
|
||||
*
|
||||
* @return the hash
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.type.hashCode();
|
||||
result = 31 * result + this.identifier.hashCode();
|
||||
return result;
|
||||
int code = 31;
|
||||
code ^= this.type.hashCode();
|
||||
code ^= this.identifier.hashCode();
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.getClass().getName()).append("[");
|
||||
sb.append("Type: ").append(this.type);
|
||||
sb.append("; Identifier: ").append(this.identifier).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -29,16 +29,16 @@ import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {
|
||||
public class ObjectIdentityRetrievalStrategyImpl implements
|
||||
ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@Override
|
||||
public ObjectIdentity getObjectIdentity(Object domainObject) {
|
||||
return new ObjectIdentityImpl(domainObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectIdentity createObjectIdentity(Serializable id, String type) {
|
||||
return new ObjectIdentityImpl(type, id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.util.List;
|
||||
@@ -26,13 +25,16 @@ import org.springframework.security.acls.model.Permission;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public interface PermissionFactory {
|
||||
|
||||
/**
|
||||
* Dynamically creates a <code>CumulativePermission</code> or
|
||||
* <code>BasePermission</code> representing the active bits in the passed mask.
|
||||
*
|
||||
* @param mask to build
|
||||
*
|
||||
* @return a Permission representing the requested object
|
||||
*/
|
||||
Permission buildFromMask(int mask);
|
||||
@@ -40,5 +42,4 @@ public interface PermissionFactory {
|
||||
Permission buildFromName(String name);
|
||||
|
||||
List<Permission> buildFromNames(List<String> names);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -31,9 +32,14 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class PrincipalSid implements Sid {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final String principal;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public PrincipalSid(String principal) {
|
||||
Assert.hasText(principal, "Principal required");
|
||||
this.principal = principal;
|
||||
@@ -42,31 +48,37 @@ public class PrincipalSid implements Sid {
|
||||
public PrincipalSid(Authentication authentication) {
|
||||
Assert.notNull(authentication, "Authentication required");
|
||||
Assert.notNull(authentication.getPrincipal(), "Principal required");
|
||||
this.principal = authentication.getName();
|
||||
|
||||
if (authentication.getPrincipal() instanceof UserDetails) {
|
||||
this.principal = ((UserDetails) authentication.getPrincipal()).getUsername();
|
||||
}
|
||||
else {
|
||||
this.principal = authentication.getPrincipal().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof PrincipalSid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delegate to getPrincipal() to perform actual comparison (both should be
|
||||
// identical)
|
||||
return ((PrincipalSid) object).getPrincipal().equals(this.getPrincipal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.getPrincipal().hashCode();
|
||||
}
|
||||
|
||||
public String getPrincipal() {
|
||||
return this.principal;
|
||||
return principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PrincipalSid[" + this.principal + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-4
@@ -51,16 +51,20 @@ public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public List<Sid> getSids(Authentication authentication) {
|
||||
Collection<? extends GrantedAuthority> authorities = this.roleHierarchy
|
||||
Collection<? extends GrantedAuthority> authorities = roleHierarchy
|
||||
.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
List<Sid> sids = new ArrayList<>(authorities.size() + 1);
|
||||
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
|
||||
|
||||
sids.add(new PrincipalSid(authentication));
|
||||
|
||||
for (GrantedAuthority authority : authorities) {
|
||||
sids.add(new GrantedAuthoritySid(authority));
|
||||
}
|
||||
|
||||
return sids;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
-23
@@ -13,11 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
@@ -26,6 +23,8 @@ import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link org.springframework.security.acls.model.AclCache} that
|
||||
* delegates to {@link Cache} implementation.
|
||||
@@ -40,14 +39,18 @@ import org.springframework.util.Assert;
|
||||
* @since 3.2
|
||||
*/
|
||||
public class SpringCacheBasedAclCache implements AclCache {
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
private PermissionGrantingStrategy permissionGrantingStrategy;
|
||||
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
public SpringCacheBasedAclCache(Cache cache, PermissionGrantingStrategy permissionGrantingStrategy,
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public SpringCacheBasedAclCache(Cache cache,
|
||||
PermissionGrantingStrategy permissionGrantingStrategy,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy) {
|
||||
Assert.notNull(cache, "Cache required");
|
||||
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
|
||||
@@ -57,72 +60,79 @@ public class SpringCacheBasedAclCache implements AclCache {
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void evictFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
|
||||
MutableAcl acl = getFromCache(pk);
|
||||
|
||||
if (acl != null) {
|
||||
this.cache.evict(acl.getId());
|
||||
this.cache.evict(acl.getObjectIdentity());
|
||||
cache.evict(acl.getId());
|
||||
cache.evict(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
|
||||
MutableAcl acl = getFromCache(objectIdentity);
|
||||
|
||||
if (acl != null) {
|
||||
this.cache.evict(acl.getId());
|
||||
this.cache.evict(acl.getObjectIdentity());
|
||||
cache.evict(acl.getId());
|
||||
cache.evict(acl.getObjectIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
return getFromCache((Object) objectIdentity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
return getFromCache((Object) pk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putInCache(MutableAcl acl) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
|
||||
Assert.notNull(acl.getId(), "ID required");
|
||||
|
||||
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
|
||||
putInCache((MutableAcl) acl.getParentAcl());
|
||||
}
|
||||
this.cache.put(acl.getObjectIdentity(), acl);
|
||||
this.cache.put(acl.getId(), acl);
|
||||
|
||||
cache.put(acl.getObjectIdentity(), acl);
|
||||
cache.put(acl.getId(), acl);
|
||||
}
|
||||
|
||||
private MutableAcl getFromCache(Object key) {
|
||||
Cache.ValueWrapper element = this.cache.get(key);
|
||||
Cache.ValueWrapper element = cache.get(key);
|
||||
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return initializeTransientFields((MutableAcl) element.get());
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value,
|
||||
this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value,
|
||||
this.permissionGrantingStrategy);
|
||||
}
|
||||
|
||||
if (value.getParentAcl() != null) {
|
||||
initializeTransientFields((MutableAcl) value.getParentAcl());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCache() {
|
||||
this.cache.clear();
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Basic implementation of access control lists (ACLs) interfaces.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2018 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
|
||||
*
|
||||
* https://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 org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility class for helping convert database representations of
|
||||
* {@link ObjectIdentity#getIdentifier()} into the correct Java type as specified by
|
||||
* <code>acl_class.class_id_type</code>.
|
||||
*
|
||||
* @author paulwheeler
|
||||
*/
|
||||
class AclClassIdUtils {
|
||||
|
||||
private static final String DEFAULT_CLASS_ID_TYPE_COLUMN_NAME = "class_id_type";
|
||||
|
||||
private static final Log log = LogFactory.getLog(AclClassIdUtils.class);
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
AclClassIdUtils() {
|
||||
GenericConversionService genericConversionService = new GenericConversionService();
|
||||
genericConversionService.addConverter(String.class, Long.class, new StringToLongConverter());
|
||||
genericConversionService.addConverter(String.class, UUID.class, new StringToUUIDConverter());
|
||||
this.conversionService = genericConversionService;
|
||||
}
|
||||
|
||||
AclClassIdUtils(ConversionService conversionService) {
|
||||
Assert.notNull(conversionService, "conversionService must not be null");
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the raw type from the database into the right Java type. For most
|
||||
* applications the 'raw type' will be Long, for some applications it could be String.
|
||||
* @param identifier The identifier from the database
|
||||
* @param resultSet Result set of the query
|
||||
* @return The identifier in the appropriate target Java type. Typically Long or UUID.
|
||||
* @throws SQLException
|
||||
*/
|
||||
Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
|
||||
if (isString(identifier) && hasValidClassIdType(resultSet)
|
||||
&& canConvertFromStringTo(classIdTypeFrom(resultSet))) {
|
||||
return convertFromStringTo((String) identifier, classIdTypeFrom(resultSet));
|
||||
}
|
||||
// Assume it should be a Long type
|
||||
return convertToLong(identifier);
|
||||
}
|
||||
|
||||
private boolean hasValidClassIdType(ResultSet resultSet) {
|
||||
try {
|
||||
return classIdTypeFrom(resultSet) != null;
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
log.debug("Unable to obtain the class id type", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Serializable> Class<T> classIdTypeFrom(ResultSet resultSet) throws SQLException {
|
||||
return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
|
||||
}
|
||||
|
||||
private <T extends Serializable> Class<T> classIdTypeFrom(String className) {
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (Class) Class.forName(className);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
log.debug("Unable to find class id type on classpath", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> boolean canConvertFromStringTo(Class<T> targetType) {
|
||||
return this.conversionService.canConvert(String.class, targetType);
|
||||
}
|
||||
|
||||
private <T extends Serializable> T convertFromStringTo(String identifier, Class<T> targetType) {
|
||||
return this.conversionService.convert(identifier, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to a {@link Long}, attempting to use the {@link ConversionService} if
|
||||
* available.
|
||||
* @param identifier The identifier
|
||||
* @return Long version of the identifier
|
||||
* @throws NumberFormatException if the string cannot be parsed to a long.
|
||||
* @throws org.springframework.core.convert.ConversionException if a conversion
|
||||
* exception occurred
|
||||
* @throws IllegalArgumentException if targetType is null
|
||||
*/
|
||||
private Long convertToLong(Serializable identifier) {
|
||||
if (this.conversionService.canConvert(identifier.getClass(), Long.class)) {
|
||||
return this.conversionService.convert(identifier, Long.class);
|
||||
}
|
||||
return Long.valueOf(identifier.toString());
|
||||
}
|
||||
|
||||
private boolean isString(Serializable object) {
|
||||
return object.getClass().isAssignableFrom(String.class);
|
||||
}
|
||||
|
||||
void setConversionService(ConversionService conversionService) {
|
||||
Assert.notNull(conversionService, "conversionService must not be null");
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
private static class StringToLongConverter implements Converter<String, Long> {
|
||||
|
||||
@Override
|
||||
public Long convert(String identifierAsString) {
|
||||
if (identifierAsString == null) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(Long.class), null, null);
|
||||
|
||||
}
|
||||
return Long.parseLong(identifierAsString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class StringToUUIDConverter implements Converter<String, UUID> {
|
||||
|
||||
@Override
|
||||
public UUID convert(String identifierAsString) {
|
||||
if (identifierAsString == null) {
|
||||
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(UUID.class), null, null);
|
||||
|
||||
}
|
||||
return UUID.fromString(identifierAsString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+213
-176
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006, 2017 Acegi Technology Pty Limited
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -31,9 +30,8 @@ import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
@@ -70,9 +68,9 @@ import org.springframework.util.Assert;
|
||||
* as it is likely to change in future releases and therefore subclassing is unsupported.
|
||||
* <p>
|
||||
* There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and
|
||||
* one in <tt>lookupObjectIdentities</tt>. These are built from the same select and "order
|
||||
* by" clause, using a different where clause in each case. In order to use custom schema
|
||||
* or column names, each of these SQL clauses can be customized, but they must be
|
||||
* one in <tt>lookupObjectIdentities</tt>. These are built from the same select and
|
||||
* "order by" clause, using a different where clause in each case. In order to use custom
|
||||
* schema or column names, each of these SQL clauses can be customized, but they must be
|
||||
* consistent with each other and with the expected result set generated by the the
|
||||
* default values.
|
||||
*
|
||||
@@ -80,151 +78,177 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
private static final String DEFAULT_SELECT_CLAUSE_COLUMNS = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, " + "acl_object_identity.id as acl_id, " + "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, " + "acl_entry.id as ace_id, " + "acl_entry.mask, "
|
||||
+ "acl_entry.granting, " + "acl_entry.audit_success, " + "acl_entry.audit_failure, "
|
||||
+ "acl_sid.principal as ace_principal, " + "acl_sid.sid as ace_sid, "
|
||||
+ "acli_sid.principal as acl_principal, " + "acli_sid.sid as acl_sid, " + "acl_class.class ";
|
||||
|
||||
private static final String DEFAULT_SELECT_CLAUSE_ACL_CLASS_ID_TYPE_COLUMN = ", acl_class.class_id_type ";
|
||||
|
||||
private static final String DEFAULT_SELECT_CLAUSE_FROM = "from acl_object_identity "
|
||||
public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
+ "acl_object_identity.id as acl_id, "
|
||||
+ "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, "
|
||||
+ "acl_entry.id as ace_id, "
|
||||
+ "acl_entry.mask, "
|
||||
+ "acl_entry.granting, "
|
||||
+ "acl_entry.audit_success, "
|
||||
+ "acl_entry.audit_failure, "
|
||||
+ "acl_sid.principal as ace_principal, "
|
||||
+ "acl_sid.sid as ace_sid, "
|
||||
+ "acli_sid.principal as acl_principal, "
|
||||
+ "acli_sid.sid as acl_sid, "
|
||||
+ "acl_class.class "
|
||||
+ "from acl_object_identity "
|
||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
||||
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id " + "where ( ";
|
||||
|
||||
public static final String DEFAULT_SELECT_CLAUSE = DEFAULT_SELECT_CLAUSE_COLUMNS + DEFAULT_SELECT_CLAUSE_FROM;
|
||||
private final static String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
|
||||
|
||||
public static final String DEFAULT_ACL_CLASS_ID_SELECT_CLAUSE = DEFAULT_SELECT_CLAUSE_COLUMNS
|
||||
+ DEFAULT_SELECT_CLAUSE_ACL_CLASS_ID_TYPE_COLUMN + DEFAULT_SELECT_CLAUSE_FROM;
|
||||
private final static String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
|
||||
|
||||
private static final String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
|
||||
|
||||
private static final String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
|
||||
|
||||
public static final String DEFAULT_ORDER_BY_CLAUSE = ") order by acl_object_identity.object_id_identity"
|
||||
public final static String DEFAULT_ORDER_BY_CLAUSE = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
private final AclCache aclCache;
|
||||
|
||||
private final PermissionGrantingStrategy grantingStrategy;
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
private int batchSize = 50;
|
||||
|
||||
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
||||
|
||||
private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
|
||||
private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class,
|
||||
"acl");
|
||||
|
||||
// SQL Customization fields
|
||||
private String selectClause = DEFAULT_SELECT_CLAUSE;
|
||||
|
||||
private String lookupPrimaryKeysWhereClause = DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE;
|
||||
|
||||
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
|
||||
|
||||
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
|
||||
|
||||
private AclClassIdUtils aclClassIdUtils;
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor accepting mandatory arguments
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
* @param aclCache the cache where fully-loaded elements can be stored
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
*/
|
||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
|
||||
this(dataSource, aclCache, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger));
|
||||
this(dataSource, aclCache, aclAuthorizationStrategy,
|
||||
new DefaultPermissionGrantingStrategy(auditLogger));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
* @param aclCache the cache where fully-loaded elements can be stored
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
* @param grantingStrategy the PermissionGrantingStrategy
|
||||
*/
|
||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
PermissionGrantingStrategy grantingStrategy) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
Assert.notNull(aclCache, "AclCache required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(grantingStrategy, "grantingStrategy required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.aclCache = aclCache;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.grantingStrategy = grantingStrategy;
|
||||
this.aclClassIdUtils = new AclClassIdUtils();
|
||||
this.fieldAces.setAccessible(true);
|
||||
this.fieldAcl.setAccessible(true);
|
||||
fieldAces.setAccessible(true);
|
||||
fieldAcl.setAccessible(true);
|
||||
|
||||
}
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
Assert.isTrue(requiredRepetitions > 0, "requiredRepetitions must be > 0");
|
||||
String startSql = this.selectClause;
|
||||
String endSql = this.orderByClause;
|
||||
StringBuilder sqlStringBldr = new StringBuilder(
|
||||
startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
|
||||
assert requiredRepetitions > 0 : "requiredRepetitions must be > 0";
|
||||
|
||||
final String startSql = selectClause;
|
||||
|
||||
final String endSql = orderByClause;
|
||||
|
||||
StringBuilder sqlStringBldr = new StringBuilder(startSql.length()
|
||||
+ endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
|
||||
sqlStringBldr.append(startSql);
|
||||
|
||||
for (int i = 1; i <= requiredRepetitions; i++) {
|
||||
sqlStringBldr.append(repeatingSql);
|
||||
|
||||
if (i != requiredRepetitions) {
|
||||
sqlStringBldr.append(" or ");
|
||||
}
|
||||
}
|
||||
|
||||
sqlStringBldr.append(endSql);
|
||||
|
||||
return sqlStringBldr.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<AccessControlEntryImpl> readAces(AclImpl acl) {
|
||||
try {
|
||||
return (List<AccessControlEntryImpl>) this.fieldAces.get(acl);
|
||||
return (List<AccessControlEntryImpl>) fieldAces.get(acl);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain AclImpl.aces field", ex);
|
||||
catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not obtain AclImpl.aces field", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAclOnAce(AccessControlEntryImpl ace, AclImpl acl) {
|
||||
try {
|
||||
this.fieldAcl.set(ace, acl);
|
||||
fieldAcl.set(ace, acl);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not or set AclImpl on AccessControlEntryImpl fields", ex);
|
||||
catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException(
|
||||
"Could not or set AclImpl on AccessControlEntryImpl fields", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAces(AclImpl acl, List<AccessControlEntryImpl> aces) {
|
||||
try {
|
||||
this.fieldAces.set(acl, aces);
|
||||
fieldAces.set(acl, aces);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not set AclImpl entries", ex);
|
||||
catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not set AclImpl entries", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the primary key IDs specified in "findNow", adding AclImpl instances with
|
||||
* StubAclParents to the "acls" Map.
|
||||
*
|
||||
* @param acls the AclImpls (with StubAclParents)
|
||||
* @param findNow Long-based primary keys to retrieve
|
||||
* @param sids
|
||||
*/
|
||||
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow, final List<Sid> sids) {
|
||||
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls,
|
||||
final Set<Long> findNow, final List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
String sql = computeRepeatingSql(this.lookupPrimaryKeysWhereClause, findNow.size());
|
||||
Set<Long> parentsToLookup = this.jdbcTemplate.query(sql, (ps) -> setKeys(ps, findNow),
|
||||
new ProcessResultSet(acls, sids));
|
||||
|
||||
String sql = computeRepeatingSql(lookupPrimaryKeysWhereClause, findNow.size());
|
||||
|
||||
Set<Long> parentsToLookup = jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
int i = 0;
|
||||
|
||||
for (Long toFind : findNow) {
|
||||
i++;
|
||||
ps.setLong(i, toFind);
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database
|
||||
// connection (SEC-547)
|
||||
if (parentsToLookup.size() > 0) {
|
||||
@@ -232,14 +256,6 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
private void setKeys(PreparedStatement ps, Set<Long> findNow) throws SQLException {
|
||||
int i = 0;
|
||||
for (Long toFind : findNow) {
|
||||
i++;
|
||||
ps.setLong(i, toFind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* <p>
|
||||
@@ -249,61 +265,85 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* develop a custom {@link LookupStrategy} implementation instead.
|
||||
* <p>
|
||||
* The implementation works in batch sizes specified by {@link #batchSize}.
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (ignored by this
|
||||
* implementation)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the
|
||||
* located {@link Acl} and values are the located {@link Acl} (never <tt>null</tt>
|
||||
* although some entries may be missing; this method should not throw
|
||||
* {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used to
|
||||
* automatically create entries if required)
|
||||
*/
|
||||
@Override
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||
Assert.isTrue(this.batchSize >= 1, "BatchSize must be >= 1");
|
||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects,
|
||||
List<Sid> sids) {
|
||||
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
|
||||
// Map<ObjectIdentity,Acl>
|
||||
// contains FULLY loaded Acl objects
|
||||
Map<ObjectIdentity, Acl> result = new HashMap<>();
|
||||
Set<ObjectIdentity> currentBatchToLoad = new HashSet<>();
|
||||
Map<ObjectIdentity, Acl> result = new HashMap<ObjectIdentity, Acl>(); // contains
|
||||
// FULLY
|
||||
// loaded
|
||||
// Acl
|
||||
// objects
|
||||
|
||||
Set<ObjectIdentity> currentBatchToLoad = new HashSet<ObjectIdentity>();
|
||||
|
||||
for (int i = 0; i < objects.size(); i++) {
|
||||
final ObjectIdentity oid = objects.get(i);
|
||||
boolean aclFound = false;
|
||||
|
||||
// Check we don't already have this ACL in the results
|
||||
if (result.containsKey(oid)) {
|
||||
aclFound = true;
|
||||
}
|
||||
|
||||
// Check cache for the present ACL entry
|
||||
if (!aclFound) {
|
||||
Acl acl = this.aclCache.getFromCache(oid);
|
||||
Acl acl = aclCache.getFromCache(oid);
|
||||
|
||||
// Ensure any cached element supports all the requested SIDs
|
||||
// (they should always, as our base impl doesn't filter on SID)
|
||||
if (acl != null) {
|
||||
Assert.state(acl.isSidLoaded(sids),
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
aclFound = true;
|
||||
if (acl.isSidLoaded(sids)) {
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
aclFound = true;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the ACL from the database
|
||||
if (!aclFound) {
|
||||
currentBatchToLoad.add(oid);
|
||||
}
|
||||
|
||||
// Is it time to load from JDBC the currentBatchToLoad?
|
||||
if ((currentBatchToLoad.size() == this.batchSize) || ((i + 1) == objects.size())) {
|
||||
if ((currentBatchToLoad.size() == this.batchSize)
|
||||
|| ((i + 1) == objects.size())) {
|
||||
if (currentBatchToLoad.size() > 0) {
|
||||
Map<ObjectIdentity, Acl> loadedBatch = lookupObjectIdentities(currentBatchToLoad, sids);
|
||||
Map<ObjectIdentity, Acl> loadedBatch = lookupObjectIdentities(
|
||||
currentBatchToLoad, sids);
|
||||
|
||||
// Add loaded batch (all elements 100% initialized) to results
|
||||
result.putAll(loadedBatch);
|
||||
|
||||
// Add the loaded batch to the cache
|
||||
|
||||
for (Acl loadedAcl : loadedBatch.values()) {
|
||||
this.aclCache.putInCache((AclImpl) loadedAcl);
|
||||
aclCache.putInCache((AclImpl) loadedAcl);
|
||||
}
|
||||
|
||||
currentBatchToLoad.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -316,20 +356,42 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* <p>
|
||||
* This subclass is required to return fully valid <code>Acl</code>s, including
|
||||
* properly-configured parent ACLs.
|
||||
*
|
||||
*/
|
||||
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities,
|
||||
List<Sid> sids) {
|
||||
private Map<ObjectIdentity, Acl> lookupObjectIdentities(
|
||||
final Collection<ObjectIdentity> objectIdentities, List<Sid> sids) {
|
||||
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
||||
|
||||
// contains Acls with StubAclParents
|
||||
Map<Serializable, Acl> acls = new HashMap<>();
|
||||
final Map<Serializable, Acl> acls = new HashMap<Serializable, Acl>(); // contains
|
||||
// Acls
|
||||
// with
|
||||
// StubAclParents
|
||||
|
||||
// Make the "acls" map contain all requested objectIdentities
|
||||
// (including markers to each parent in the hierarchy)
|
||||
String sql = computeRepeatingSql(this.lookupObjectIdentitiesWhereClause, objectIdentities.size());
|
||||
String sql = computeRepeatingSql(lookupObjectIdentitiesWhereClause,
|
||||
objectIdentities.size());
|
||||
|
||||
Set<Long> parentsToLookup = this.jdbcTemplate.query(sql,
|
||||
(ps) -> setupLookupObjectIdentitiesStatement(ps, objectIdentities), new ProcessResultSet(acls, sids));
|
||||
Set<Long> parentsToLookup = jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
int i = 0;
|
||||
for (ObjectIdentity oid : objectIdentities) {
|
||||
// Determine prepared statement values for this iteration
|
||||
String type = oid.getType();
|
||||
|
||||
// No need to check for nulls, as guaranteed non-null by
|
||||
// ObjectIdentity.getIdentifier() interface contract
|
||||
String identifier = oid.getIdentifier().toString();
|
||||
long id = (Long.valueOf(identifier)).longValue();
|
||||
|
||||
// Inject values
|
||||
ps.setLong((2 * i) + 1, id);
|
||||
ps.setString((2 * i) + 2, type);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database
|
||||
// connection (SEC-547)
|
||||
@@ -338,10 +400,14 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
// Finally, convert our "acls" containing StubAclParents into true Acls
|
||||
Map<ObjectIdentity, Acl> resultMap = new HashMap<>();
|
||||
Map<ObjectIdentity, Acl> resultMap = new HashMap<ObjectIdentity, Acl>();
|
||||
|
||||
for (Acl inputAcl : acls.values()) {
|
||||
Assert.isInstanceOf(AclImpl.class, inputAcl, "Map should have contained an AclImpl");
|
||||
Assert.isInstanceOf(Long.class, ((AclImpl) inputAcl).getId(), "Acl.getId() must be Long");
|
||||
Assert.isInstanceOf(AclImpl.class, inputAcl,
|
||||
"Map should have contained an AclImpl");
|
||||
Assert.isInstanceOf(Long.class, ((AclImpl) inputAcl).getId(),
|
||||
"Acl.getId() must be Long");
|
||||
|
||||
Acl result = convert(acls, (Long) ((AclImpl) inputAcl).getId());
|
||||
resultMap.put(result.getObjectIdentity(), result);
|
||||
}
|
||||
@@ -349,31 +415,15 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
private void setupLookupObjectIdentitiesStatement(PreparedStatement ps, Collection<ObjectIdentity> objectIdentities)
|
||||
throws SQLException {
|
||||
int i = 0;
|
||||
for (ObjectIdentity oid : objectIdentities) {
|
||||
// Determine prepared statement values for this iteration
|
||||
String type = oid.getType();
|
||||
|
||||
// No need to check for nulls, as guaranteed non-null by
|
||||
// ObjectIdentity.getIdentifier() interface contract
|
||||
String identifier = oid.getIdentifier().toString();
|
||||
|
||||
// Inject values
|
||||
ps.setString((2 * i) + 1, identifier);
|
||||
ps.setString((2 * i) + 2, type);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The final phase of converting the <code>Map</code> of <code>AclImpl</code>
|
||||
* instances which contain <code>StubAclParent</code>s into proper, valid
|
||||
* <code>AclImpl</code>s with correct ACL parents.
|
||||
*
|
||||
* @param inputMap the unconverted <code>AclImpl</code>s
|
||||
* @param currentIdentity the current<code>Acl</code> that we wish to convert (this
|
||||
* may be
|
||||
*
|
||||
*/
|
||||
private AclImpl convert(Map<Serializable, Acl> inputMap, Long currentIdentity) {
|
||||
Assert.notEmpty(inputMap, "InputMap required");
|
||||
@@ -381,7 +431,8 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
// Retrieve this Acl from the InputMap
|
||||
Acl uncastAcl = inputMap.get(currentIdentity);
|
||||
Assert.isInstanceOf(AclImpl.class, uncastAcl, "The inputMap contained a non-AclImpl");
|
||||
Assert.isInstanceOf(AclImpl.class, uncastAcl,
|
||||
"The inputMap contained a non-AclImpl");
|
||||
|
||||
AclImpl inputAcl = (AclImpl) uncastAcl;
|
||||
|
||||
@@ -394,8 +445,9 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
|
||||
// Now we have the parent (if there is one), create the true AclImpl
|
||||
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), inputAcl.getId(), this.aclAuthorizationStrategy,
|
||||
this.grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(),
|
||||
(Long) inputAcl.getId(), aclAuthorizationStrategy, grantingStrategy,
|
||||
parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
|
||||
@@ -403,7 +455,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
List<AccessControlEntryImpl> aces = readAces(inputAcl);
|
||||
|
||||
// Create a list in which to store the "aces" for the "result" AclImpl instance
|
||||
List<AccessControlEntryImpl> acesNew = new ArrayList<>();
|
||||
List<AccessControlEntryImpl> acesNew = new ArrayList<AccessControlEntryImpl>();
|
||||
|
||||
// Iterate over the "aces" input and replace each nested
|
||||
// AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
||||
@@ -422,6 +474,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
/**
|
||||
* Creates a particular implementation of {@link Sid} depending on the arguments.
|
||||
*
|
||||
* @param sid the name of the sid representing its unique identifier. In typical ACL
|
||||
* database schema it's located in table {@code acl_sid} table, {@code sid} column.
|
||||
* @param isPrincipal whether it's a user or granted authority like role
|
||||
@@ -431,13 +484,16 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
if (isPrincipal) {
|
||||
return new PrincipalSid(sid);
|
||||
}
|
||||
return new GrantedAuthoritySid(sid);
|
||||
else {
|
||||
return new GrantedAuthoritySid(sid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code PermissionFactory} instance which will be used to convert loaded
|
||||
* permission data values to {@code Permission}s. A {@code DefaultPermissionFactory}
|
||||
* will be used by default.
|
||||
*
|
||||
* @param permissionFactory
|
||||
*/
|
||||
public final void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||
@@ -451,6 +507,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
/**
|
||||
* The SQL for the select clause. If customizing in order to modify column names,
|
||||
* schema etc, the other SQL customization fields must also be set to match.
|
||||
*
|
||||
* @param selectClause the select clause, which defaults to
|
||||
* {@link #DEFAULT_SELECT_CLAUSE}.
|
||||
*/
|
||||
@@ -468,7 +525,8 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
/**
|
||||
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
|
||||
*/
|
||||
public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
|
||||
public final void setLookupObjectIdentitiesWhereClause(
|
||||
String lookupObjectIdentitiesWhereClause) {
|
||||
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
|
||||
}
|
||||
|
||||
@@ -479,26 +537,14 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
public final void setAclClassIdSupported(boolean aclClassIdSupported) {
|
||||
if (aclClassIdSupported) {
|
||||
Assert.isTrue(this.selectClause.equals(DEFAULT_SELECT_CLAUSE),
|
||||
"Cannot set aclClassIdSupported and override the select clause; "
|
||||
+ "just override the select clause");
|
||||
this.selectClause = DEFAULT_ACL_CLASS_ID_SELECT_CLAUSE;
|
||||
}
|
||||
}
|
||||
|
||||
public final void setConversionService(ConversionService conversionService) {
|
||||
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
|
||||
}
|
||||
// ~ Inner Classes
|
||||
// ==================================================================================================
|
||||
|
||||
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
|
||||
|
||||
private final Map<Serializable, Acl> acls;
|
||||
|
||||
private final List<Sid> sids;
|
||||
|
||||
ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||
public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs cannot be null");
|
||||
this.acls = acls;
|
||||
this.sids = sids; // can be null
|
||||
@@ -514,32 +560,32 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
* <tt>null</tt>)
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public Set<Long> extractData(ResultSet rs) throws SQLException {
|
||||
Set<Long> parentIdsToLookup = new HashSet<>(); // Set of parent_id Longs
|
||||
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
|
||||
|
||||
while (rs.next()) {
|
||||
// Convert current row into an Acl (albeit with a StubAclParent)
|
||||
convertCurrentResultIntoObject(this.acls, rs);
|
||||
convertCurrentResultIntoObject(acls, rs);
|
||||
|
||||
// Figure out if this row means we need to lookup another parent
|
||||
long parentId = rs.getLong("parent_object");
|
||||
|
||||
if (parentId != 0) {
|
||||
// See if it's already in the "acls"
|
||||
if (this.acls.containsKey(parentId)) {
|
||||
if (acls.containsKey(new Long(parentId))) {
|
||||
continue; // skip this while iteration
|
||||
}
|
||||
|
||||
// Now try to find it in the cache
|
||||
MutableAcl cached = BasicLookupStrategy.this.aclCache.getFromCache(parentId);
|
||||
if ((cached == null) || !cached.isSidLoaded(this.sids)) {
|
||||
parentIdsToLookup.add(parentId);
|
||||
MutableAcl cached = aclCache.getFromCache(new Long(parentId));
|
||||
|
||||
if ((cached == null) || !cached.isSidLoaded(sids)) {
|
||||
parentIdsToLookup.add(new Long(parentId));
|
||||
}
|
||||
else {
|
||||
// Pop into the acls map, so our convert method doesn't
|
||||
// need to deal with an unsynchronized AclCache
|
||||
this.acls.put(cached.getId(), cached);
|
||||
acls.put(cached.getId(), cached);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -551,38 +597,38 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
/**
|
||||
* Accepts the current <code>ResultSet</code> row, and converts it into an
|
||||
* <code>AclImpl</code> that contains a <code>StubAclParent</code>
|
||||
*
|
||||
* @param acls the Map we should add the converted Acl to
|
||||
* @param rs the ResultSet focused on a current row
|
||||
*
|
||||
* @throws SQLException if something goes wrong converting values
|
||||
* @throws ConversionException if can't convert to the desired Java type
|
||||
*/
|
||||
private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultSet rs) throws SQLException {
|
||||
Long id = rs.getLong("acl_id");
|
||||
private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls,
|
||||
ResultSet rs) throws SQLException {
|
||||
Long id = new Long(rs.getLong("acl_id"));
|
||||
|
||||
// If we already have an ACL for this ID, just create the ACE
|
||||
Acl acl = acls.get(id);
|
||||
|
||||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
|
||||
// If the Java type is a String, check to see if we can convert it to the
|
||||
// target id type, e.g. UUID.
|
||||
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
|
||||
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"), identifier);
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(
|
||||
rs.getString("class"), Long.valueOf(rs
|
||||
.getLong("object_id_identity")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(parentAclId);
|
||||
parentAcl = new StubAclParent(Long.valueOf(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
|
||||
Sid owner = createSid(rs.getBoolean("acl_principal"),
|
||||
rs.getString("acl_sid"));
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, BasicLookupStrategy.this.aclAuthorizationStrategy,
|
||||
BasicLookupStrategy.this.grantingStrategy, parentAcl, null, entriesInheriting, owner);
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy,
|
||||
grantingStrategy, parentAcl, null, entriesInheriting, owner);
|
||||
|
||||
acls.put(id, acl);
|
||||
}
|
||||
@@ -591,17 +637,18 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
// It is permissible to have no ACEs in an ACL (which is detected by a null
|
||||
// ACE_SID)
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = rs.getLong("ace_id");
|
||||
Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
Sid recipient = createSid(rs.getBoolean("ace_principal"),
|
||||
rs.getString("ace_sid"));
|
||||
|
||||
int mask = rs.getInt("mask");
|
||||
Permission permission = BasicLookupStrategy.this.permissionFactory.buildFromMask(mask);
|
||||
Permission permission = permissionFactory.buildFromMask(mask);
|
||||
boolean granting = rs.getBoolean("granting");
|
||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, recipient, permission, granting,
|
||||
auditSuccess, auditFailure);
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl,
|
||||
recipient, permission, granting, auditSuccess, auditFailure);
|
||||
|
||||
// Field acesField = FieldUtils.getField(AclImpl.class, "aces");
|
||||
List<AccessControlEntryImpl> aces = readAces((AclImpl) acl);
|
||||
@@ -612,57 +659,47 @@ public class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class StubAclParent implements Acl {
|
||||
|
||||
private final Long id;
|
||||
|
||||
StubAclParent(Long id) {
|
||||
public StubAclParent(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessControlEntry> getEntries() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ObjectIdentity getObjectIdentity() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sid getOwner() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl getParentAcl() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEntriesInheriting() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids,
|
||||
boolean administrativeMode) throws NotFoundException,
|
||||
UnloadedSidException {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006, 2017, 2018 Acegi Technology Pty Limited
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,13 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -27,10 +25,8 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
@@ -49,124 +45,97 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class JdbcAclService implements AclService {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
||||
|
||||
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS = "class.class as class";
|
||||
|
||||
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE = DEFAULT_SELECT_ACL_CLASS_COLUMNS
|
||||
+ ", class.class_id_type as class_id_type";
|
||||
|
||||
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, "
|
||||
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS
|
||||
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, class.class as class "
|
||||
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||
+ "select id FROM acl_class where acl_class.class = ?)";
|
||||
|
||||
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE = "select obj.object_id_identity as obj_id, "
|
||||
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE
|
||||
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||
+ "select id FROM acl_class where acl_class.class = ?)";
|
||||
|
||||
protected final JdbcOperations jdbcOperations;
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
protected final JdbcTemplate jdbcTemplate;
|
||||
private final LookupStrategy lookupStrategy;
|
||||
|
||||
private boolean aclClassIdSupported;
|
||||
|
||||
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
||||
|
||||
private AclClassIdUtils aclClassIdUtils;
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
|
||||
this(new JdbcTemplate(dataSource), lookupStrategy);
|
||||
}
|
||||
|
||||
public JdbcAclService(JdbcOperations jdbcOperations, LookupStrategy lookupStrategy) {
|
||||
Assert.notNull(jdbcOperations, "JdbcOperations required");
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
Assert.notNull(lookupStrategy, "LookupStrategy required");
|
||||
this.jdbcOperations = jdbcOperations;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.lookupStrategy = lookupStrategy;
|
||||
this.aclClassIdUtils = new AclClassIdUtils();
|
||||
}
|
||||
|
||||
@Override
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
|
||||
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
|
||||
(rs, rowNum) -> mapObjectIdentityRow(rs));
|
||||
return (!objects.isEmpty()) ? objects : null;
|
||||
Object[] args = { parentIdentity.getIdentifier(), parentIdentity.getType() };
|
||||
List<ObjectIdentity> objects = jdbcTemplate.query(findChildrenSql, args,
|
||||
new RowMapper<ObjectIdentity>() {
|
||||
public ObjectIdentity mapRow(ResultSet rs, int rowNum)
|
||||
throws SQLException {
|
||||
String javaType = rs.getString("class");
|
||||
Long identifier = new Long(rs.getLong("obj_id"));
|
||||
|
||||
return new ObjectIdentityImpl(javaType, identifier);
|
||||
}
|
||||
});
|
||||
|
||||
if (objects.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
private ObjectIdentity mapObjectIdentityRow(ResultSet rs) throws SQLException {
|
||||
String javaType = rs.getString("class");
|
||||
Serializable identifier = (Serializable) rs.getObject("obj_id");
|
||||
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
|
||||
return new ObjectIdentityImpl(javaType, identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
|
||||
public Acl readAclById(ObjectIdentity object, List<Sid> sids)
|
||||
throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> map = readAclsById(Arrays.asList(object), sids);
|
||||
Assert.isTrue(map.containsKey(object),
|
||||
() -> "There should have been an Acl entry for ObjectIdentity " + object);
|
||||
return map.get(object);
|
||||
"There should have been an Acl entry for ObjectIdentity " + object);
|
||||
|
||||
return (Acl) map.get(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
|
||||
return readAclById(object, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects)
|
||||
throws NotFoundException {
|
||||
return readAclsById(objects, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
|
||||
throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects,
|
||||
List<Sid> sids) throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
|
||||
|
||||
// Check every requested object identity was found (throw NotFoundException if
|
||||
// needed)
|
||||
for (ObjectIdentity oid : objects) {
|
||||
if (!result.containsKey(oid)) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
|
||||
throw new NotFoundException(
|
||||
"Unable to find ACL information for object identity '" + oid
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customization of the SQL query used to find child object identities.
|
||||
*
|
||||
* @param findChildrenSql
|
||||
*/
|
||||
public void setFindChildrenQuery(String findChildrenSql) {
|
||||
this.findChildrenSql = findChildrenSql;
|
||||
}
|
||||
|
||||
public void setAclClassIdSupported(boolean aclClassIdSupported) {
|
||||
this.aclClassIdSupported = aclClassIdSupported;
|
||||
if (aclClassIdSupported) {
|
||||
// Change the default children select if it hasn't been overridden
|
||||
if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) {
|
||||
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
|
||||
}
|
||||
else {
|
||||
log.debug("Find children statement has already been overridden, so not overridding the default");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
|
||||
}
|
||||
|
||||
protected boolean isAclClassIdSupported() {
|
||||
return this.aclClassIdSupported;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+106
-94
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006, 2017, 2018 Acegi Technology Pty Limited
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -59,58 +58,53 @@ import org.springframework.util.Assert;
|
||||
* @author Johannes Zlattinger
|
||||
*/
|
||||
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
||||
|
||||
private static final String DEFAULT_INSERT_INTO_ACL_CLASS = "insert into acl_class (class) values (?)";
|
||||
|
||||
private static final String DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID = "insert into acl_class (class, class_id_type) values (?, ?)";
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
|
||||
private final AclCache aclCache;
|
||||
|
||||
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
||||
|
||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||
|
||||
private String classIdentityQuery = "call identity()";
|
||||
|
||||
private String sidIdentityQuery = "call identity()";
|
||||
|
||||
private String insertClass = DEFAULT_INSERT_INTO_ACL_CLASS;
|
||||
|
||||
private String insertClass = "insert into acl_class (class) values (?)";
|
||||
private String insertEntry = "insert into acl_entry "
|
||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private String insertObjectIdentity = "insert into acl_object_identity "
|
||||
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
|
||||
|
||||
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) "
|
||||
+ "values (?, ?, ?, ?)";
|
||||
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
|
||||
|
||||
private String selectClassPrimaryKey = "select id from acl_class where class=?";
|
||||
|
||||
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_class "
|
||||
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
|
||||
+ "and acl_object_identity.object_id_identity = ?";
|
||||
|
||||
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
|
||||
|
||||
private String updateObjectIdentity = "update acl_object_identity set "
|
||||
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
|
||||
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?"
|
||||
+ " where id = ?";
|
||||
|
||||
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy,
|
||||
AclCache aclCache) {
|
||||
super(dataSource, lookupStrategy);
|
||||
Assert.notNull(aclCache, "AclCache required");
|
||||
this.aclCache = aclCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity)
|
||||
throws AlreadyExistsException {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
|
||||
// Check this object identity hasn't already been persisted
|
||||
if (retrieveObjectIdentityPrimaryKey(objectIdentity) != null) {
|
||||
throw new AlreadyExistsException("Object identity '" + objectIdentity + "' already exists");
|
||||
throw new AlreadyExistsException("Object identity '" + objectIdentity
|
||||
+ "' already exists");
|
||||
}
|
||||
|
||||
// Need to retrieve the current principal, in order to know who "owns" this ACL
|
||||
@@ -132,34 +126,33 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
/**
|
||||
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl
|
||||
* object.
|
||||
*
|
||||
* @param acl containing the ACEs to insert
|
||||
*/
|
||||
protected void createEntries(final MutableAcl acl) {
|
||||
if (acl.getEntries().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
this.jdbcOperations.batchUpdate(this.insertEntry, new BatchPreparedStatementSetter() {
|
||||
|
||||
@Override
|
||||
jdbcTemplate.batchUpdate(insertEntry, new BatchPreparedStatementSetter() {
|
||||
public int getBatchSize() {
|
||||
return acl.getEntries().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(PreparedStatement stmt, int i) throws SQLException {
|
||||
AccessControlEntry entry_ = acl.getEntries().get(i);
|
||||
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
|
||||
Assert.isTrue(entry_ instanceof AccessControlEntryImpl,
|
||||
"Unknown ACE class");
|
||||
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
|
||||
|
||||
stmt.setLong(1, (Long) acl.getId());
|
||||
stmt.setLong(1, ((Long) acl.getId()).longValue());
|
||||
stmt.setInt(2, i);
|
||||
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true));
|
||||
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true)
|
||||
.longValue());
|
||||
stmt.setInt(4, entry.getPermission().getMask());
|
||||
stmt.setBoolean(5, entry.isGranting());
|
||||
stmt.setBoolean(6, entry.isAuditSuccess());
|
||||
stmt.setBoolean(7, entry.isAuditFailure());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -167,41 +160,40 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity.
|
||||
* The Sid is also necessary, as acl_object_identity has defined the sid column as
|
||||
* non-null.
|
||||
*
|
||||
* @param object to represent an acl_object_identity for
|
||||
* @param owner for the SID column (will be created if there is no acl_sid entry for
|
||||
* this particular Sid already)
|
||||
*/
|
||||
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
||||
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
||||
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true, object.getIdentifier().getClass());
|
||||
this.jdbcOperations.update(this.insertObjectIdentity, classId, object.getIdentifier().toString(), sidId,
|
||||
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true);
|
||||
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId,
|
||||
Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from {@code acl_class}, creating a new row if needed and
|
||||
* the {@code allowCreate} property is {@code true}.
|
||||
*
|
||||
* @param type to find or create an entry for (often the fully-qualified class name)
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
*
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, new Object[] { type },
|
||||
Long.class);
|
||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate) {
|
||||
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey,
|
||||
new Object[] { type }, Long.class);
|
||||
|
||||
if (!classIds.isEmpty()) {
|
||||
return classIds.get(0);
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
if (!isAclClassIdSupported()) {
|
||||
this.jdbcOperations.update(this.insertClass, type);
|
||||
}
|
||||
else {
|
||||
this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName());
|
||||
}
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
return this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
|
||||
jdbcTemplate.update(insertClass, type);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
return jdbcTemplate.queryForObject(classIdentityQuery, Long.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -210,23 +202,33 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
/**
|
||||
* Retrieves the primary key from acl_sid, creating a new row if needed and the
|
||||
* allowCreate property is true.
|
||||
*
|
||||
* @param sid to find or create
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
*
|
||||
* @return the primary key or null if not found
|
||||
*
|
||||
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized
|
||||
* implementation.
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
Assert.notNull(sid, "Sid required");
|
||||
|
||||
String sidName;
|
||||
boolean sidIsPrincipal = true;
|
||||
|
||||
if (sid instanceof PrincipalSid) {
|
||||
String sidName = ((PrincipalSid) sid).getPrincipal();
|
||||
return createOrRetrieveSidPrimaryKey(sidName, true, allowCreate);
|
||||
sidName = ((PrincipalSid) sid).getPrincipal();
|
||||
}
|
||||
if (sid instanceof GrantedAuthoritySid) {
|
||||
String sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
|
||||
return createOrRetrieveSidPrimaryKey(sidName, false, allowCreate);
|
||||
else if (sid instanceof GrantedAuthoritySid) {
|
||||
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
|
||||
sidIsPrincipal = false;
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
||||
}
|
||||
|
||||
return createOrRetrieveSidPrimaryKey(sidName, sidIsPrincipal, allowCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,24 +239,32 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
|
||||
List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey,
|
||||
new Object[] { sidIsPrincipal, sidName }, Long.class);
|
||||
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal,
|
||||
boolean allowCreate) {
|
||||
|
||||
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey, new Object[] {
|
||||
Boolean.valueOf(sidIsPrincipal), sidName }, Long.class);
|
||||
|
||||
if (!sidIds.isEmpty()) {
|
||||
return sidIds.get(0);
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
return this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
|
||||
jdbcTemplate.update(insertSid, Boolean.valueOf(sidIsPrincipal), sidName);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
return jdbcTemplate.queryForObject(sidIdentityQuery, Long.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
|
||||
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
|
||||
throws ChildrenExistException {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
|
||||
Assert.notNull(objectIdentity.getIdentifier(),
|
||||
"Object Identity doesn't provide an identifier");
|
||||
|
||||
if (deleteChildren) {
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
@@ -264,13 +274,14 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.foreignKeysInDatabase) {
|
||||
if (!foreignKeysInDatabase) {
|
||||
// We need to perform a manual verification for what a FK would normally
|
||||
// do. We generally don't do this, in the interests of deadlock management
|
||||
// do
|
||||
// We generally don't do this, in the interests of deadlock management
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
throw new ChildrenExistException(
|
||||
"Cannot delete '" + objectIdentity + "' (has " + children.size() + " children)");
|
||||
throw new ChildrenExistException("Cannot delete '" + objectIdentity
|
||||
+ "' (has " + children.size() + " children)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,16 +295,17 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
deleteObjectIdentity(oidPrimaryKey);
|
||||
|
||||
// Clear the cache
|
||||
this.aclCache.evictFromCache(objectIdentity);
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all ACEs defined in the acl_entry table belonging to the presented
|
||||
* ObjectIdentity primary key.
|
||||
*
|
||||
* @param oidPrimaryKey the rows in acl_entry to delete
|
||||
*/
|
||||
protected void deleteEntries(Long oidPrimaryKey) {
|
||||
this.jdbcOperations.update(this.deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,24 +314,27 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* <p>
|
||||
* We do not delete any entries from acl_class, even if no classes are using that
|
||||
* class any longer. This is a deadlock avoidance approach.
|
||||
*
|
||||
* @param oidPrimaryKey to delete the acl_object_identity
|
||||
*/
|
||||
protected void deleteObjectIdentity(Long oidPrimaryKey) {
|
||||
// Delete the acl_object_identity row
|
||||
this.jdbcOperations.update(this.deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
|
||||
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from the acl_object_identity table for the passed
|
||||
* ObjectIdentity. Unlike some other methods in this implementation, this method will
|
||||
* NOT create a row (use {@link #createObjectIdentity(ObjectIdentity, Sid)} instead).
|
||||
*
|
||||
* @param oid to find
|
||||
*
|
||||
* @return the object identity or null if not found
|
||||
*/
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
return this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, oid.getType(),
|
||||
oid.getIdentifier().toString());
|
||||
return jdbcTemplate.queryForObject(selectObjectIdentityPrimaryKey, Long.class,
|
||||
oid.getType(), oid.getIdentifier());
|
||||
}
|
||||
catch (DataAccessException notFound) {
|
||||
return null;
|
||||
@@ -332,7 +347,6 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* dirty state checking, or more likely use ORM capabilities for create, update and
|
||||
* delete operations of {@link MutableAcl}.
|
||||
*/
|
||||
@Override
|
||||
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
||||
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
||||
|
||||
@@ -361,28 +375,37 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
clearCacheIncludingChildren(child);
|
||||
}
|
||||
}
|
||||
this.aclCache.evictFromCache(objectIdentity);
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing acl_object_identity row, with new information presented in the
|
||||
* passed MutableAcl object. Also will create an acl_sid entry if needed for the Sid
|
||||
* that owns the MutableAcl.
|
||||
*
|
||||
* @param acl to modify (a row must already exist in acl_object_identity)
|
||||
*
|
||||
* @throws NotFoundException if the ACL could not be found to update.
|
||||
*/
|
||||
protected void updateObjectIdentity(MutableAcl acl) {
|
||||
Long parentId = null;
|
||||
|
||||
if (acl.getParentAcl() != null) {
|
||||
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
|
||||
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl()
|
||||
.getObjectIdentity(),
|
||||
"Implementation only supports ObjectIdentityImpl");
|
||||
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
|
||||
|
||||
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl()
|
||||
.getObjectIdentity();
|
||||
parentId = retrieveObjectIdentityPrimaryKey(oii);
|
||||
}
|
||||
|
||||
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
|
||||
|
||||
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
|
||||
int count = this.jdbcOperations.update(this.updateObjectIdentity, parentId, ownerSid, acl.isEntriesInheriting(),
|
||||
acl.getId());
|
||||
int count = jdbcTemplate.update(updateObjectIdentity, parentId, ownerSid,
|
||||
Boolean.valueOf(acl.isEntriesInheriting()), acl.getId());
|
||||
|
||||
if (count != 1) {
|
||||
throw new NotFoundException("Unable to locate ACL to update");
|
||||
}
|
||||
@@ -391,6 +414,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
/**
|
||||
* Sets the query that will be used to retrieve the identity of a newly created row in
|
||||
* the <tt>acl_class</tt> table.
|
||||
*
|
||||
* @param classIdentityQuery the query, which should return the identifier. Defaults
|
||||
* to <tt>call identity()</tt>
|
||||
*/
|
||||
@@ -402,6 +426,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
/**
|
||||
* Sets the query that will be used to retrieve the identity of a newly created row in
|
||||
* the <tt>acl_sid</tt> table.
|
||||
*
|
||||
* @param sidIdentityQuery the query, which should return the identifier. Defaults to
|
||||
* <tt>call identity()</tt>
|
||||
*/
|
||||
@@ -410,11 +435,13 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
this.sidIdentityQuery = sidIdentityQuery;
|
||||
}
|
||||
|
||||
public void setDeleteEntryByObjectIdentityForeignKeySql(String deleteEntryByObjectIdentityForeignKey) {
|
||||
public void setDeleteEntryByObjectIdentityForeignKeySql(
|
||||
String deleteEntryByObjectIdentityForeignKey) {
|
||||
this.deleteEntryByObjectIdentityForeignKey = deleteEntryByObjectIdentityForeignKey;
|
||||
}
|
||||
|
||||
public void setDeleteObjectIdentityByPrimaryKeySql(String deleteObjectIdentityByPrimaryKey) {
|
||||
public void setDeleteObjectIdentityByPrimaryKeySql(
|
||||
String deleteObjectIdentityByPrimaryKey) {
|
||||
this.deleteObjectIdentityByPrimaryKey = deleteObjectIdentityByPrimaryKey;
|
||||
}
|
||||
|
||||
@@ -458,19 +485,4 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAclClassIdSupported(boolean aclClassIdSupported) {
|
||||
super.setAclClassIdSupported(aclClassIdSupported);
|
||||
if (aclClassIdSupported) {
|
||||
// Change the default insert if it hasn't been overridden
|
||||
if (this.insertClass.equals(DEFAULT_INSERT_INTO_ACL_CLASS)) {
|
||||
this.insertClass = DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID;
|
||||
}
|
||||
else {
|
||||
log.debug("Insert class statement has already been overridden, so not overridding the default");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,29 +13,32 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Performs lookups for {@link org.springframework.security.acls.model.AclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface LookupStrategy {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Perform database-specific optimized lookup.
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (may be <tt>null</tt> -
|
||||
* implementations may elect not to provide SID optimisations)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the
|
||||
* located {@link Acl} and values are the located {@link Acl} (never <tt>null</tt>
|
||||
* although some entries may be missing; this method should not throw
|
||||
@@ -43,5 +46,4 @@ public interface LookupStrategy {
|
||||
* automatically create entries if required)
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDBC-based persistence of ACL information
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -27,13 +26,17 @@ import java.io.Serializable;
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public interface AccessControlEntry extends Serializable {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
Acl getAcl();
|
||||
|
||||
/**
|
||||
* Obtains an identifier that represents this ACE.
|
||||
*
|
||||
* @return the identifier, or <code>null</code> if unsaved
|
||||
*/
|
||||
Serializable getId();
|
||||
@@ -43,10 +46,10 @@ public interface AccessControlEntry extends Serializable {
|
||||
Sid getSid();
|
||||
|
||||
/**
|
||||
* Indicates the permission is being granted to the relevant Sid. If false, indicates
|
||||
* the permission is being revoked/blocked.
|
||||
* Indicates the permission is being granted to the relevant Sid. If false,
|
||||
* indicates the permission is being revoked/blocked.
|
||||
*
|
||||
* @return true if being granted, false otherwise
|
||||
*/
|
||||
boolean isGranting();
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -64,6 +63,7 @@ public interface Acl extends Serializable {
|
||||
* subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
|
||||
* result if only a subset of <tt>Sid</tt>s is represented.
|
||||
* </p>
|
||||
*
|
||||
* @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if
|
||||
* there are no entries presently associated with this <tt>Acl</tt>.
|
||||
*/
|
||||
@@ -72,6 +72,7 @@ public interface Acl extends Serializable {
|
||||
/**
|
||||
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable
|
||||
* once an <tt>Acl</tt> is created.
|
||||
*
|
||||
* @return the object identity (never <tt>null</tt>)
|
||||
*/
|
||||
ObjectIdentity getObjectIdentity();
|
||||
@@ -79,6 +80,7 @@ public interface Acl extends Serializable {
|
||||
/**
|
||||
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by
|
||||
* implementation and is unspecified.
|
||||
*
|
||||
* @return the owner (may be <tt>null</tt> if the implementation does not use
|
||||
* ownership concepts)
|
||||
*/
|
||||
@@ -100,6 +102,7 @@ public interface Acl extends Serializable {
|
||||
* subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
|
||||
* result if only a subset of <tt>Sid</tt>s is represented.
|
||||
* </p>
|
||||
*
|
||||
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not
|
||||
* have a parent)
|
||||
*/
|
||||
@@ -115,6 +118,7 @@ public interface Acl extends Serializable {
|
||||
* parent for navigation purposes. Thus, this method denotes whether or not the
|
||||
* navigation relationship also extends to the actual inheritance of entries.
|
||||
* </p>
|
||||
*
|
||||
* @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
|
||||
*/
|
||||
boolean isEntriesInheriting();
|
||||
@@ -154,6 +158,7 @@ public interface Acl extends Serializable {
|
||||
* authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>
|
||||
* .
|
||||
* </p>
|
||||
*
|
||||
* @param permission the permission or permissions required (at least one entry
|
||||
* required)
|
||||
* @param sids the security identities held by the principal (at least one entry
|
||||
@@ -161,15 +166,17 @@ public interface Acl extends Serializable {
|
||||
* @param administrativeMode if <tt>true</tt> denotes the query is for administrative
|
||||
* purposes and no logging or auditing (if supported by the implementation) should be
|
||||
* undertaken
|
||||
*
|
||||
* @return <tt>true</tt> if authorization is granted
|
||||
*
|
||||
* @throws NotFoundException MUST be thrown if an implementation cannot make an
|
||||
* authoritative authorization decision, usually because there is no ACL information
|
||||
* for this particular permission and/or SID
|
||||
* @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for
|
||||
* one or more of the <tt>Sid</tt>s passed as arguments
|
||||
*/
|
||||
boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException;
|
||||
boolean isGranted(List<Permission> permission, List<Sid> sids,
|
||||
boolean administrativeMode) throws NotFoundException, UnloadedSidException;
|
||||
|
||||
/**
|
||||
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain
|
||||
@@ -184,11 +191,12 @@ public interface Acl extends Serializable {
|
||||
* all <tt>Sid</tt>s. This method denotes whether or not the specified <tt>Sid</tt>s
|
||||
* have been loaded or not.
|
||||
* </p>
|
||||
*
|
||||
* @param sids one or more security identities the caller is interest in knowing
|
||||
* whether this <tt>Sid</tt> supports
|
||||
*
|
||||
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this
|
||||
* <tt>Acl</tt> instance
|
||||
*/
|
||||
boolean isSidLoaded(List<Sid> sids);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,19 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.acls.jdbc.JdbcAclService;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A caching layer for {@link JdbcAclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public interface AclCache {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
void evictFromCache(Serializable pk);
|
||||
|
||||
@@ -38,5 +40,4 @@ public interface AclCache {
|
||||
void putInCache(MutableAcl acl);
|
||||
|
||||
void clearCache();
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
@@ -27,6 +26,7 @@ public abstract class AclDataAccessException extends RuntimeException {
|
||||
/**
|
||||
* Constructs an <code>AclDataAccessException</code> with the specified message and
|
||||
* root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause the root cause
|
||||
*/
|
||||
@@ -37,10 +37,10 @@ public abstract class AclDataAccessException extends RuntimeException {
|
||||
/**
|
||||
* Constructs an <code>AclDataAccessException</code> with the specified message and no
|
||||
* root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AclDataAccessException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.util.List;
|
||||
@@ -25,11 +24,15 @@ import java.util.Map;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AclService {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Locates all object identities that use the specified parent. This is useful for
|
||||
* administration tools.
|
||||
*
|
||||
* @param parentIdentity to locate children of
|
||||
*
|
||||
* @return the children (or <tt>null</tt> if none were found)
|
||||
*/
|
||||
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||
@@ -41,9 +44,12 @@ public interface AclService {
|
||||
* implementation's potential ability to filter <tt>Acl</tt> entries based on a
|
||||
* {@link Sid} parameter.
|
||||
* </p>
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never
|
||||
* <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
@@ -51,11 +57,14 @@ public interface AclService {
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(List, List)} except it returns only a single Acl.
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never
|
||||
* <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
@@ -67,13 +76,17 @@ public interface AclService {
|
||||
* The returned map is keyed on the passed objects, with the values being the
|
||||
* <tt>Acl</tt> instances. Any unknown objects will not have a map key.
|
||||
* </p>
|
||||
*
|
||||
* @param objects the objects to find {@link Acl} information for
|
||||
*
|
||||
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an
|
||||
* argument (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException;
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only
|
||||
@@ -90,14 +103,17 @@ public interface AclService {
|
||||
* <tt>Acl</tt> instances. Any unknown objects (or objects for which the interested
|
||||
* <tt>Sid</tt>s do not have entries) will not have a map key.
|
||||
* </p>
|
||||
*
|
||||
* @param objects the objects to find {@link Acl} information for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
*
|
||||
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an
|
||||
* argument (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested
|
||||
* {@link ObjectIdentity}
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
|
||||
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
|
||||
throws NotFoundException;
|
||||
}
|
||||
|
||||
+7
-5
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
@@ -22,9 +21,12 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AlreadyExistsException extends AclDataAccessException {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>AlreadyExistsException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AlreadyExistsException(String msg) {
|
||||
@@ -34,11 +36,11 @@ public class AlreadyExistsException extends AclDataAccessException {
|
||||
/**
|
||||
* Constructs an <code>AlreadyExistsException</code> with the specified message and
|
||||
* root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause root cause
|
||||
* @param t root cause
|
||||
*/
|
||||
public AlreadyExistsException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
public AlreadyExistsException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -13,18 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
* Represents an ACE that provides auditing information.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public interface AuditableAccessControlEntry extends AccessControlEntry {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
boolean isAuditFailure();
|
||||
|
||||
boolean isAuditSuccess();
|
||||
|
||||
}
|
||||
|
||||
@@ -13,16 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
* A mutable ACL that provides audit capabilities.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public interface AuditableAcl extends MutableAcl {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
|
||||
|
||||
}
|
||||
|
||||
+7
-5
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
@@ -22,9 +21,12 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class ChildrenExistException extends AclDataAccessException {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>ChildrenExistException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public ChildrenExistException(String msg) {
|
||||
@@ -34,11 +36,11 @@ public class ChildrenExistException extends AclDataAccessException {
|
||||
/**
|
||||
* Constructs an <code>ChildrenExistException</code> with the specified message and
|
||||
* root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause root cause
|
||||
* @param t root cause
|
||||
*/
|
||||
public ChildrenExistException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
public ChildrenExistException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -27,35 +26,41 @@ import java.io.Serializable;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface MutableAcl extends Acl {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
void deleteAce(int aceIndex) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
|
||||
*
|
||||
* @return the identifier, or <tt>null</tt> if unsaved
|
||||
*/
|
||||
Serializable getId();
|
||||
|
||||
void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting) throws NotFoundException;
|
||||
void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Changes the present owner to a different owner.
|
||||
*
|
||||
* @param newOwner the new owner (mandatory; cannot be null)
|
||||
*/
|
||||
void setOwner(Sid newOwner);
|
||||
|
||||
/**
|
||||
* Change the value returned by {@link Acl#isEntriesInheriting()}.
|
||||
*
|
||||
* @param entriesInheriting the new value
|
||||
*/
|
||||
void setEntriesInheriting(boolean entriesInheriting);
|
||||
|
||||
/**
|
||||
* Changes the parent of this ACL.
|
||||
*
|
||||
* @param newParent the new parent
|
||||
*/
|
||||
void setParent(Acl newParent);
|
||||
|
||||
void updateAce(int aceIndex, Permission permission) throws NotFoundException;
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
@@ -22,32 +21,41 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface MutableAclService extends AclService {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Creates an empty <code>Acl</code> object in the database. It will have no entries.
|
||||
* The returned object will then be used to add entries.
|
||||
*
|
||||
* @param objectIdentity the object identity to create
|
||||
*
|
||||
* @return an ACL object with its ID set
|
||||
*
|
||||
* @throws AlreadyExistsException if the passed object identity already has a record
|
||||
*/
|
||||
MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException;
|
||||
|
||||
/**
|
||||
* Removes the specified entry from the database.
|
||||
*
|
||||
* @param objectIdentity the object identity to remove
|
||||
* @param deleteChildren whether to cascade the delete to children
|
||||
*
|
||||
* @throws ChildrenExistException if the deleteChildren argument was
|
||||
* <code>false</code> but children exist
|
||||
*/
|
||||
void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException;
|
||||
void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
|
||||
throws ChildrenExistException;
|
||||
|
||||
/**
|
||||
* Changes an existing <code>Acl</code> in the database.
|
||||
*
|
||||
* @param acl to modify
|
||||
*
|
||||
* @throws NotFoundException if the relevant record could not be found (did you
|
||||
* remember to use {@link #createAcl(ObjectIdentity)} to create the object, rather
|
||||
* than creating it with the <code>new</code> keyword?)
|
||||
*/
|
||||
MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
@@ -22,9 +21,12 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class NotFoundException extends AclDataAccessException {
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public NotFoundException(String msg) {
|
||||
@@ -34,11 +36,11 @@ public class NotFoundException extends AclDataAccessException {
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message and root
|
||||
* cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param cause root cause
|
||||
* @param t root cause
|
||||
*/
|
||||
public NotFoundException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
public NotFoundException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -33,13 +32,15 @@ import java.io.Serializable;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface ObjectIdentity extends Serializable {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* @param obj to be compared
|
||||
*
|
||||
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
@@ -52,6 +53,7 @@ public interface ObjectIdentity extends Serializable {
|
||||
* identifier with business meaning, as that business meaning may change in the future
|
||||
* such change will cascade to the ACL subsystem data.
|
||||
* </p>
|
||||
*
|
||||
* @return the identifier (unique within this <tt>type</tt>; never <tt>null</tt>)
|
||||
*/
|
||||
Serializable getIdentifier();
|
||||
@@ -60,6 +62,7 @@ public interface ObjectIdentity extends Serializable {
|
||||
* Obtains the "type" metadata for the domain object. This will often be a Java type
|
||||
* name (an interface or a class) – traditionally it is the name of the domain
|
||||
* object implementation class.
|
||||
*
|
||||
* @return the "type" of the domain object (never <tt>null</tt>).
|
||||
*/
|
||||
String getType();
|
||||
@@ -68,7 +71,5 @@ public interface ObjectIdentity extends Serializable {
|
||||
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
||||
* @see Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -31,6 +30,7 @@ import java.io.Serializable;
|
||||
public interface ObjectIdentityGenerator {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id the identifier of the domain object, not null
|
||||
* @param type the type of the object (often a class name), not null
|
||||
* @return the identity constructed using the supplied identifier and type
|
||||
|
||||
+3
-1
@@ -21,9 +21,11 @@ package org.springframework.security.acls.model;
|
||||
* will be returned for a particular domain object
|
||||
*
|
||||
* @author Ben Alex
|
||||
*
|
||||
*/
|
||||
public interface ObjectIdentityRetrievalStrategy {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
ObjectIdentity getObjectIdentity(Object domainObject);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
@@ -26,8 +25,8 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface OwnershipAcl extends MutableAcl {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@Override
|
||||
void setOwner(Sid newOwner);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -24,15 +23,19 @@ import java.io.Serializable;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface Permission extends Serializable {
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
char RESERVED_ON = '~';
|
||||
|
||||
char RESERVED_OFF = '.';
|
||||
|
||||
String THIRTY_TWO_RESERVED_OFF = "................................";
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Returns the bits that represents the permission.
|
||||
*
|
||||
* @return the bits that represent the permission
|
||||
*/
|
||||
int getMask();
|
||||
@@ -53,8 +56,8 @@ public interface Permission extends Serializable {
|
||||
* This method is only used for user interface and logging purposes. It is not used in
|
||||
* any permission calculations. Therefore, duplication of characters within the output
|
||||
* is permitted.
|
||||
*
|
||||
* @return a 32-character bit pattern
|
||||
*/
|
||||
String getPattern();
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.util.List;
|
||||
@@ -28,9 +27,10 @@ import java.util.List;
|
||||
public interface PermissionGrantingStrategy {
|
||||
|
||||
/**
|
||||
* Returns true if the supplied strategy decides that the supplied {@code Acl} grants
|
||||
* access based on the supplied list of permissions and sids.
|
||||
* Returns true if the supplied strategy decides that the supplied {@code Acl}
|
||||
* grants access based on the supplied list of permissions and sids.
|
||||
*/
|
||||
boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode);
|
||||
boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids,
|
||||
boolean administrativeMode);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -32,22 +31,24 @@ import java.io.Serializable;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface Sid extends Serializable {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Refer to the <code>java.lang.Object</code> documentation for the interface
|
||||
* contract.
|
||||
*
|
||||
* @param obj to be compared
|
||||
*
|
||||
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Refer to the <code>java.lang.Object</code> documentation for the interface
|
||||
* contract.
|
||||
*
|
||||
* @return a hash code representation of this object
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface SidRetrievalStrategy {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
List<Sid> getSids(Authentication authentication);
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user