Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 82d140ffb1 | |||
| 1563491322 | |||
| b688bb69ee | |||
| 36f008643d | |||
| cbdf77e991 | |||
| 399e921d14 | |||
| c458311d2d | |||
| d6f408e8bf | |||
| 1739628e6a | |||
| 8e68fa1334 | |||
| 82cd72768d | |||
| 161710cc87 | |||
| dc1b652512 | |||
| ed9411c660 | |||
| e58f982351 | |||
| 072b73354f | |||
| 443231d1e8 | |||
| 45674a16ea | |||
| a1b124def5 | |||
| f6abc24ed6 | |||
| 1a9b7e1b6f | |||
| 8b5c70951d | |||
| c891ab45ec | |||
| 657a69b906 | |||
| 3b8fbe8bee | |||
| 4ad85cdfdf | |||
| 845c50a1c3 | |||
| 25d222208d | |||
| 9b0c21dfef | |||
| 8301bd6276 | |||
| 1872d94aa1 | |||
| 46611872db | |||
| b6cbdde0cb | |||
| 71e1702224 | |||
| 80ccd2b285 | |||
| 02c1f02f2a | |||
| 21a664b2eb | |||
| 9a2d0c2cb5 | |||
| 73b62497a3 | |||
| 09aba3906c | |||
| 57cfff6f5c | |||
| b7b6b2bac7 | |||
| 8602ae3863 | |||
| 8737fe3acb | |||
| 27faad3402 | |||
| aaa7bd90b2 | |||
| 295e0ded18 | |||
| 304f12fb63 | |||
| 8cbe232fbf | |||
| 5ac106808e | |||
| 8c605516b3 | |||
| e6e168f127 | |||
| 6d6c2d31ef | |||
| 8f6aecac9b | |||
| 0760bb947b | |||
| 9d2e2ca11d | |||
| 6354c7e052 | |||
| 42cdaa0ce2 | |||
| eda60b72b1 | |||
| 0d198d42ae | |||
| f000aaa7e8 | |||
| 634e340d80 | |||
| 4c8e9e2d7e | |||
| e518adbef1 | |||
| 59b69f6f48 | |||
| b8e50c0933 | |||
| 677576ea8b | |||
| 91153df78d | |||
| 1b0ac9c785 | |||
| 8c9159f273 | |||
| 4c8b0faa88 | |||
| 5a5b62e2cb | |||
| 6ac8588144 | |||
| 5690f1c581 | |||
| 87cf27ab7c | |||
| 41e06152b3 | |||
| a7e21318bf | |||
| bc6aae132b | |||
| b46ae6ac62 | |||
| 317da55cd0 | |||
| 9e751e22c8 | |||
| 4d65b35827 | |||
| 9831980bc2 |
@@ -1,22 +0,0 @@
|
|||||||
# EditorConfig for Spring Security
|
|
||||||
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc#mind-the-whitespace
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
max_line_length = 120
|
|
||||||
|
|
||||||
[*.{java,xml}]
|
|
||||||
indent_style = tab
|
|
||||||
indent_size = 4
|
|
||||||
charset = utf-8
|
|
||||||
continuation_indent_size = 8
|
|
||||||
|
|
||||||
ij_smart_tabs = false
|
|
||||||
ij_java_align_multiline_parameters = false
|
|
||||||
|
|
||||||
[*.gradle]
|
|
||||||
indent_style = tab
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Normalize line endings to auto.
|
|
||||||
* text auto
|
|
||||||
|
|
||||||
# Ensure that line endings for DOS batch files are not modified.
|
|
||||||
*.bat -text
|
|
||||||
|
|
||||||
# Ensure the following are treated as binary.
|
|
||||||
*.cer binary
|
|
||||||
*.graffle binary
|
|
||||||
*.jar binary
|
|
||||||
*.jpeg binary
|
|
||||||
*.jpg binary
|
|
||||||
*.keystore binary
|
|
||||||
*.odg binary
|
|
||||||
*.otg binary
|
|
||||||
*.png binary
|
|
||||||
*.hsx binary
|
|
||||||
*.serialized binary
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<!--
|
|
||||||
For Security Vulnerabilities, please use https://spring.io/security-policy
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please provide a high level summary of the issue you are having
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Actual Behavior
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please describe step by step the behavior you are observing
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Expected Behavior
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please describe step by step the behavior you expect
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please provide any configuration you have.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Version
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please describe what version you are using. Does the problem occur in other versions?
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Sample
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Providing a complete sample (i.e. link to a github repository) will give this issue higher
|
|
||||||
priority than issues that do not have a complete sample
|
|
||||||
-->
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug
|
|
||||||
about: Create a bug report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: 'status: waiting-for-triage, type: bug'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Do NOT report Security Vulnerabilities here. Please use https://github.com/spring-projects/spring-security/security/policy
|
|
||||||
-->
|
|
||||||
|
|
||||||
**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 +0,0 @@
|
|||||||
<!--
|
|
||||||
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-).
|
|
||||||
-->
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
require:
|
|
||||||
members: false
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
version: 2
|
|
||||||
registries:
|
|
||||||
spring-milestones:
|
|
||||||
type: maven-repository
|
|
||||||
url: https://repo.spring.io/milestone
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: gradle
|
|
||||||
target-branch: 6.4.x
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
time: '03:00'
|
|
||||||
timezone: Etc/UTC
|
|
||||||
labels:
|
|
||||||
- 'type: dependency-upgrade'
|
|
||||||
registries:
|
|
||||||
- spring-milestones
|
|
||||||
ignore:
|
|
||||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
|
||||||
- dependency-name: org.python:jython
|
|
||||||
- dependency-name: org.apache.directory.server:*
|
|
||||||
- dependency-name: org.apache.directory.shared:*
|
|
||||||
- dependency-name: org.junit:junit-bom
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- dependency-name: org.mockito:mockito-bom
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- dependency-name: '*'
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- version-update:semver-minor
|
|
||||||
- package-ecosystem: gradle
|
|
||||||
target-branch: 6.3.x
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
time: '03:00'
|
|
||||||
timezone: Etc/UTC
|
|
||||||
labels:
|
|
||||||
- 'type: dependency-upgrade'
|
|
||||||
registries:
|
|
||||||
- spring-milestones
|
|
||||||
ignore:
|
|
||||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
|
||||||
- dependency-name: org.python:jython
|
|
||||||
- dependency-name: org.apache.directory.server:*
|
|
||||||
- dependency-name: org.apache.directory.shared:*
|
|
||||||
- dependency-name: org.junit:junit-bom
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- dependency-name: org.mockito:mockito-bom
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- dependency-name: '*'
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- version-update:semver-minor
|
|
||||||
- package-ecosystem: gradle
|
|
||||||
target-branch: main
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
time: '03:00'
|
|
||||||
timezone: Etc/UTC
|
|
||||||
labels:
|
|
||||||
- 'type: dependency-upgrade'
|
|
||||||
registries:
|
|
||||||
- spring-milestones
|
|
||||||
ignore:
|
|
||||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
|
||||||
- dependency-name: org.python:jython
|
|
||||||
- dependency-name: org.apache.directory.server:*
|
|
||||||
- dependency-name: org.apache.directory.shared:*
|
|
||||||
- dependency-name: org.junit:junit-bom
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- dependency-name: org.mockito:mockito-bom
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- dependency-name: com.gradle.enterprise
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- version-update:semver-minor
|
|
||||||
- dependency-name: '*'
|
|
||||||
update-types:
|
|
||||||
- version-update:semver-major
|
|
||||||
- version-update:semver-minor
|
|
||||||
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
target-branch: 6.3.x
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
ignore:
|
|
||||||
- dependency-name: sjohnr/*
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
target-branch: docs-build
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
|
|
||||||
- package-ecosystem: npm
|
|
||||||
target-branch: docs-build
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
|
|
||||||
- package-ecosystem: npm
|
|
||||||
target-branch: main
|
|
||||||
directory: /docs
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
- package-ecosystem: npm
|
|
||||||
target-branch: 6.3.x
|
|
||||||
directory: /docs
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
labels:
|
|
||||||
- 'type: task'
|
|
||||||
- 'in: build'
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
name: Clean build artifacts
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
|
||||||
permissions:
|
|
||||||
contents: none
|
|
||||||
steps:
|
|
||||||
- name: Delete artifacts in cron job
|
|
||||||
env:
|
|
||||||
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "Running clean build artifacts logic"
|
|
||||||
output=$(curl -X GET -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts | grep '"id"' | cut -d : -f2 | sed 's/,*$//g')
|
|
||||||
echo Output is $output
|
|
||||||
for id in $output; do curl -X DELETE -H "Authorization: token $GH_ACTIONS_REPO_TOKEN" https://api.github.com/repos/spring-projects/spring-security/actions/artifacts/$id; done;
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
name: "CodeQL Advanced"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule
|
|
||||||
- cron: '0 5 * * *'
|
|
||||||
permissions: read-all
|
|
||||||
jobs:
|
|
||||||
codeql-analysis-call:
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
security-events: write
|
|
||||||
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@e415dadd0910c901e7a7fabd67bbb355b2324500 # 1
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- "dependabot/**"
|
|
||||||
schedule:
|
|
||||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
|
||||||
workflow_dispatch: # Manual trigger
|
|
||||||
|
|
||||||
env:
|
|
||||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/build.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ ubuntu-latest, windows-latest ]
|
|
||||||
jdk: [ 17 ]
|
|
||||||
with:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
java-version: ${{ matrix.jdk }}
|
|
||||||
distribution: temurin
|
|
||||||
secrets: inherit
|
|
||||||
test:
|
|
||||||
name: Test Against Snapshots
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/test.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- java-version: 21-ea
|
|
||||||
toolchain: 21
|
|
||||||
- java-version: 17
|
|
||||||
toolchain: 17
|
|
||||||
with:
|
|
||||||
java-version: ${{ matrix.java-version }}
|
|
||||||
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=6.2.+ -PreactorVersion=2023.0.+ -PspringDataVersion=2024.0.+ -PmicrometerVersion=1.15.+ --stacktrace
|
|
||||||
secrets: inherit
|
|
||||||
check-samples:
|
|
||||||
name: Check Samples
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.repository_owner == 'spring-projects' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
- name: Set up gradle
|
|
||||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
|
||||||
with:
|
|
||||||
java-version: 17
|
|
||||||
distribution: temurin
|
|
||||||
- name: Check samples project
|
|
||||||
env:
|
|
||||||
LOCAL_REPOSITORY_PATH: ${{ github.workspace }}/build/publications/repos
|
|
||||||
SAMPLES_DIR: ../spring-security-samples
|
|
||||||
run: |
|
|
||||||
# Extract version from gradle.properties
|
|
||||||
version=$(cat gradle.properties | grep "version=" | awk -F'=' '{print $2}')
|
|
||||||
# Extract samplesBranch from gradle.properties
|
|
||||||
samples_branch=$(cat gradle.properties | grep "samplesBranch=" | awk -F'=' '{print $2}')
|
|
||||||
./gradlew publishMavenJavaPublicationToLocalRepository
|
|
||||||
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR"
|
|
||||||
./gradlew --refresh-dependencies --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" test integrationTest
|
|
||||||
deploy-artifacts:
|
|
||||||
name: Deploy Artifacts
|
|
||||||
needs: [ build, test, check-samples ]
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
|
||||||
secrets: inherit
|
|
||||||
deploy-schema:
|
|
||||||
name: Deploy Schema
|
|
||||||
needs: [ build, test, check-samples ]
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
|
||||||
secrets: inherit
|
|
||||||
perform-release:
|
|
||||||
name: Perform Release
|
|
||||||
needs: [ deploy-artifacts, deploy-schema ]
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
|
|
||||||
project-version: ${{ needs.deploy-artifacts.outputs.project-version }}
|
|
||||||
milestone-repo-url: https://repo.spring.io/artifactory/milestone
|
|
||||||
release-repo-url: https://repo1.maven.org/maven2
|
|
||||||
artifact-path: org/springframework/security/spring-security-core
|
|
||||||
slack-announcing-id: spring-security-announcing
|
|
||||||
secrets: inherit
|
|
||||||
send-notification:
|
|
||||||
name: Send Notification
|
|
||||||
needs: [ perform-release ]
|
|
||||||
if: ${{ !success() }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Notification
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
name: Defer Issues
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
defer-issues:
|
|
||||||
name: Defer Issues
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository_owner == 'spring-projects'
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
- name: Compute Version
|
|
||||||
id: compute-version
|
|
||||||
uses: spring-io/spring-release-actions/compute-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
|
|
||||||
- name: Get Today's Release Version
|
|
||||||
id: todays-release
|
|
||||||
uses: spring-io/spring-release-actions/get-todays-release-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
|
|
||||||
with:
|
|
||||||
snapshot-version: ${{ steps.compute-version.outputs.version }}
|
|
||||||
milestone-repository: ${{ github.repository }}
|
|
||||||
milestone-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Compute Next Version
|
|
||||||
id: next-version
|
|
||||||
uses: spring-io/spring-release-actions/compute-next-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
|
|
||||||
with:
|
|
||||||
version: ${{ steps.todays-release.outputs.release-version }}
|
|
||||||
- name: Schedule Next Milestone
|
|
||||||
uses: spring-io/spring-release-actions/schedule-milestone@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
|
|
||||||
with:
|
|
||||||
version: ${{ steps.next-version.outputs.version }}
|
|
||||||
version-date: ${{ steps.next-version.outputs.version-date }}
|
|
||||||
repository: ${{ github.repository }}
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Move Open Issues to Next Milestone
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
CURRENT_MILESTONE: ${{ steps.todays-release.outputs.release-version }}
|
|
||||||
NEXT_MILESTONE: ${{ steps.next-version.outputs.version }}
|
|
||||||
run: |
|
|
||||||
current_milestone_number=$(gh api repos/${{ github.repository }}/milestones \
|
|
||||||
--jq ".[] | select(.title == \"$CURRENT_MILESTONE\") | .number")
|
|
||||||
if [ -z "$current_milestone_number" ]; then
|
|
||||||
echo "No milestone found for $CURRENT_MILESTONE"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
next_milestone_number=$(gh api repos/${{ github.repository }}/milestones \
|
|
||||||
--jq ".[] | select(.title == \"$NEXT_MILESTONE\") | .number")
|
|
||||||
if [ -z "$next_milestone_number" ]; then
|
|
||||||
echo "No milestone found for $NEXT_MILESTONE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Moving open issues from milestone '$CURRENT_MILESTONE' (#$current_milestone_number) to '$NEXT_MILESTONE' (#$next_milestone_number)"
|
|
||||||
page=1
|
|
||||||
while true; do
|
|
||||||
issues=$(gh api "repos/${{ github.repository }}/issues?milestone=$current_milestone_number&state=open&per_page=100&page=$page" \
|
|
||||||
--jq '.[].number')
|
|
||||||
if [ -z "$issues" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
for issue in $issues; do
|
|
||||||
echo "Moving issue/PR #$issue to milestone $NEXT_MILESTONE"
|
|
||||||
gh api repos/${{ github.repository }}/issues/$issue \
|
|
||||||
--method PATCH \
|
|
||||||
--field milestone=$next_milestone_number \
|
|
||||||
--silent
|
|
||||||
done
|
|
||||||
page=$((page + 1))
|
|
||||||
done
|
|
||||||
echo "Done."
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
name: Deploy Docs
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches-ignore:
|
|
||||||
- "gh-pages"
|
|
||||||
- "dependabot/**"
|
|
||||||
tags: '**'
|
|
||||||
repository_dispatch:
|
|
||||||
types: request-build-reference # legacy
|
|
||||||
#schedule:
|
|
||||||
#- cron: '0 10 * * *' # Once per day at 10am UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
permissions: read-all
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository_owner == 'spring-projects'
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
with:
|
|
||||||
ref: docs-build
|
|
||||||
fetch-depth: 1
|
|
||||||
- name: Dispatch (partial build)
|
|
||||||
if: github.ref_type == 'branch'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}
|
|
||||||
- name: Dispatch (full build)
|
|
||||||
if: github.ref_type == 'tag'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
name: Execute Gradle Wrapper Upgrade
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 2 * * *' # 2am UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
jobs:
|
|
||||||
upgrade_wrapper:
|
|
||||||
name: Execution
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Set up Git configuration
|
|
||||||
env:
|
|
||||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
git config --global url."https://unused-username:${TOKEN}@github.com/".insteadOf "https://github.com/"
|
|
||||||
git config --global user.name 'github-actions[bot]'
|
|
||||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
- name: Set up JDK 17
|
|
||||||
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
- name: Set up Gradle
|
|
||||||
uses: gradle/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
|
|
||||||
- name: Upgrade Wrappers
|
|
||||||
run: ./gradlew clean upgradeGradleWrapperAll --continue -Porg.gradle.java.installations.auto-download=false
|
|
||||||
env:
|
|
||||||
WRAPPER_UPGRADE_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
name: Check Milestone
|
|
||||||
on:
|
|
||||||
milestone:
|
|
||||||
types: [created, opened, edited]
|
|
||||||
env:
|
|
||||||
DUE_ON: ${{ github.event.milestone.due_on }}
|
|
||||||
TITLE: ${{ github.event.milestone.title }}
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
|
||||||
spring-releasetrain-checks:
|
|
||||||
name: Check DueOn is on a Release Date
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
|
||||||
permissions:
|
|
||||||
contents: none
|
|
||||||
steps:
|
|
||||||
- name: Print Milestone Being Checked
|
|
||||||
run: echo "Validating DueOn '$DUE_ON' for milestone '$TITLE'"
|
|
||||||
- name: Validate DueOn
|
|
||||||
if: env.DUE_ON != ''
|
|
||||||
run: |
|
|
||||||
export TOOL_VERSION=0.1.1
|
|
||||||
wget "https://repo.maven.apache.org/maven2/io/spring/releasetrain/spring-release-train-tools/$TOOL_VERSION/spring-release-train-tools-$TOOL_VERSION.jar"
|
|
||||||
java -cp "spring-release-train-tools-$TOOL_VERSION.jar" io.spring.releasetrain.CheckMilestoneDueOnMain --dueOn "$DUE_ON" --expectedDayOfWeek MONDAY --expectedMondayCount 3
|
|
||||||
send-notification:
|
|
||||||
name: Send Notification
|
|
||||||
needs: [ spring-releasetrain-checks ]
|
|
||||||
if: ${{ failure() || cancelled() }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Notification
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
name: PR Build
|
|
||||||
|
|
||||||
on: pull_request
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
- name: Set up gradle
|
|
||||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan
|
|
||||||
generate-docs:
|
|
||||||
name: Generate Docs
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.repository == 'spring-projects/spring-security' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
- name: Set up gradle
|
|
||||||
uses: spring-io/spring-gradle-build-action@c8668747d7c264864c8c7f7026d0d277d14a78dc # v2.0.6
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
- name: Run Antora
|
|
||||||
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
|
|
||||||
- name: Upload Docs
|
|
||||||
id: upload
|
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
||||||
with:
|
|
||||||
name: docs
|
|
||||||
path: docs/build/site
|
|
||||||
overwrite: true
|
|
||||||
send-notification:
|
|
||||||
name: Send Notification
|
|
||||||
needs: [ build, generate-docs ]
|
|
||||||
if: ${{ failure() && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'spring-projects/spring-security' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Notification
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
name: Release Scheduler
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '15 15 * * MON' # Every Monday at 3:15pm UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
permissions: read-all
|
|
||||||
jobs:
|
|
||||||
dispatch_scheduled_releases:
|
|
||||||
name: Dispatch scheduled releases
|
|
||||||
if: github.repository_owner == 'spring-projects'
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
# List of active maintenance branches.
|
|
||||||
branch: [ main, 6.4.x, 6.3.x ]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
- name: Dispatch
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
|
|
||||||
run: gh workflow run update-scheduled-release-version.yml -r ${{ matrix.branch }}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
name: Update Antora UI Spring
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 10 * * *' # Once per day at 10am UTC
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
issues: write
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-antora-ui-spring:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Update on Supported Branches
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ]
|
|
||||||
steps:
|
|
||||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
|
|
||||||
name: Update
|
|
||||||
with:
|
|
||||||
docs-branch: ${{ matrix.branch }}
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
antora-file-path: 'docs/antora-playbook.yml'
|
|
||||||
update-antora-ui-spring-docs-build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Update on docs-build
|
|
||||||
steps:
|
|
||||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@415e2b11a766ba64799fffb5c97a4f7e17f677cf # v0.0.22
|
|
||||||
name: Update
|
|
||||||
with:
|
|
||||||
docs-branch: 'docs-build'
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
name: Update Scheduled Release Version
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch: # Manual trigger only. Triggered by release-scheduler.yml on main.
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-scheduled-release-version:
|
|
||||||
name: Update Scheduled Release Version
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/workflows/update-scheduled-release-version.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
secrets: inherit
|
|
||||||
send-notification:
|
|
||||||
name: Send Notification
|
|
||||||
needs: [ update-scheduled-release-version ]
|
|
||||||
if: ${{ failure() || cancelled() }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Notification
|
|
||||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
|
|
||||||
with:
|
|
||||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
|
||||||
+7
-23
@@ -1,32 +1,16 @@
|
|||||||
classes/
|
|
||||||
target/
|
target/
|
||||||
*/src/*/java/META-INF
|
|
||||||
*/src/META-INF/
|
|
||||||
*/src/*/java/META-INF/
|
|
||||||
.classpath
|
.classpath
|
||||||
.springBeans
|
|
||||||
.project
|
.project
|
||||||
.DS_Store
|
|
||||||
.settings/
|
.settings/
|
||||||
.idea/*
|
|
||||||
out/
|
|
||||||
bin/
|
|
||||||
intellij/
|
|
||||||
build/
|
build/
|
||||||
*.log
|
out/
|
||||||
*.log.*
|
intellij/
|
||||||
*.iml
|
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
|
*.log
|
||||||
|
*.log.1
|
||||||
|
.DS_Store
|
||||||
|
*.iml
|
||||||
.gradle/
|
.gradle/
|
||||||
|
gradle.properties
|
||||||
atlassian-ide-plugin.xml
|
atlassian-ide-plugin.xml
|
||||||
!etc/eclipse/.checkstyle
|
|
||||||
.checkstyle
|
|
||||||
s101plugin.state
|
|
||||||
.attach_pid*
|
|
||||||
.~lock.*#
|
|
||||||
|
|
||||||
!.idea/checkstyle-idea.xml
|
|
||||||
!.idea/externalDependencies.xml
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
|
|||||||
Generated
-16
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CheckStyle-IDEA">
|
|
||||||
<option name="configuration">
|
|
||||||
<map>
|
|
||||||
<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="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>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Use sdkman to run "sdk env" to initialize with correct JDK version
|
|
||||||
# Enable auto-env through the sdkman_auto_env config
|
|
||||||
# See https://sdkman.io/usage#config
|
|
||||||
# A summary is to add the following to ~/.sdkman/etc/config
|
|
||||||
# sdkman_auto_env=true
|
|
||||||
java=17.0.3-tem
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"java.import.gradle.enabled": false
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
= Contributing to Spring Security
|
|
||||||
|
|
||||||
First off, thank you for taking the time to contribute! :+1: :tada:
|
|
||||||
|
|
||||||
== Table of Contents
|
|
||||||
|
|
||||||
* <<code-of-conduct>>
|
|
||||||
* <<how-to-contribute>>
|
|
||||||
* <<ask-questions>>
|
|
||||||
* <<find-an-issue>>
|
|
||||||
* <<create-an-issue>>
|
|
||||||
* <<issue-lifecycle>>
|
|
||||||
* <<submit-a-pull-request>>
|
|
||||||
* <<build-from-source>>
|
|
||||||
* <<code-style>>
|
|
||||||
|
|
||||||
[[code-of-conduct]]
|
|
||||||
== Code of Conduct
|
|
||||||
|
|
||||||
This project is governed by the https://github.com/spring-projects/.github/blob/main/CODE_OF_CONDUCT.md[Spring code of conduct].
|
|
||||||
By participating you are expected to uphold this code.
|
|
||||||
Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
|
||||||
|
|
||||||
[[how-to-contribute]]
|
|
||||||
== How to Contribute
|
|
||||||
|
|
||||||
[[ask-questions]]
|
|
||||||
=== Ask Questions
|
|
||||||
|
|
||||||
If you have a question, check Stack Overflow using
|
|
||||||
https://stackoverflow.com/questions/tagged/spring-security+or+spring-ldap+or+spring-authorization-server+or+spring-session?tab=Newest[this list of tags].
|
|
||||||
Find an existing discussion, or start a new one if necessary.
|
|
||||||
|
|
||||||
If you believe there is an issue, search through https://github.com/spring-projects/spring-security/issues[existing issues] trying a few different ways to find discussions, past or current, that are related to the issue.
|
|
||||||
Reading those discussions helps you to learn about the issue, and helps us to make a decision.
|
|
||||||
|
|
||||||
[[find-an-issue]]
|
|
||||||
=== Find an Existing Issue
|
|
||||||
|
|
||||||
There are many issues in Spring Security with the labels https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+ideal-for-contribution%22[`ideal-for-contribution`] or https://github.com/spring-projects/spring-security/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+first-timers-only%22[`first-timers-only`] that are a great way to contribute to a discussion or <<submit-a-pull-request,to a PR>>.
|
|
||||||
You can volunteer by commenting on these tickets, and we will assign them to you.
|
|
||||||
|
|
||||||
[[create-an-issue]]
|
|
||||||
=== Create an Issue
|
|
||||||
|
|
||||||
Reporting an issue or making a feature request is a great way to contribute.
|
|
||||||
Your feedback and the conversations that result from it provide a continuous flow of ideas.
|
|
||||||
However, before creating a ticket, please take the time to <<ask-questions,ask and research>> first.
|
|
||||||
|
|
||||||
If you create an issue after a discussion on Stack Overflow, please provide a description in the issue instead of simply referring to Stack Overflow.
|
|
||||||
The issue tracker is an important place of record for design discussions and should be self-sufficient.
|
|
||||||
|
|
||||||
Once you're ready, create an issue on https://github.com/spring-projects/spring-security/issues[GitHub].
|
|
||||||
|
|
||||||
Many issues are caused by subtle behavior, typos, and unintended configuration.
|
|
||||||
Creating a https://stackoverflow.com/help/minimal-reproducible-example[Minimal Reproducible Example] (starting with https://start.spring.io for example) of the problem helps the team quickly triage your issue and get to the core of the problem.
|
|
||||||
|
|
||||||
We love contributors, and we may ask you to <<submit-a-pull-request,submit a PR with a fix>>.
|
|
||||||
|
|
||||||
[[issue-lifecycle]]
|
|
||||||
=== Issue Lifecycle
|
|
||||||
|
|
||||||
When an issue is first created, it is flagged `waiting-for-triage` waiting for a team member to triage it.
|
|
||||||
Once the issue has been reviewed, the team may ask for further information if needed, and based on the findings, the issue is either assigned a target branch (or no branch if a feature) or is closed with a specific status.
|
|
||||||
The target branch is https://spring.io/projects/spring-security#support[the earliest supported branch] where <<choose-a-branch,the change will be applied>>.
|
|
||||||
|
|
||||||
When a fix is ready, the issue is closed and may still be re-opened until the fix is released.
|
|
||||||
After that the issue will typically no longer be reopened.
|
|
||||||
In rare cases if the issue was not at all fixed, the issue may be re-opened.
|
|
||||||
In most cases however any follow-up reports will need to be created as new issues with a fresh description.
|
|
||||||
|
|
||||||
[[build-from-source]]
|
|
||||||
=== Build from Source
|
|
||||||
|
|
||||||
See https://github.com/spring-projects/spring-security/tree/main#building-from-source[Build from Source] for instructions on how to check out, build, and import the Spring Security source code into your IDE.
|
|
||||||
|
|
||||||
[[code-style]]
|
|
||||||
=== Source Code Style
|
|
||||||
|
|
||||||
The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.
|
|
||||||
|
|
||||||
To format the code as well as check the style, run `./gradlew format && ./gradlew check`.
|
|
||||||
|
|
||||||
[[submit-a-pull-request]]
|
|
||||||
=== Submit a Pull Request
|
|
||||||
|
|
||||||
We are excited for your pull request! :heart:
|
|
||||||
|
|
||||||
Please do your best to follow these steps.
|
|
||||||
Don't worry if you don't get them all correct the first time, we will help you.
|
|
||||||
|
|
||||||
1. [[sign-cla]] All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin.
|
|
||||||
For additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring].
|
|
||||||
2. [[create-an-issue-list]] Must you https://github.com/spring-projects/spring-security/issues/new/choose[create an issue] first? No, but it is recommended for features and larger bug fixes. It's easier discuss with the team first to determine the right fix or enhancement.
|
|
||||||
For typos and straightforward bug fixes, starting with a pull request is encouraged.
|
|
||||||
Please include a description for context and motivation.
|
|
||||||
Note that the team may close your pull request if it's not a fit for the project.
|
|
||||||
3. [[choose-a-branch]] Always check out the branch indicated in the milestone and submit pull requests against it (for example, for milestone `5.8.3` use the `5.8.x` branch).
|
|
||||||
If there is no milestone, choose `main`.
|
|
||||||
Once merged, the fix will be forwarded-ported to applicable branches including `main`.
|
|
||||||
4. [[create-a-local-branch]] Create a local branch
|
|
||||||
If this is for an issue, consider a branch name with the issue number, like `gh-22276`.
|
|
||||||
5. [[write-tests]] Add documentation and JUnit Tests for your changes.
|
|
||||||
6. [[update-copyright]] In all files you edited, if the copyright header is of the form 2002-20xx, update the final copyright year to the current year.
|
|
||||||
7. [[add-since]] If on `main`, add `@since` JavaDoc attributes to new public APIs that your PR adds
|
|
||||||
8. [[change-rnc]] If you are updating the XSD, please instead update the RNC file and then run `./gradlew :spring-security-config:rncToXsd`.
|
|
||||||
9. [[format-code]] For each commit, build the code using `./gradlew format && ./gradlew check`.
|
|
||||||
This command ensures the code meets most of <<code-style,the style guide>>; a notable exception is import order.
|
|
||||||
10. [[commit-atomically]] Choose the granularity of your commits consciously and squash commits that represent
|
|
||||||
multiple edits or corrections of the same logical change.
|
|
||||||
See https://git-scm.com/book/en/Git-Tools-Rewriting-History[Rewriting History section of Pro Git] for an overview of streamlining the commit history.
|
|
||||||
11. [[format-commit-messages]] Format commit messages using 55 characters for the subject line, 72 characters per line
|
|
||||||
for the description, followed by the issue fixed, for example, `Closes gh-22276`.
|
|
||||||
See the https://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines[Commit Guidelines section of Pro Git] for best practices around commit messages, and use `git log` to see some examples.
|
|
||||||
Favor imperative tense over present tense (use "Fix" instead of "Fixes"); avoid past tense (use "Fix" instead of "Fixed").
|
|
||||||
+
|
|
||||||
[indent=0]
|
|
||||||
----
|
|
||||||
Address NullPointerException
|
|
||||||
|
|
||||||
Closes gh-22276
|
|
||||||
----
|
|
||||||
[[reference-issue]]
|
|
||||||
1. If there is a prior issue, reference the GitHub issue number in the description of the pull request.
|
|
||||||
+
|
|
||||||
[indent=0]
|
|
||||||
----
|
|
||||||
Closes gh-22276
|
|
||||||
----
|
|
||||||
|
|
||||||
If accepted, your contribution may be heavily modified as needed prior to merging.
|
|
||||||
You will likely retain author attribution for your Git commits granted that the bulk of your changes remain intact.
|
|
||||||
You may also be asked to rework the submission.
|
|
||||||
|
|
||||||
If asked to make corrections, simply push the changes against the same branch, and your pull request will be updated.
|
|
||||||
In other words, you do not need to create a new pull request when asked to make changes.
|
|
||||||
When it is time to merge, you'll be asked to squash your commits.
|
|
||||||
|
|
||||||
==== Participate in Reviews
|
|
||||||
|
|
||||||
Helping to review pull requests is another great way to contribute.
|
|
||||||
Your feedback can help to shape the implementation of new features.
|
|
||||||
When reviewing pull requests, however, please refrain from approving or rejecting a PR unless you are a core committer for Spring Security.
|
|
||||||
-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.
|
|
||||||
-101
@@ -1,101 +0,0 @@
|
|||||||
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]
|
|
||||||
|
|
||||||
image:https://github.com/spring-projects/spring-security/actions/workflows/continuous-integration-workflow.yml/badge.svg?branch=main["Build Status", link="https://github.com/spring-projects/spring-security/actions/workflows/continuous-integration-workflow.yml"]
|
|
||||||
|
|
||||||
image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=spring-security"]
|
|
||||||
|
|
||||||
= Spring Security
|
|
||||||
|
|
||||||
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 6.0 requires Spring 6.0 as
|
|
||||||
a minimum and also requires Java 17.
|
|
||||||
|
|
||||||
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/main/CODE_OF_CONDUCT.md[code of conduct]
|
|
||||||
|
|
||||||
== Downloading Artifacts
|
|
||||||
See https://docs.spring.io/spring-security/reference/getting-spring-security.html[Getting Spring Security] for how to obtain Spring Security.
|
|
||||||
|
|
||||||
== Documentation
|
|
||||||
Be sure to read the https://docs.spring.io/spring-security/reference/[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].
|
|
||||||
|
|
||||||
You may also want to check out https://docs.spring.io/spring-security/reference/whats-new.html[what's new in the latest release].
|
|
||||||
|
|
||||||
== Quick Start
|
|
||||||
See https://docs.spring.io/spring-security/reference/servlet/getting-started.html[Hello Spring Security] to get started with a "Hello, World" application.
|
|
||||||
|
|
||||||
== Building from Source
|
|
||||||
Spring Security uses a https://gradle.org[Gradle]-based build system.
|
|
||||||
In the instructions below, https://vimeo.com/34436402[`./gradlew`] is invoked from the root of the source tree and serves as
|
|
||||||
a cross-platform, self-contained bootstrap mechanism for the build.
|
|
||||||
|
|
||||||
=== Prerequisites
|
|
||||||
https://docs.github.com/en/get-started/quickstart/set-up-git[Git] and the https://www.oracle.com/java/technologies/downloads/#java17[JDK17 build].
|
|
||||||
|
|
||||||
Be sure that your `JAVA_HOME` environment variable points to the `jdk-17` folder extracted from the JDK download.
|
|
||||||
|
|
||||||
=== Check out sources
|
|
||||||
[indent=0]
|
|
||||||
----
|
|
||||||
git clone git@github.com:spring-projects/spring-security.git
|
|
||||||
----
|
|
||||||
|
|
||||||
=== Install all `spring-*.jar` into your local Maven repository.
|
|
||||||
|
|
||||||
[indent=0]
|
|
||||||
----
|
|
||||||
./gradlew publishToMavenLocal
|
|
||||||
----
|
|
||||||
|
|
||||||
=== Compile and test; build all JARs, distribution zips, and docs
|
|
||||||
|
|
||||||
[indent=0]
|
|
||||||
----
|
|
||||||
./gradlew build
|
|
||||||
----
|
|
||||||
|
|
||||||
The reference docs are not currently included in the distribution zip.
|
|
||||||
You can build the reference docs for this branch by running the following command:
|
|
||||||
|
|
||||||
----
|
|
||||||
./gradlew :spring-security-docs:antora
|
|
||||||
----
|
|
||||||
|
|
||||||
That command publishes the docs site to the `_docs/build/site_` directory.
|
|
||||||
The https://github.com/spring-projects/spring-security/tree/docs-build[playbook branch] describes how to build the reference docs in detail.
|
|
||||||
|
|
||||||
Discover more commands with `./gradlew tasks`.
|
|
||||||
|
|
||||||
=== IDE setup (IntelliJ)
|
|
||||||
|
|
||||||
No special steps are needed to open Spring Security in IntelliJ.
|
|
||||||
|
|
||||||
=== IDE setup (Eclipse and VS Code)
|
|
||||||
|
|
||||||
To work in Eclipse or VS Code, first generate Eclipse metadata so you can import the project into Eclipse or VS Code:
|
|
||||||
|
|
||||||
[indent=0]
|
|
||||||
----
|
|
||||||
./gradlew cleanEclipse eclipse
|
|
||||||
----
|
|
||||||
|
|
||||||
If you have not built the project yet, run `./gradlew publishToMavenLocal` first so dependencies are resolved.
|
|
||||||
|
|
||||||
*VS Code:* Open the repository root as a folder. The repository includes `.vscode/settings.json` which disables automatic Gradle import so that the generated Eclipse metadata (`.classpath`, `.project`) is used. Do not use the Gradle for Java extension to import the project.
|
|
||||||
|
|
||||||
*Eclipse:* File → Import → General → Existing Projects into Workspace, then select the repository root.
|
|
||||||
|
|
||||||
The build uses a custom Eclipse plugin to work around Gradle dependency cycles that confuse IDE metadata generation. You may see Eclipse warnings about `xml-apis` from some test dependencies; those are excluded in the build and can be ignored.
|
|
||||||
|
|
||||||
== Getting Support
|
|
||||||
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
|
|
||||||
https://spring.io/support[Commercial support] is available too.
|
|
||||||
|
|
||||||
== Contributing
|
|
||||||
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/main/CONTRIBUTING.adoc[contributor guidelines] for details.
|
|
||||||
|
|
||||||
== License
|
|
||||||
Spring Security is Open Source software released under the
|
|
||||||
https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
|
|
||||||
-266
@@ -1,266 +0,0 @@
|
|||||||
= Release Process
|
|
||||||
|
|
||||||
The release process for Spring Security is entirely automated via the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc[Spring Security Release Plugin] and https://github.com/spring-io/spring-security-release-tools/tree/main/.github/workflows[reusable workflows].
|
|
||||||
The following table outlines the steps that are taken by the automation.
|
|
||||||
|
|
||||||
WARNING: The `5.8.x` branch does not have all of the improvements from the `6.x.x` branches. See "Status (5.8.x)" for which steps are still manual.
|
|
||||||
|
|
||||||
In case of a failure, you can follow the links below to read about each step, which includes instructions for performing the step manually if applicable.
|
|
||||||
See <<frequently-asked-questions,FAQ>> for troubleshooting tips.
|
|
||||||
|
|
||||||
[cols="1,1,1"]
|
|
||||||
|===
|
|
||||||
| Step | Status (5.8.x) | Status (6.0.x+)
|
|
||||||
|
|
||||||
| <<update-dependencies>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<check-all-issues-are-closed>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<update-release-version>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<tag-release>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<push-release-commit>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<build-locally>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<update-release-notes-on-github>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<update-version-on-project-page>>
|
|
||||||
| :x: manual
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<close-create-milestone,Close milestone>>
|
|
||||||
| :x: manual
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<announce-release-on-slack>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<update-to-next-development-version>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<close-create-milestone,Create milestone>>
|
|
||||||
| :white_check_mark: automated
|
|
||||||
| :white_check_mark: automated
|
|
||||||
|
|
||||||
| <<announce-release-on-other-channels>>
|
|
||||||
| :x: manual
|
|
||||||
| :x: manual
|
|
||||||
|===
|
|
||||||
|
|
||||||
[#update-dependencies]
|
|
||||||
== Update dependencies
|
|
||||||
|
|
||||||
Dependency versions are managed in the file xref:./gradle/libs.versions.toml[libs.versions.toml] and are automatically updated by xref:./.github/dependabot.yml[dependabot].
|
|
||||||
|
|
||||||
[#check-all-issues-are-closed]
|
|
||||||
== Check all issues are closed
|
|
||||||
|
|
||||||
The first step of a release is to check if there are any open issues remaining in a milestone.
|
|
||||||
|
|
||||||
NOTE: A scheduled release will not proceed if there are any open issues.
|
|
||||||
|
|
||||||
TIP: If you need to prevent a release from occurring automatically, the easiest way to block a release is to add an unresolved issue to the milestone.
|
|
||||||
|
|
||||||
The https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#checkMilestoneHasNoOpenIssues[`checkMilestoneHasOpenIssues`] command will check if there are any open issues for the release.
|
|
||||||
Before running the command manually, replace the following values:
|
|
||||||
|
|
||||||
* `<next-version>` - Replace with the title of the milestone you are releasing now (i.e. 5.5.0-RC1)
|
|
||||||
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `public_repo`. This is optional since you are unlikely to reach the rate limit for such a simple check.
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./gradlew checkMilestoneHasOpenIssues -PnextVersion=<next-version> -PgitHubAccessToken=<github-personal-access-token>
|
|
||||||
----
|
|
||||||
|
|
||||||
Alternatively, you can manually check using the https://github.com/spring-projects/spring-security/milestones[milestones] page.
|
|
||||||
|
|
||||||
[#update-release-version]
|
|
||||||
== Update release version
|
|
||||||
|
|
||||||
If all issues for the release are <<check-all-issues-are-closed,closed>>, the version number is automatically updated using the milestone title.
|
|
||||||
When performing this step manually, update the version number in `gradle.properties` for the release (for example `5.5.0`) and commit the change using the message "Release x.y.z".
|
|
||||||
|
|
||||||
[#tag-release]
|
|
||||||
== Tag release
|
|
||||||
|
|
||||||
The release will automatically be tagged using the milestone title.
|
|
||||||
It is not required to tag manually.
|
|
||||||
However, you can perform this step manually by running the following command:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
git tag 5.5.0
|
|
||||||
----
|
|
||||||
|
|
||||||
[#push-release-commit]
|
|
||||||
== Push release commit
|
|
||||||
|
|
||||||
During a scheduled release, the release commit will automatically be pushed to trigger a build.
|
|
||||||
If performing this step manually, you can push the commit and tag and GitHub actions will build and deploy the artifacts with the following command:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
git push --atomic origin main 5.5.0
|
|
||||||
----
|
|
||||||
|
|
||||||
The build will automatically wait for artifacts to be released to Maven Central.
|
|
||||||
You can get notified manually when uploading is complete by running the following:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./scripts/release/wait-for-done.sh 5.5.0
|
|
||||||
----
|
|
||||||
|
|
||||||
[#build-locally]
|
|
||||||
== Build
|
|
||||||
|
|
||||||
All checks will automatically be performed by the build prior to uploading the artifacts to Maven Central.
|
|
||||||
If something goes wrong, you can run the build locally using:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./gradlew check
|
|
||||||
----
|
|
||||||
|
|
||||||
[#update-release-notes-on-github]
|
|
||||||
== Update release notes on GitHub
|
|
||||||
|
|
||||||
Once the release has been uploaded to Maven Central, release notes will automatically be generated and a GitHub release will be created.
|
|
||||||
To do this manually, you can use the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#generateChangelog[`generateChangelog`] command to generate the release notes by replacing:
|
|
||||||
|
|
||||||
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./gradlew generateChangelog -PnextVersion=<next-version>
|
|
||||||
----
|
|
||||||
|
|
||||||
Then copy the release notes to your clipboard (your mileage may vary with the following command):
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
cat build/changelog/release-notes.md | xclip -selection clipboard
|
|
||||||
----
|
|
||||||
|
|
||||||
Finally, create the
|
|
||||||
https://github.com/spring-projects/spring-security/releases[release on
|
|
||||||
GitHub], associate it with the tag, and paste the generated notes.
|
|
||||||
|
|
||||||
Alternatively, you can run the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#createGitHubRelease[`createGitHubRelease`] command to perform these steps automatically, replacing:
|
|
||||||
|
|
||||||
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
|
|
||||||
* `<branch>` - The name of the branch to be tagged (if the release commit has not already been tagged)
|
|
||||||
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `write:org`
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./gradlew createGitHubRelease -PnextVersion=<next-version> -Pbranch=<branch> -PcreateRelease=true -PgitHubAccessToken=<github-personal-access-token>
|
|
||||||
----
|
|
||||||
|
|
||||||
[#update-version-on-project-page]
|
|
||||||
== Update version on project page
|
|
||||||
|
|
||||||
The build will automatically update the project versions on https://spring.io/projects/spring-security#learn.
|
|
||||||
To do this manually, you can use the https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#createSaganRelease[`createSaganRelease`] and https://github.com/spring-io/spring-security-release-tools/blob/main/release-plugin/README.adoc#deleteSaganRelease[`deleteSaganRelease`] commands using the following parameters:
|
|
||||||
|
|
||||||
* `<next-version>` - Replace with the milestone you are releasing now (i.e. 5.5.0)
|
|
||||||
* `<previous-version>` - Replace with the previous release which will be removed from the listed versions (i.e. 5.5.0-RC1)
|
|
||||||
* `<github-personal-access-token>` - Replace with a https://github.com/settings/tokens[GitHub personal access token] that has a scope of `read:org` as https://spring.io/restdocs/index.html#authentication[documented for spring.io api]
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
./gradlew createSaganRelease deleteSaganRelease -PnextVersion=<next-version> -PpreviousVersion=<previous-version> -PgitHubAccessToken=<github-personal-access-token>
|
|
||||||
----
|
|
||||||
|
|
||||||
Alternatively, you can log into Contentful and update the versions manually on the Spring Security project page.
|
|
||||||
|
|
||||||
[#close-create-milestone]
|
|
||||||
== Close / Create milestone
|
|
||||||
|
|
||||||
The release milestone will be automatically closed once the release is complete.
|
|
||||||
To proceed manually, perform the following steps:
|
|
||||||
|
|
||||||
1. Visit https://github.com/spring-projects/spring-security/milestones[GitHub
|
|
||||||
Milestones] and create a new milestone for the next release version
|
|
||||||
2. Move any open issues from the existing milestone you just released to the new milestone
|
|
||||||
3. Close the milestone for the release
|
|
||||||
|
|
||||||
NOTE: Remember that scheduled releases <<check-all-issues-are-closed,will not proceed>> if there are still open issues in the milestone.
|
|
||||||
|
|
||||||
[#announce-release-on-slack]
|
|
||||||
== Announce release on Slack
|
|
||||||
|
|
||||||
The release will automatically be announced on Slack.
|
|
||||||
If proceeding manually, announce the release on Slack in the channel https://pivotal.slack.com/messages/spring-release[#spring-release], including the keyword `+spring-security-announcing+` in the message.
|
|
||||||
Something like:
|
|
||||||
|
|
||||||
....
|
|
||||||
spring-security-announcing `5.5.0` is available now
|
|
||||||
....
|
|
||||||
|
|
||||||
[#update-to-next-development-version]
|
|
||||||
== Update to next development version
|
|
||||||
|
|
||||||
After the release is complete and artifacts have been uploaded to Maven Central, the build will automatically update to the next development version, commit and push.
|
|
||||||
If proceeding manually, update the version in `gradle.properties` to the next `+SNAPSHOT+` version with the commit message "Next development version" and then push.
|
|
||||||
|
|
||||||
[#announce-release-on-other-channels]
|
|
||||||
== Announce release on other channels
|
|
||||||
|
|
||||||
* Create a blog post on Contentful
|
|
||||||
* Tweet from https://twitter.com/springsecurity[@SpringSecurity]
|
|
||||||
|
|
||||||
[[frequently-asked-questions]]
|
|
||||||
== Frequently Asked Questions
|
|
||||||
|
|
||||||
*When should I update dependencies manually?* Dependencies should be updated at the latest the end of the week prior to the release. This is usually the Friday following the 2nd Monday of the month (counting from the first week with a Monday). When in doubt, check the https://github.com/spring-projects/spring-security/milestones[milestones] page for release due dates.
|
|
||||||
|
|
||||||
*When do scheduled releases occur?* Automated releases are scheduled to occur at *3:15 PM UTC* on the *3rd Monday of the month* (counting from the first week with a Monday).
|
|
||||||
|
|
||||||
[NOTE]
|
|
||||||
The scheduled release process currently runs every Monday but only releases when a release is due. See the performed checks below for more information.
|
|
||||||
|
|
||||||
The automated release process occurs on the following branches:
|
|
||||||
|
|
||||||
* `main`
|
|
||||||
* `6.2.x`
|
|
||||||
* `6.1.x`
|
|
||||||
* `6.0.x` (commercial only)
|
|
||||||
* `5.8.x`
|
|
||||||
|
|
||||||
For each of the above branches, the automated process performs the following checks before proceeding with the release:
|
|
||||||
|
|
||||||
1. _Check if the milestone is due today._ This check compares the current (SNAPSHOT) version of the branch with available milestones and chooses the first match (sorted alphabetically). If the due date on the matched milestone is *not* today, the process stops.
|
|
||||||
2. _Check if all issues are closed._ This check uses the milestone from the previous step and looks for open issues. If any open issues are found, the process stops.
|
|
||||||
|
|
||||||
[IMPORTANT]
|
|
||||||
You should ensure all issues are closed or moved to another milestone prior to a scheduled release.
|
|
||||||
|
|
||||||
If the above checks pass, the version number is updated (in `gradle.properties`) and a commit is pushed to trigger the CI process.
|
|
||||||
|
|
||||||
*How do I trigger a release manually?* You can trigger a release manually in two ways:
|
|
||||||
|
|
||||||
1. Trigger a release for a particular branch via https://github.com/spring-projects/spring-security/actions/workflows/update-scheduled-release-version.yml[`update-scheduled-release-version.yml`] on the desired branch. The above checks are performed for that branch, and the release will proceed if all checks pass. _This is the recommended way to trigger a release that did not pass the above checks during a regularly scheduled release._
|
|
||||||
2. Trigger releases for all branches via https://github.com/spring-projects/spring-security/actions/workflows/release-scheduler.yml[`release-scheduler.yml`] on the `main` branch. The above checks are performed for each branch, and only releases that pass all checks will proceed.
|
|
||||||
|
|
||||||
*When should additional manual steps be performed?* All other automated steps listed above occur during the normal CI process. Additional manual steps can be performed at any time once the builds pass and releases are finished.
|
|
||||||
|
|
||||||
*What if something goes wrong?* If the normal CI process fails, you can retry by re-running the failed jobs with the "Re-run failed jobs" option in GitHub Actions. If changes are required, you should revert the "Release x.y.z" commit, delete the tag, and proceed manually.
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// Acl Module build file
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':spring-security-core'),
|
||||||
|
"net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||||
|
"org.springframework:spring-aop:$springVersion",
|
||||||
|
"org.springframework:spring-context:$springVersion",
|
||||||
|
"org.springframework:spring-tx:$springVersion",
|
||||||
|
"org.springframework:spring-jdbc:$springVersion"
|
||||||
|
|
||||||
|
testCompile "org.springframework:spring-beans:$springVersion",
|
||||||
|
"org.springframework:spring-context-support:$springVersion",
|
||||||
|
"org.springframework:spring-test:$springVersion"
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>spring-security-parent</artifactId>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<version>3.0.4.RELEASE</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-acl</artifactId>
|
||||||
|
<name>Spring Security - ACL module</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<classifier>tests</classifier>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context-support</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.ehcache</groupId>
|
||||||
|
<artifactId>ehcache</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>hsqldb</groupId>
|
||||||
|
<artifactId>hsqldb</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>8.3-603.jdbc3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.springsource.bundlor</groupId>
|
||||||
|
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
apply plugin: 'io.spring.convention.spring-module'
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
management platform(project(":spring-security-dependencies"))
|
|
||||||
api project(':spring-security-core')
|
|
||||||
api 'org.springframework:spring-aop'
|
|
||||||
api 'org.springframework:spring-context'
|
|
||||||
api 'org.springframework:spring-core'
|
|
||||||
api 'org.springframework:spring-jdbc'
|
|
||||||
api 'org.springframework:spring-tx'
|
|
||||||
|
|
||||||
testImplementation "org.assertj:assertj-core"
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-params"
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-engine"
|
|
||||||
testImplementation "org.mockito:mockito-core"
|
|
||||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
|
||||||
testImplementation 'org.springframework:spring-beans'
|
|
||||||
testImplementation 'org.springframework:spring-context-support'
|
|
||||||
testImplementation "org.springframework:spring-test"
|
|
||||||
|
|
||||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls;
|
package org.springframework.security.acls;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -22,10 +20,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.security.access.AuthorizationServiceException;
|
import org.springframework.security.access.AuthorizationServiceException;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.access.vote.AbstractAclVoter;
|
import org.springframework.security.access.vote.AbstractAclVoter;
|
||||||
@@ -41,103 +37,93 @@ import org.springframework.security.acls.model.Sid;
|
|||||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Given a domain object instance passed as a method argument, ensures the principal has
|
* Given a domain object instance passed as a method argument, ensures the principal has appropriate permission
|
||||||
* appropriate permission as indicated by the {@link AclService}.
|
* as indicated by the {@link AclService}.
|
||||||
* <p>
|
* <p>
|
||||||
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions
|
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions associated with a
|
||||||
* associated with a domain object instance for the current <tt>Authentication</tt>
|
* domain object instance for the current <tt>Authentication</tt> object.
|
||||||
* object.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the
|
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the {@link #processConfigAttribute}.
|
||||||
* {@link #processConfigAttribute}. The provider will then locate the first method
|
* The provider will then locate the first method argument of type {@link #processDomainObjectClass}. Assuming that
|
||||||
* argument of type {@link #processDomainObjectClass}. Assuming that method argument is
|
* method argument is non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and ensure the
|
||||||
* non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and
|
* principal is {@link Acl#isGranted(List,
|
||||||
* ensure the principal is {@link Acl#isGranted(List, List, boolean)} when presenting the
|
* List, boolean)} when presenting the {@link #requirePermission} array to that
|
||||||
* {@link #requirePermission} array to that method.
|
* method.
|
||||||
* <p>
|
* <p>
|
||||||
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the
|
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the method argument
|
||||||
* method argument could not be found, an {@link AuthorizationServiceException} will be
|
* could not be found, an {@link AuthorizationServiceException} will be thrown.
|
||||||
* thrown.
|
|
||||||
* <p>
|
* <p>
|
||||||
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each
|
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each will have a
|
||||||
* will have a different {@link #setProcessDomainObjectClass processDomainObjectClass},
|
* different {@link #setProcessDomainObjectClass processDomainObjectClass}, {@link #processConfigAttribute} and
|
||||||
* {@link #processConfigAttribute} and {@link #requirePermission} combination. For
|
* {@link #requirePermission} combination. For example, a small application might employ the following instances of
|
||||||
* example, a small application might employ the following instances of
|
|
||||||
* <tt>AclEntryVoter</tt>:
|
* <tt>AclEntryVoter</tt>:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
||||||
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission
|
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission <code>BasePermission.READ</code></li>
|
||||||
* <code>BasePermission.READ</code></li>
|
|
||||||
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
||||||
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list
|
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
|
||||||
* <code>BasePermission.WRITE</code> and <code>BasePermission.CREATE</code> (allowing the
|
* <code>BasePermission.CREATE</code> (allowing the principal to have <b>either</b> of these two permissions)</li>
|
||||||
* principal to have <b>either</b> of these two permissions)</li>
|
|
||||||
* <li>Process domain object class <code>Customer</code>, configuration attribute
|
* <li>Process domain object class <code>Customer</code>, configuration attribute
|
||||||
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission
|
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission <code>BasePermission.READ</code></li>
|
||||||
* <code>BasePermission.READ</code></li>
|
|
||||||
* <li>Process domain object class <code>Customer</code>, configuration attribute
|
* <li>Process domain object class <code>Customer</code>, configuration attribute
|
||||||
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list
|
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
|
||||||
* <code>BasePermission.WRITE</code> and <code>BasePermission.CREATE</code></li>
|
* <code>BasePermission.CREATE</code></li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* Alternatively, you could have used a common superclass or interface for the
|
* Alternatively, you could have used a common superclass or interface for the {@link #processDomainObjectClass}
|
||||||
* {@link #processDomainObjectClass} if both <code>BankAccount</code> and
|
* if both <code>BankAccount</code> and <code>Customer</code> had common parents.</p>
|
||||||
* <code>Customer</code> had common parents.
|
* <p>If the principal does not have sufficient permissions, the voter will vote to deny access.</p>
|
||||||
*
|
* <p>All comparisons and prefixes are case sensitive.</p>
|
||||||
* <p>
|
|
||||||
* If the principal does not have sufficient permissions, the voter will vote to deny
|
|
||||||
* access.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* All comparisons and prefixes are case sensitive.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
|
|
||||||
* annotations may also prove useful, for example
|
|
||||||
* {@code @PreAuthorize("hasPermission(#id, ObjectsReturnType.class, read)")}
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public class AclEntryVoter extends AbstractAclVoter {
|
public class AclEntryVoter extends AbstractAclVoter {
|
||||||
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
|
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
|
||||||
|
|
||||||
private final AclService aclService;
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final String processConfigAttribute;
|
|
||||||
|
|
||||||
private final List<Permission> requirePermission;
|
|
||||||
|
|
||||||
|
private AclService aclService;
|
||||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||||
|
|
||||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||||
|
|
||||||
private String internalMethod;
|
private String internalMethod;
|
||||||
|
private String processConfigAttribute;
|
||||||
|
private List<Permission> requirePermission;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
|
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
|
||||||
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
|
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||||
Assert.notNull(aclService, "An AclService 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.aclService = aclService;
|
||||||
this.processConfigAttribute = processConfigAttribute;
|
this.processConfigAttribute = processConfigAttribute;
|
||||||
this.requirePermission = Arrays.asList(requirePermission);
|
this.requirePermission = Arrays.asList(requirePermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optionally specifies a method of the domain object that will be used to obtain a
|
* Optionally specifies a method of the domain object that will be used to obtain a contained domain
|
||||||
* contained domain object. That contained domain object will be used for the ACL
|
* object. That contained domain object will be used for the ACL evaluation. This is useful if a domain object
|
||||||
* evaluation. This is useful if a domain object contains a parent that an ACL
|
* contains a parent that an ACL evaluation should be targeted for, instead of the child domain object (which
|
||||||
* 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)
|
* 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>
|
* @return <code>null</code> to use the domain object, or the name of a method (that requires no arguments) that
|
||||||
* which will be the domain object used for ACL evaluation
|
* should be invoked to obtain an <code>Object</code> which will be the domain object used for ACL
|
||||||
|
* evaluation
|
||||||
*/
|
*/
|
||||||
protected String getInternalMethod() {
|
protected String getInternalMethod() {
|
||||||
return this.internalMethod;
|
return internalMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInternalMethod(String internalMethod) {
|
public void setInternalMethod(String internalMethod) {
|
||||||
@@ -145,7 +131,7 @@ public class AclEntryVoter extends AbstractAclVoter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getProcessConfigAttribute() {
|
protected String getProcessConfigAttribute() {
|
||||||
return this.processConfigAttribute;
|
return processConfigAttribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||||
@@ -158,60 +144,95 @@ public class AclEntryVoter extends AbstractAclVoter {
|
|||||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(ConfigAttribute attribute) {
|
public boolean supports(ConfigAttribute attribute) {
|
||||||
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
|
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
|
||||||
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
|
|
||||||
for(ConfigAttribute attr : attributes) {
|
for(ConfigAttribute attr : attributes) {
|
||||||
if (!supports(attr)) {
|
|
||||||
|
if (!this.supports(attr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to make an access decision on this invocation
|
// Need to make an access decision on this invocation
|
||||||
// Attempt to locate the domain object instance to process
|
// Attempt to locate the domain object instance to process
|
||||||
Object domainObject = getDomainObjectInstance(object);
|
Object domainObject = getDomainObjectInstance(object);
|
||||||
|
|
||||||
// If domain object is null, vote to abstain
|
// If domain object is null, vote to abstain
|
||||||
if (domainObject == null) {
|
if (domainObject == null) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Voting to abstain - domainObject is null");
|
logger.debug("Voting to abstain - domainObject is null");
|
||||||
|
}
|
||||||
|
|
||||||
return ACCESS_ABSTAIN;
|
return ACCESS_ABSTAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate if we are required to use an inner domain object
|
// Evaluate if we are required to use an inner domain object
|
||||||
if (StringUtils.hasText(this.internalMethod)) {
|
if (StringUtils.hasText(internalMethod)) {
|
||||||
domainObject = invokeInternalMethod(domainObject);
|
try {
|
||||||
|
Class<?> clazz = domainObject.getClass();
|
||||||
|
Method method = clazz.getMethod(internalMethod, new Class[0]);
|
||||||
|
domainObject = method.invoke(domainObject, new Object[0]);
|
||||||
|
} 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
|
// 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
|
// Obtain the SIDs applicable to the principal
|
||||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||||
|
|
||||||
Acl acl;
|
Acl acl;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Lookup only ACLs for SIDs we're interested in
|
// Lookup only ACLs for SIDs we're interested in
|
||||||
acl = this.aclService.readAclById(objectIdentity, sids);
|
acl = aclService.readAclById(objectIdentity, sids);
|
||||||
}
|
} catch (NotFoundException nfe) {
|
||||||
catch (NotFoundException ex) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||||
|
}
|
||||||
|
|
||||||
return ACCESS_DENIED;
|
return ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (acl.isGranted(this.requirePermission, sids, false)) {
|
if (acl.isGranted(requirePermission, sids, false)) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Voting to grant access");
|
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_GRANTED;
|
||||||
|
} else {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Voting to deny access - ACLs returned, but insufficient permissions for this principal");
|
||||||
|
}
|
||||||
|
|
||||||
return ACCESS_DENIED;
|
return ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
catch (NotFoundException ex) {
|
} catch (NotFoundException nfe) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||||
|
}
|
||||||
|
|
||||||
return ACCESS_DENIED;
|
return ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,27 +240,4 @@ public class AclEntryVoter extends AbstractAclVoter {
|
|||||||
// No configuration attribute matched, so abstain
|
// No configuration attribute matched, so abstain
|
||||||
return ACCESS_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
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;
|
|
||||||
import org.springframework.security.acls.model.AclService;
|
|
||||||
import org.springframework.security.acls.model.ObjectIdentity;
|
|
||||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
|
||||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch loads ACLs for collections of objects to allow optimised filtering.
|
|
||||||
*
|
|
||||||
* @author Luke Taylor
|
|
||||||
* @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());
|
|
||||||
for (Object domainObject : objects) {
|
|
||||||
if (domainObject != null) {
|
|
||||||
ObjectIdentity oid = this.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
|
||||||
this.oidRetrievalStrategy = objectIdentityRetrievalStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
|
||||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,30 +1,11 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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;
|
package org.springframework.security.acls;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.core.log.LogMessage;
|
|
||||||
import org.springframework.security.access.PermissionEvaluator;
|
import org.springframework.security.access.PermissionEvaluator;
|
||||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||||
@@ -42,8 +23,8 @@ import org.springframework.security.acls.model.SidRetrievalStrategy;
|
|||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by Spring Security's expression-based access control implementation to evaluate
|
* Used by Spring Security's expression-based access control implementation to evaluate permissions for a particular
|
||||||
* permissions for a particular object using the ACL module. Similar in behaviour to
|
* object using the ACL module. Similar in behaviour to
|
||||||
* {@link org.springframework.security.acls.AclEntryVoter AclEntryVoter}.
|
* {@link org.springframework.security.acls.AclEntryVoter AclEntryVoter}.
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
@@ -53,14 +34,10 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
|||||||
|
|
||||||
private final Log logger = LogFactory.getLog(getClass());
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private final AclService aclService;
|
private AclService aclService;
|
||||||
|
|
||||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||||
|
|
||||||
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
||||||
|
|
||||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||||
|
|
||||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||||
|
|
||||||
public AclPermissionEvaluator(AclService aclService) {
|
public AclPermissionEvaluator(AclService aclService) {
|
||||||
@@ -68,74 +45,88 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether the user has the given permission(s) on the domain object using
|
* Determines whether the user has the given permission(s) on the domain object using the ACL
|
||||||
* the ACL configuration. If the domain object is null, returns false (this can always
|
* configuration. If the domain object is null, returns false (this can always be overridden using a null
|
||||||
* be overridden using a null check in the expression itself).
|
* 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) {
|
if (domainObject == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
|
||||||
|
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||||
|
|
||||||
return checkPermission(authentication, objectIdentity, permission);
|
return checkPermission(authentication, objectIdentity, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
|
||||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
|
ObjectIdentity objectIdentity = objectIdentityGenerator.createObjectIdentity(targetId, targetType);
|
||||||
Object permission) {
|
|
||||||
ObjectIdentity objectIdentity = this.objectIdentityGenerator.createObjectIdentity(targetId, targetType);
|
|
||||||
return checkPermission(authentication, objectIdentity, permission);
|
return checkPermission(authentication, objectIdentity, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPermission(Authentication authentication, ObjectIdentity oid, Object permission) {
|
private boolean checkPermission(Authentication authentication, ObjectIdentity oid, Object permission) {
|
||||||
// Obtain the SIDs applicable to the principal
|
// 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);
|
List<Permission> requiredPermission = resolvePermission(permission);
|
||||||
this.logger.debug(LogMessage.of(() -> "Checking permission '" + permission + "' for object '" + oid + "'"));
|
|
||||||
try {
|
try {
|
||||||
// Lookup only ACLs for SIDs we're interested in
|
// 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)) {
|
if (acl.isGranted(requiredPermission, sids, false)) {
|
||||||
this.logger.debug("Access is granted");
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Access is granted");
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
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");
|
} catch (NotFoundException nfe) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Returning false - no ACLs apply for this principal");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Permission> resolvePermission(Object permission) {
|
List<Permission> resolvePermission(Object permission) {
|
||||||
if (permission instanceof Integer) {
|
if (permission instanceof Integer) {
|
||||||
return Arrays.asList(this.permissionFactory.buildFromMask((Integer) permission));
|
return Arrays.asList(permissionFactory.buildFromMask(((Integer)permission).intValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permission instanceof Permission) {
|
if (permission instanceof Permission) {
|
||||||
return Arrays.asList((Permission)permission);
|
return Arrays.asList((Permission)permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permission instanceof Permission[]) {
|
if (permission instanceof Permission[]) {
|
||||||
return Arrays.asList((Permission[])permission);
|
return Arrays.asList((Permission[])permission);
|
||||||
}
|
}
|
||||||
if (permission instanceof String permString) {
|
|
||||||
Permission p = buildPermission(permString);
|
if (permission instanceof String) {
|
||||||
|
String permString = (String)permission;
|
||||||
|
Permission p = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
p = permissionFactory.buildFromName(permString);
|
||||||
|
} catch(IllegalArgumentException notfound) {
|
||||||
|
p = permissionFactory.buildFromName(permString.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
return Arrays.asList(p);
|
return Arrays.asList(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Unsupported permission: " + permission);
|
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;
|
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||||
}
|
}
|
||||||
@@ -151,5 +142,4 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
|||||||
public void setPermissionFactory(PermissionFactory permissionFactory) {
|
public void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||||
this.permissionFactory = permissionFactory;
|
this.permissionFactory = permissionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-34
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -16,11 +15,12 @@
|
|||||||
|
|
||||||
package org.springframework.security.acls.afterinvocation;
|
package org.springframework.security.acls.afterinvocation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.security.access.AfterInvocationProvider;
|
import org.springframework.security.access.AfterInvocationProvider;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.acls.AclPermissionEvaluator;
|
import org.springframework.security.acls.domain.BasePermission;
|
||||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||||
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
||||||
import org.springframework.security.acls.model.Acl;
|
import org.springframework.security.acls.model.Acl;
|
||||||
@@ -33,59 +33,59 @@ import org.springframework.security.acls.model.Sid;
|
|||||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related
|
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related services.
|
||||||
* services.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
|
|
||||||
* annotations may also prove useful, for example
|
|
||||||
* {@code @PostAuthorize("hasPermission(filterObject, read)")}
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
protected final AclService aclService;
|
protected AclService aclService;
|
||||||
|
|
||||||
protected String processConfigAttribute;
|
|
||||||
|
|
||||||
protected Class<?> processDomainObjectClass = Object.class;
|
protected Class<?> processDomainObjectClass = Object.class;
|
||||||
|
|
||||||
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||||
|
|
||||||
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||||
|
protected String processConfigAttribute;
|
||||||
|
protected List<Permission> requirePermission = Arrays.asList(BasePermission.READ);
|
||||||
|
|
||||||
protected final List<Permission> requirePermission;
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public AbstractAclProvider(AclService aclService, String processConfigAttribute,
|
public AbstractAclProvider(AclService aclService, String processConfigAttribute, List<Permission> requirePermission) {
|
||||||
List<Permission> requirePermission) {
|
|
||||||
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
|
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||||
Assert.notNull(aclService, "An AclService 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.aclService = aclService;
|
||||||
this.processConfigAttribute = processConfigAttribute;
|
this.processConfigAttribute = processConfigAttribute;
|
||||||
this.requirePermission = requirePermission;
|
this.requirePermission = requirePermission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
protected Class<?> getProcessDomainObjectClass() {
|
protected Class<?> getProcessDomainObjectClass() {
|
||||||
return this.processDomainObjectClass;
|
return processDomainObjectClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hasPermission(Authentication authentication, Object domainObject) {
|
protected boolean hasPermission(Authentication authentication, Object domainObject) {
|
||||||
// Obtain the OID applicable to the domain object
|
// 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
|
// Obtain the SIDs applicable to the principal
|
||||||
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
|
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||||
|
|
||||||
|
Acl acl = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Lookup only ACLs for SIDs we're interested in
|
// Lookup only ACLs for SIDs we're interested in
|
||||||
Acl acl = this.aclService.readAclById(objectIdentity, sids);
|
acl = aclService.readAclById(objectIdentity, sids);
|
||||||
return acl.isGranted(this.requirePermission, sids, false);
|
|
||||||
}
|
return acl.isGranted(requirePermission, sids, false);
|
||||||
catch (NotFoundException ex) {
|
} catch (NotFoundException ignore) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,20 +110,18 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
|||||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(ConfigAttribute attribute) {
|
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
|
* This implementation supports any type of class, because it does not query the presented secure object.
|
||||||
* presented secure object.
|
*
|
||||||
* @param clazz the secure object
|
* @param clazz the secure object
|
||||||
|
*
|
||||||
* @return always <code>true</code>
|
* @return always <code>true</code>
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> clazz) {
|
public boolean supports(Class<?> clazz) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-58
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.afterinvocation;
|
package org.springframework.security.acls.afterinvocation;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -21,68 +19,66 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.core.log.LogMessage;
|
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.access.AuthorizationServiceException;
|
import org.springframework.security.access.AuthorizationServiceException;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.acls.AclPermissionEvaluator;
|
|
||||||
import org.springframework.security.acls.model.AclService;
|
import org.springframework.security.acls.model.AclService;
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Given a <code>Collection</code> of domain object instances returned from a secure
|
* Given a <code>Collection</code> of domain object instances returned from a secure object invocation, remove
|
||||||
* object invocation, remove any <code>Collection</code> elements the principal does not
|
* any <code>Collection</code> elements the principal does not have appropriate permission to access as defined by the
|
||||||
* have appropriate permission to access as defined by the {@link AclService}.
|
* {@link AclService}.
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>AclService</code> is used to retrieve the access control list (ACL)
|
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with
|
||||||
* permissions associated with each <code>Collection</code> domain object instance element
|
* each <code>Collection</code> domain object instance element for the current <code>Authentication</code> object.
|
||||||
* for the current <code>Authentication</code> object.
|
|
||||||
* <p>
|
* <p>
|
||||||
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()}
|
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
|
||||||
* matches the {@link #processConfigAttribute}. The provider will then lookup the ACLs
|
* #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
|
||||||
* from the <code>AclService</code> and ensure the principal is
|
* principal is {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean) Acl.isGranted()}
|
||||||
* {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
|
* when presenting the {@link #requirePermission} array to that method.
|
||||||
* Acl.isGranted()} when presenting the {@link #requirePermission} array to that method.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the principal does not have permission, that element will not be included in the
|
* If the principal does not have permission, that element will not be included in the returned
|
||||||
* returned <code>Collection</code>.
|
* <code>Collection</code>.
|
||||||
* <p>
|
* <p>
|
||||||
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a
|
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a {@link
|
||||||
* {@link #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a
|
* #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a {@link #requirePermission} of
|
||||||
* {@link #requirePermission} of <code>BasePermission.READ</code>. These are also the
|
* <code>BasePermission.READ</code>. These are also the defaults.
|
||||||
* defaults.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code>
|
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code><code>Collection</code>
|
||||||
* <code>Collection</code> will be returned. If the provided <code>returnObject</code> is
|
* will be returned. If the provided <code>returnObject</code> is not a <code>Collection</code>, an {@link
|
||||||
* not a <code>Collection</code>, an {@link AuthorizationServiceException} will be thrown.
|
* AuthorizationServiceException} will be thrown.
|
||||||
* <p>
|
* <p>
|
||||||
* All comparisons and prefixes are case sensitive.
|
* All comparisons and prefixes are case sensitive.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Paulo Neves
|
* @author Paulo Neves
|
||||||
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
|
|
||||||
* annotations may also prove useful, for example
|
|
||||||
* {@code @PostFilter("hasPermission(filterObject, read)")}
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
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);
|
||||||
|
|
||||||
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService,
|
//~ Constructors ===================================================================================================
|
||||||
List<Permission> requirePermission) {
|
|
||||||
|
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, List<Permission> requirePermission) {
|
||||||
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
|
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||||
Object returnedObject) throws AccessDeniedException {
|
Object returnedObject) throws AccessDeniedException {
|
||||||
|
|
||||||
if (returnedObject == null) {
|
if (returnedObject == null) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Return object is null, skipping");
|
logger.debug("Return object is null, skipping");
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,34 +88,36 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Need to process the Collection for this invocation
|
// Need to process the Collection for this invocation
|
||||||
Filterer filterer = getFilterer(returnedObject);
|
Filterer filterer;
|
||||||
|
|
||||||
// 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())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!hasPermission(authentication, domainObject)) {
|
|
||||||
filterer.remove(domainObject);
|
|
||||||
logger.debug(LogMessage.of(() -> "Principal is NOT authorised for element: " + domainObject));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filterer.getFilteredObject();
|
|
||||||
}
|
|
||||||
return returnedObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Filterer getFilterer(Object returnedObject) {
|
|
||||||
if (returnedObject instanceof Collection) {
|
if (returnedObject instanceof Collection) {
|
||||||
return new CollectionFilterer((Collection) returnedObject);
|
filterer = new CollectionFilterer((Collection) returnedObject);
|
||||||
}
|
} else if (returnedObject.getClass().isArray()) {
|
||||||
if (returnedObject.getClass().isArray()) {
|
filterer = new ArrayFilterer((Object[]) returnedObject);
|
||||||
return new ArrayFilterer((Object[]) returnedObject);
|
} else {
|
||||||
}
|
|
||||||
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
|
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
|
||||||
+ "returnedObject, but the returnedObject was: " + returnedObject);
|
+ "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())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!hasPermission(authentication, domainObject)) {
|
||||||
|
filterer.remove(domainObject);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Principal is NOT authorised for element: " + domainObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filterer.getFilteredObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnedObject;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-36
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.afterinvocation;
|
package org.springframework.security.acls.afterinvocation;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -21,59 +19,53 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
import org.springframework.context.MessageSourceAware;
|
import org.springframework.context.MessageSourceAware;
|
||||||
import org.springframework.context.support.MessageSourceAccessor;
|
import org.springframework.context.support.MessageSourceAccessor;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.acls.AclPermissionEvaluator;
|
|
||||||
import org.springframework.security.acls.model.AclService;
|
import org.springframework.security.acls.model.AclService;
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a domain object instance returned from a secure object invocation, ensures the
|
* Given a domain object instance returned from a secure object invocation, ensures the principal has
|
||||||
* principal has appropriate permission as defined by the {@link AclService}.
|
* appropriate permission as defined by the {@link AclService}.
|
||||||
* <p>
|
* <p>
|
||||||
* The <code>AclService</code> is used to retrieve the access control list (ACL)
|
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
|
||||||
* permissions associated with a domain object instance for the current
|
* domain object instance for the current <code>Authentication</code> object.
|
||||||
* <code>Authentication</code> object.
|
|
||||||
* <p>
|
* <p>
|
||||||
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()}
|
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
|
||||||
* matches the {@link #processConfigAttribute}. The provider will then lookup the ACLs
|
* #processConfigAttribute}. The provider will then lookup the ACLs from the <tt>AclService</tt> and ensure the
|
||||||
* from the <tt>AclService</tt> and ensure the principal is
|
* principal is {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
|
||||||
* {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
|
* Acl.isGranted(List, List, boolean)} when presenting the {@link #requirePermission} array to that method.
|
||||||
* Acl.isGranted(List, List, boolean)} when presenting the {@link #requirePermission}
|
|
||||||
* array to that method.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Often users will set up an <code>AclEntryAfterInvocationProvider</code> with a
|
* Often users will set up an <code>AclEntryAfterInvocationProvider</code> with a {@link
|
||||||
* {@link #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a
|
* #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a {@link #requirePermission} of
|
||||||
* {@link #requirePermission} of <code>BasePermission.READ</code>. These are also the
|
* <code>BasePermission.READ</code>. These are also the defaults.
|
||||||
* defaults.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the principal does not have sufficient permissions, an
|
* If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.
|
||||||
* <code>AccessDeniedException</code> will be thrown.
|
|
||||||
* <p>
|
* <p>
|
||||||
* If the provided <tt>returnedObject</tt> is <code>null</code>, permission will always be
|
* If the provided <tt>returnedObject</tt> is <code>null</code>, permission will always be granted and
|
||||||
* granted and <code>null</code> will be returned.
|
* <code>null</code> will be returned.
|
||||||
* <p>
|
* <p>
|
||||||
* All comparisons and prefixes are case sensitive.
|
* All comparisons and prefixes are case sensitive.
|
||||||
*
|
|
||||||
* @deprecated please use {@link AclPermissionEvaluator} instead. Spring Method Security
|
|
||||||
* annotations may also prove useful, for example
|
|
||||||
* {@code @PostAuthorize("hasPermission(filterObject, read)")}
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
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();
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
|
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
|
||||||
this(aclService, "AFTER_ACL_READ", requirePermission);
|
super(aclService, "AFTER_ACL_READ", requirePermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
|
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
|
||||||
@@ -81,19 +73,26 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
|||||||
super(aclService, processConfigAttribute, requirePermission);
|
super(aclService, processConfigAttribute, requirePermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||||
Object returnedObject) throws AccessDeniedException {
|
Object returnedObject) throws AccessDeniedException {
|
||||||
|
|
||||||
if (returnedObject == null) {
|
if (returnedObject == null) {
|
||||||
// AclManager interface contract prohibits nulls
|
// AclManager interface contract prohibits nulls
|
||||||
// As they have permission to null/nothing, grant access
|
// As they have permission to null/nothing, grant access
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Return object is null, skipping");
|
logger.debug("Return object is null, skipping");
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
|
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Return object is not applicable for this provider, skipping");
|
logger.debug("Return object is not applicable for this provider, skipping");
|
||||||
|
}
|
||||||
|
|
||||||
return returnedObject;
|
return returnedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,14 +100,15 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
|||||||
if (!this.supports(attr)) {
|
if (!this.supports(attr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to make an access decision on this invocation
|
// Need to make an access decision on this invocation
|
||||||
|
|
||||||
if (hasPermission(authentication, returnedObject)) {
|
if (hasPermission(authentication, returnedObject)) {
|
||||||
return returnedObject;
|
return returnedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Denying access");
|
logger.debug("Denying access");
|
||||||
throw new AccessDeniedException(this.messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
|
|
||||||
|
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
|
||||||
new Object[] {authentication.getName(), returnedObject},
|
new Object[] {authentication.getName(), returnedObject},
|
||||||
"Authentication {0} has NO permissions to the domain object {1}"));
|
"Authentication {0} has NO permissions to the domain object {1}"));
|
||||||
}
|
}
|
||||||
@@ -116,9 +116,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
|||||||
return returnedObject;
|
return returnedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMessageSource(MessageSource messageSource) {
|
public void setMessageSource(MessageSource messageSource) {
|
||||||
this.messages = new MessageSourceAccessor(messageSource);
|
this.messages = new MessageSourceAccessor(messageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-41
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -25,81 +24,94 @@ import java.util.Set;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.core.log.LogMessage;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A filter used to filter arrays.
|
* A filter used to filter arrays.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Paulo Neves
|
* @author Paulo Neves
|
||||||
* @deprecated please see {@code PostFilter}
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
class ArrayFilterer<T> implements Filterer<T> {
|
class ArrayFilterer<T> implements Filterer<T> {
|
||||||
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);
|
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;
|
private final T[] list;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
ArrayFilterer(T[] list) {
|
ArrayFilterer(T[] list) {
|
||||||
this.list = list;
|
this.list = list;
|
||||||
|
|
||||||
// Collect the removed objects to a HashSet so that
|
// Collect the removed objects to a HashSet so that
|
||||||
// it is fast to lookup them when a filtered array
|
// it is fast to lookup them when a filtered array
|
||||||
// is constructed.
|
// is constructed.
|
||||||
this.removeList = new HashSet<>();
|
removeList = new HashSet<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.acls.afterinvocation.Filterer#getFilteredObject()
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T[] getFilteredObject() {
|
public T[] getFilteredObject() {
|
||||||
// Recreate an array of same type and filter the removed objects.
|
// Recreate an array of same type and filter the removed objects.
|
||||||
int originalSize = this.list.length;
|
int originalSize = list.length;
|
||||||
int sizeOfResultingList = originalSize - this.removeList.size();
|
int sizeOfResultingList = originalSize - removeList.size();
|
||||||
T[] filtered = (T[]) Array.newInstance(this.list.getClass().getComponentType(), sizeOfResultingList);
|
T[] filtered = (T[]) Array.newInstance(list.getClass().getComponentType(), sizeOfResultingList);
|
||||||
for (int i = 0, j = 0; i < this.list.length; i++) {
|
|
||||||
T object = this.list[i];
|
for (int i = 0, j = 0; i < list.length; i++) {
|
||||||
if (!this.removeList.contains(object)) {
|
T object = list[i];
|
||||||
|
|
||||||
|
if (!removeList.contains(object)) {
|
||||||
filtered[j] = object;
|
filtered[j] = object;
|
||||||
j++;
|
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;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
|
||||||
|
*/
|
||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return new ArrayFiltererIterator();
|
return new Iterator<T>() {
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return index < list.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public T next() {
|
||||||
public void remove(T object) {
|
if (hasNext() == false) {
|
||||||
this.removeList.add(object);
|
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> {
|
public void remove(T object) {
|
||||||
|
removeList.add(object);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-25
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -16,34 +15,40 @@
|
|||||||
|
|
||||||
package org.springframework.security.acls.afterinvocation;
|
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.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
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.
|
* A filter used to filter Collections.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Paulo Neves
|
* @author Paulo Neves
|
||||||
* @deprecated please see {@code PostFilter}
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
class CollectionFilterer<T> implements Filterer<T> {
|
class CollectionFilterer<T> implements Filterer<T> {
|
||||||
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);
|
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);
|
||||||
|
|
||||||
private final Collection<T> collection;
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final Set<T> removeList;
|
private Collection<T> collection;
|
||||||
|
|
||||||
|
// collectionIter offers significant performance optimisations (as
|
||||||
|
// per security-developer mailing list conversation 19/5/05)
|
||||||
|
private Iterator<T> collectionIter;
|
||||||
|
private Set<T> removeList;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
CollectionFilterer(Collection<T> collection) {
|
CollectionFilterer(Collection<T> collection) {
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
|
|
||||||
// We create a Set of objects to be removed from the Collection,
|
// We create a Set of objects to be removed from the Collection,
|
||||||
// as ConcurrentModificationException prevents removal during
|
// as ConcurrentModificationException prevents removal during
|
||||||
// iteration, and making a new Collection to be returned is
|
// iteration, and making a new Collection to be returned is
|
||||||
@@ -51,30 +56,48 @@ class CollectionFilterer<T> implements Filterer<T> {
|
|||||||
// to the method may not necessarily be re-constructable (as
|
// to the method may not necessarily be re-constructable (as
|
||||||
// the Collection(collection) constructor is not guaranteed and
|
// the Collection(collection) constructor is not guaranteed and
|
||||||
// manually adding may lose sort order or other capabilities)
|
// 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() {
|
public Object getFilteredObject() {
|
||||||
// Now the Iterator has ended, remove Objects from Collection
|
// Now the Iterator has ended, remove Objects from Collection
|
||||||
Iterator<T> removeIter = this.removeList.iterator();
|
Iterator<T> removeIter = removeList.iterator();
|
||||||
int originalSize = this.collection.size();
|
|
||||||
|
int originalSize = collection.size();
|
||||||
|
|
||||||
while (removeIter.hasNext()) {
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Original collection contained " + originalSize + " elements; now contains "
|
||||||
|
+ collection.size() + " elements");
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
|
||||||
|
*/
|
||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return this.collection.iterator();
|
collectionIter = collection.iterator();
|
||||||
|
|
||||||
|
return collectionIter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
*
|
||||||
|
* @see org.springframework.security.acls.afterinvocation.Filterer#remove(java.lang.Object)
|
||||||
|
*/
|
||||||
public void remove(T object) {
|
public void remove(T object) {
|
||||||
this.removeList.add(object);
|
removeList.add(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -18,33 +17,34 @@ package org.springframework.security.acls.afterinvocation;
|
|||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filterer strategy interface.
|
* Filterer strategy interface.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Paulo Neves
|
* @author Paulo Neves
|
||||||
* @deprecated please use {@code PreFilter} and {@code @PostFilter} instead
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
interface Filterer<T> extends Iterable<T> {
|
interface Filterer<T> extends Iterable<T> {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the filtered collection or array.
|
* Gets the filtered collection or array.
|
||||||
|
*
|
||||||
* @return the filtered collection or array
|
* @return the filtered collection or array
|
||||||
*/
|
*/
|
||||||
Object getFilteredObject();
|
Object getFilteredObject();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator over the filtered collection or array.
|
* Returns an iterator over the filtered collection or array.
|
||||||
|
*
|
||||||
* @return an Iterator
|
* @return an Iterator
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
Iterator<T> iterator();
|
Iterator<T> iterator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given object from the resulting list.
|
* Removes the the given object from the resulting list.
|
||||||
|
*
|
||||||
* @param object the object to be removed
|
* @param object the object to be removed
|
||||||
*/
|
*/
|
||||||
void remove(T object);
|
void remove(T object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-18
@@ -1,21 +1,6 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After-invocation providers for collection and array filtering. Consider using a
|
* After-invocation providers for collection and array filtering. Consider using a {@code PostFilter} annotation in
|
||||||
* {@code PostFilter} annotation in preference.
|
* preference.
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.acls.afterinvocation;
|
package org.springframework.security.acls.afterinvocation;
|
||||||
|
|
||||||
|
|||||||
+33
-46
@@ -1,19 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
@@ -26,13 +10,16 @@ import org.springframework.security.acls.model.Permission;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractPermission implements Permission {
|
public abstract class AbstractPermission implements Permission {
|
||||||
|
|
||||||
protected final char code;
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
protected char code;
|
||||||
protected int mask;
|
protected int mask;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
/**
|
/**
|
||||||
* Sets the permission mask and uses the '*' character to represent active bits when
|
* Sets the permission mask and uses the '*' character to represent active bits when represented as a bit
|
||||||
* represented as a bit pattern string.
|
* pattern string.
|
||||||
|
*
|
||||||
* @param mask the integer bit mask for the permission
|
* @param mask the integer bit mask for the permission
|
||||||
*/
|
*/
|
||||||
protected AbstractPermission(int mask) {
|
protected AbstractPermission(int mask) {
|
||||||
@@ -42,44 +29,44 @@ public abstract class AbstractPermission implements Permission {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the permission mask and uses the specified character for active bits.
|
* Sets the permission mask and uses the specified character for active bits.
|
||||||
|
*
|
||||||
* @param mask the integer bit mask for the permission
|
* @param mask the integer bit mask for the permission
|
||||||
* @param code the character to print for each active bit in the mask (see
|
* @param code the character to print for each active bit in the mask (see {@link Permission#getPattern()})
|
||||||
* {@link Permission#getPattern()})
|
|
||||||
*/
|
*/
|
||||||
protected AbstractPermission(int mask, char code) {
|
protected AbstractPermission(int mask, char code) {
|
||||||
this.mask = mask;
|
this.mask = mask;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
public final boolean equals(Object obj) {
|
|
||||||
if (obj == null) {
|
public final boolean equals(Object arg0) {
|
||||||
|
if (arg0 == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof Permission other)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (this.mask == other.getMask());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (!(arg0 instanceof Permission)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + "]";
|
||||||
|
}
|
||||||
|
|
||||||
public final int hashCode() {
|
public final int hashCode() {
|
||||||
return this.mask;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-60
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004-present the original author or authors.
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,38 +12,36 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import org.springframework.security.acls.model.AccessControlEntry;
|
import org.springframework.security.acls.model.AccessControlEntry;
|
||||||
import org.springframework.security.acls.model.Acl;
|
import org.springframework.security.acls.model.Acl;
|
||||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An immutable default implementation of <code>AccessControlEntry</code>.
|
* An immutable default implementation of <code>AccessControlEntry</code>.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
|
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final Acl acl;
|
private Acl acl;
|
||||||
|
|
||||||
private Permission permission;
|
private Permission permission;
|
||||||
|
private Serializable id;
|
||||||
private final Serializable id;
|
private Sid sid;
|
||||||
|
|
||||||
private final Sid sid;
|
|
||||||
|
|
||||||
private boolean auditFailure = false;
|
private boolean auditFailure = false;
|
||||||
|
|
||||||
private boolean auditSuccess = false;
|
private boolean auditSuccess = false;
|
||||||
|
private boolean granting;
|
||||||
|
|
||||||
private final boolean granting;
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||||
boolean auditSuccess, boolean auditFailure) {
|
boolean auditSuccess, boolean auditFailure) {
|
||||||
@@ -60,106 +57,92 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
|||||||
this.auditFailure = auditFailure;
|
this.auditFailure = auditFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public boolean equals(Object arg0) {
|
public boolean equals(Object arg0) {
|
||||||
if (!(arg0 instanceof AccessControlEntryImpl)) {
|
if (!(arg0 instanceof AccessControlEntryImpl)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AccessControlEntryImpl other = (AccessControlEntryImpl) arg0;
|
|
||||||
|
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
|
||||||
|
|
||||||
if (this.acl == null) {
|
if (this.acl == null) {
|
||||||
if (other.getAcl() != null) {
|
if (rhs.getAcl() != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Both this.acl and rhs.acl are null and thus equal
|
// Both this.acl and rhs.acl are null and thus equal
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// this.acl is non-null
|
// this.acl is non-null
|
||||||
if (other.getAcl() == null) {
|
if (rhs.getAcl() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both this.acl and rhs.acl are non-null, so do a comparison
|
// Both this.acl and rhs.acl are non-null, so do a comparison
|
||||||
if (this.acl.getObjectIdentity() == null) {
|
if (this.acl.getObjectIdentity() == null) {
|
||||||
if (other.acl.getObjectIdentity() != null) {
|
if (rhs.acl.getObjectIdentity() != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Both this.acl and rhs.acl are null and thus equal
|
// Both this.acl and rhs.acl are null and thus equal
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.id == null) {
|
if (this.id == null) {
|
||||||
if (other.id != null) {
|
if (rhs.id != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Both this.id and rhs.id are null and thus equal
|
// Both this.id and rhs.id are null and thus equal
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// this.id is non-null
|
// this.id is non-null
|
||||||
if (other.id == null) {
|
if (rhs.id == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both this.id and rhs.id are non-null
|
// Both this.id and rhs.id are non-null
|
||||||
if (!this.id.equals(other.id)) {
|
if (!this.id.equals(rhs.id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((this.auditFailure != other.isAuditFailure()) || (this.auditSuccess != other.isAuditSuccess())
|
|
||||||
|| (this.granting != other.isGranting()) || !this.permission.equals(other.getPermission())
|
if ((this.auditFailure != rhs.isAuditFailure()) || (this.auditSuccess != rhs.isAuditSuccess())
|
||||||
|| !this.sid.equals(other.getSid())) {
|
|| (this.granting != rhs.isGranting())
|
||||||
|
|| !this.permission.equals(rhs.getPermission()) || !this.sid.equals(rhs.getSid())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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() {
|
public Acl getAcl() {
|
||||||
return this.acl;
|
return acl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable getId() {
|
public Serializable getId() {
|
||||||
return this.id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Permission getPermission() {
|
public Permission getPermission() {
|
||||||
return this.permission;
|
return permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Sid getSid() {
|
public Sid getSid() {
|
||||||
return this.sid;
|
return sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAuditFailure() {
|
public boolean isAuditFailure() {
|
||||||
return this.auditFailure;
|
return auditFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAuditSuccess() {
|
public boolean isAuditSuccess() {
|
||||||
return this.auditSuccess;
|
return auditSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGranting() {
|
public boolean isGranting() {
|
||||||
return this.granting;
|
return granting;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAuditFailure(boolean auditFailure) {
|
void setAuditFailure(boolean auditFailure) {
|
||||||
@@ -175,7 +158,6 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
|||||||
this.permission = permission;
|
this.permission = permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("AccessControlEntryImpl[");
|
sb.append("AccessControlEntryImpl[");
|
||||||
@@ -186,7 +168,7 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
|||||||
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
|
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
|
||||||
sb.append("auditFailure: ").append(this.auditFailure);
|
sb.append("auditFailure: ").append(this.auditFailure);
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -18,6 +17,7 @@ package org.springframework.security.acls.domain;
|
|||||||
|
|
||||||
import org.springframework.security.acls.model.Acl;
|
import org.springframework.security.acls.model.Acl;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
|
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
|
||||||
* adminstrative methods on the <code>AclImpl</code>.
|
* adminstrative methods on the <code>AclImpl</code>.
|
||||||
@@ -25,13 +25,13 @@ import org.springframework.security.acls.model.Acl;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface AclAuthorizationStrategy {
|
public interface AclAuthorizationStrategy {
|
||||||
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
int CHANGE_OWNERSHIP = 0;
|
int CHANGE_OWNERSHIP = 0;
|
||||||
|
|
||||||
int CHANGE_AUDITING = 1;
|
int CHANGE_AUDITING = 1;
|
||||||
|
|
||||||
int CHANGE_GENERAL = 2;
|
int CHANGE_GENERAL = 2;
|
||||||
|
|
||||||
void securityCheck(Acl acl, int changeType);
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
void securityCheck(Acl acl, int changeType);
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-109
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -17,111 +16,94 @@
|
|||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
|
||||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
|
||||||
import org.springframework.security.acls.model.Acl;
|
import org.springframework.security.acls.model.Acl;
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of {@link AclAuthorizationStrategy}.
|
* Default implementation of {@link AclAuthorizationStrategy}.
|
||||||
* <p>
|
* <p>
|
||||||
* Permission will be granted if at least one of the following conditions is true for the
|
* Permission will be granted provided the current principal is either the owner (as defined by the ACL), has
|
||||||
* current principal.
|
* {@link BasePermission#ADMINISTRATION} (as defined by the ACL and via a {@link Sid} retrieved for the current
|
||||||
* <ul>
|
* principal via {@link #sidRetrievalStrategy}), or if the current principal holds the relevant system-wide
|
||||||
* <li>is the owner (as defined by the ACL).</li>
|
* {@link GrantedAuthority} and injected into the constructor.
|
||||||
* <li>holds the relevant system-wide {@link GrantedAuthority} injected into the
|
|
||||||
* constructor.</li>
|
|
||||||
* <li>has {@link BasePermission#ADMINISTRATION} permission (as defined by the ACL).</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
private GrantedAuthority gaGeneralChanges;
|
||||||
.getContextHolderStrategy();
|
private GrantedAuthority gaModifyAuditing;
|
||||||
|
private GrantedAuthority gaTakeOwnership;
|
||||||
private final GrantedAuthority gaGeneralChanges;
|
|
||||||
|
|
||||||
private final GrantedAuthority gaModifyAuditing;
|
|
||||||
|
|
||||||
private final GrantedAuthority gaTakeOwnership;
|
|
||||||
|
|
||||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||||
|
|
||||||
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. The only mandatory parameter relates to the system-wide
|
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
|
||||||
* {@link GrantedAuthority} instances that can be held to always permit ACL changes.
|
* 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
|
* @param auths an array of <code>GrantedAuthority</code>s that have
|
||||||
* needed to modify auditing details, index 2 is the authority needed to change other
|
* special permissions (index 0 is the authority needed to change
|
||||||
* ACL and ACE details) (required)
|
* ownership, index 1 is the authority needed to modify auditing details,
|
||||||
* <p>
|
* index 2 is the authority needed to change other ACL and ACE details) (required)
|
||||||
* Alternatively, a single value can be supplied for all three permissions.
|
|
||||||
*/
|
*/
|
||||||
public AclAuthorizationStrategyImpl(GrantedAuthority... auths) {
|
public AclAuthorizationStrategyImpl(GrantedAuthority[] auths) {
|
||||||
Assert.isTrue(auths != null && (auths.length == 3 || auths.length == 1),
|
Assert.isTrue(auths != null && auths.length == 3, "GrantedAuthority[] with three elements required");
|
||||||
"One or three GrantedAuthority instances required");
|
|
||||||
if (auths.length == 3) {
|
|
||||||
this.gaTakeOwnership = auths[0];
|
this.gaTakeOwnership = auths[0];
|
||||||
this.gaModifyAuditing = auths[1];
|
this.gaModifyAuditing = auths[1];
|
||||||
this.gaGeneralChanges = auths[2];
|
this.gaGeneralChanges = auths[2];
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
this.gaTakeOwnership = auths[0];
|
|
||||||
this.gaModifyAuditing = auths[0];
|
|
||||||
this.gaGeneralChanges = auths[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public void securityCheck(Acl acl, int changeType) {
|
public void securityCheck(Acl acl, int changeType) {
|
||||||
SecurityContext context = this.securityContextHolderStrategy.getContext();
|
if ((SecurityContextHolder.getContext() == null)
|
||||||
if ((context == null) || (context.getAuthentication() == null)
|
|| (SecurityContextHolder.getContext().getAuthentication() == null)
|
||||||
|| !context.getAuthentication().isAuthenticated()) {
|
|| !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
|
||||||
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
|
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
|
||||||
}
|
}
|
||||||
Authentication authentication = context.getAuthentication();
|
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
// Check if authorized by virtue of ACL ownership
|
// Check if authorized by virtue of ACL ownership
|
||||||
Sid currentUser = createCurrentUser(authentication);
|
Sid currentUser = new PrincipalSid(authentication);
|
||||||
|
|
||||||
if (currentUser.equals(acl.getOwner())
|
if (currentUser.equals(acl.getOwner())
|
||||||
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate this principal's authorities to determine right
|
// Not authorized by ACL ownership; try via adminstrative permissions
|
||||||
Collection<? extends GrantedAuthority> reachableGrantedAuthorities = this.roleHierarchy
|
GrantedAuthority requiredAuthority = null;
|
||||||
.getReachableGrantedAuthorities(authentication.getAuthorities());
|
|
||||||
Set<String> authorities = AuthorityUtils.authorityListToSet(reachableGrantedAuthorities);
|
if (changeType == CHANGE_AUDITING) {
|
||||||
if (acl.getOwner() instanceof GrantedAuthoritySid
|
requiredAuthority = this.gaModifyAuditing;
|
||||||
&& authorities.contains(((GrantedAuthoritySid) acl.getOwner()).getGrantedAuthority())) {
|
} else if (changeType == CHANGE_GENERAL) {
|
||||||
return;
|
requiredAuthority = this.gaGeneralChanges;
|
||||||
|
} else if (changeType == CHANGE_OWNERSHIP) {
|
||||||
|
requiredAuthority = this.gaTakeOwnership;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown change type");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not authorized by ACL ownership; try via adminstrative permissions
|
// Iterate this principal's authorities to determine right
|
||||||
GrantedAuthority requiredAuthority = getRequiredAuthority(changeType);
|
if (authentication.getAuthorities().contains(requiredAuthority)) {
|
||||||
|
|
||||||
if (authorities.contains(requiredAuthority.getAuthority())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get permission via ACEs within the ACL
|
// 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)) {
|
if (acl.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), sids, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -130,53 +112,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
|||||||
"Principal does not have required ACL permissions to perform requested operation");
|
"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
|
|
||||||
*/
|
|
||||||
protected Sid createCurrentUser(Authentication authentication) {
|
|
||||||
return new PrincipalSid(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||||
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
||||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
|
|
||||||
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
|
|
||||||
*
|
|
||||||
* @since 5.8
|
|
||||||
*/
|
|
||||||
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
|
||||||
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
|
|
||||||
this.securityContextHolderStrategy = securityContextHolderStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link RoleHierarchy} to use. The default is to use a
|
|
||||||
* {@link NullRoleHierarchy}
|
|
||||||
* @since 6.4
|
|
||||||
*/
|
|
||||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
|
||||||
Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
|
|
||||||
this.roleHierarchy = roleHierarchy;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-16
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,12 +12,12 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for displaying ACL information.
|
* Utility methods for displaying ACL information.
|
||||||
*
|
*
|
||||||
@@ -31,15 +30,17 @@ public abstract class AclFormattingUtils {
|
|||||||
Assert.notNull(removeBits, "Bits To Remove string required");
|
Assert.notNull(removeBits, "Bits To Remove string required");
|
||||||
Assert.isTrue(original.length() == removeBits.length(),
|
Assert.isTrue(original.length() == removeBits.length(),
|
||||||
"Original and Bits To Remove strings must be identical length");
|
"Original and Bits To Remove strings must be identical length");
|
||||||
|
|
||||||
char[] replacement = new char[original.length()];
|
char[] replacement = new char[original.length()];
|
||||||
|
|
||||||
for (int i = 0; i < original.length(); i++) {
|
for (int i = 0; i < original.length(); i++) {
|
||||||
if (removeBits.charAt(i) == Permission.RESERVED_OFF) {
|
if (removeBits.charAt(i) == Permission.RESERVED_OFF) {
|
||||||
replacement[i] = original.charAt(i);
|
replacement[i] = original.charAt(i);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
replacement[i] = Permission.RESERVED_OFF;
|
replacement[i] = Permission.RESERVED_OFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new String(replacement);
|
return new String(replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,24 +49,28 @@ public abstract class AclFormattingUtils {
|
|||||||
Assert.notNull(extraBits, "Extra Bits string required");
|
Assert.notNull(extraBits, "Extra Bits string required");
|
||||||
Assert.isTrue(original.length() == extraBits.length(),
|
Assert.isTrue(original.length() == extraBits.length(),
|
||||||
"Original and Extra Bits strings must be identical length");
|
"Original and Extra Bits strings must be identical length");
|
||||||
|
|
||||||
char[] replacement = new char[extraBits.length()];
|
char[] replacement = new char[extraBits.length()];
|
||||||
|
|
||||||
for (int i = 0; i < extraBits.length(); i++) {
|
for (int i = 0; i < extraBits.length(); i++) {
|
||||||
if (extraBits.charAt(i) == Permission.RESERVED_OFF) {
|
if (extraBits.charAt(i) == Permission.RESERVED_OFF) {
|
||||||
replacement[i] = original.charAt(i);
|
replacement[i] = original.charAt(i);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
replacement[i] = extraBits.charAt(i);
|
replacement[i] = extraBits.charAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new String(replacement);
|
return new String(replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a representation of the active bits in the presented mask, with each active
|
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
|
||||||
* bit being denoted by character '*'.
|
* character '*'.
|
||||||
* <p>
|
* <p>
|
||||||
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
||||||
|
*
|
||||||
* @param i the integer bit mask to print the active bits for
|
* @param i the integer bit mask to print the active bits for
|
||||||
|
*
|
||||||
* @return a 32-character representation of the bit mask
|
* @return a 32-character representation of the bit mask
|
||||||
*/
|
*/
|
||||||
public static String printBinary(int i) {
|
public static String printBinary(int i) {
|
||||||
@@ -73,27 +78,30 @@ public abstract class AclFormattingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a representation of the active bits in the presented mask, with each active
|
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
|
||||||
* bit being denoted by the passed character.
|
* the passed character.
|
||||||
* <p>
|
* <p>
|
||||||
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
||||||
|
*
|
||||||
* @param mask the integer bit mask to print the active bits for
|
* @param mask the integer bit mask to print the active bits for
|
||||||
* @param code the character to print when an active bit is detected
|
* @param code the character to print when an active bit is detected
|
||||||
|
*
|
||||||
* @return a 32-character representation of the bit mask
|
* @return a 32-character representation of the bit mask
|
||||||
*/
|
*/
|
||||||
public static String printBinary(int mask, char code) {
|
public static String printBinary(int mask, char code) {
|
||||||
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_ON),
|
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_ON),
|
||||||
() -> Permission.RESERVED_ON + " is a reserved character code");
|
Permission.RESERVED_ON + " is a reserved character code");
|
||||||
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_OFF),
|
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_OFF),
|
||||||
() -> Permission.RESERVED_OFF + " is a reserved character code");
|
Permission.RESERVED_OFF + " is a reserved character code");
|
||||||
|
|
||||||
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, 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) {
|
private static String printBinary(int i, char on, char off) {
|
||||||
String s = Integer.toBinaryString(i);
|
String s = Integer.toString(i, 2);
|
||||||
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
|
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
|
||||||
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
|
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
|
||||||
|
|
||||||
return temp2.replace('0', off).replace('1', on);
|
return temp2.replace('0', off).replace('1', on);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -28,11 +26,10 @@ import org.springframework.security.acls.model.NotFoundException;
|
|||||||
import org.springframework.security.acls.model.ObjectIdentity;
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
import org.springframework.security.acls.model.OwnershipAcl;
|
import org.springframework.security.acls.model.OwnershipAcl;
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.security.acls.model.UnloadedSidException;
|
import org.springframework.security.acls.model.UnloadedSidException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base implementation of <code>Acl</code>.
|
* Base implementation of <code>Acl</code>.
|
||||||
@@ -40,31 +37,24 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private Acl parentAcl;
|
private Acl parentAcl;
|
||||||
|
|
||||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||||
|
private transient AuditLogger auditLogger;
|
||||||
private transient PermissionGrantingStrategy permissionGrantingStrategy;
|
private List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
|
||||||
|
|
||||||
private final List<AccessControlEntry> aces = new ArrayList<>();
|
|
||||||
|
|
||||||
private ObjectIdentity objectIdentity;
|
private ObjectIdentity objectIdentity;
|
||||||
|
|
||||||
private Serializable id;
|
private Serializable id;
|
||||||
|
private Sid owner; // OwnershipAcl
|
||||||
// OwnershipAcl
|
private List<Sid> loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||||
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 boolean entriesInheriting = true;
|
private boolean entriesInheriting = true;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimal constructor, which should be used
|
* Minimal constructor, which should be used {@link
|
||||||
* {@link org.springframework.security.acls.model.MutableAclService#createAcl(ObjectIdentity)}
|
* org.springframework.security.acls.model.MutableAclService#createAcl(ObjectIdentity)}.
|
||||||
* .
|
*
|
||||||
* @param objectIdentity the object identity this ACL relates to (required)
|
* @param objectIdentity the object identity this ACL relates to (required)
|
||||||
* @param id the primary key assigned to this ACL (required)
|
* @param id the primary key assigned to this ACL (required)
|
||||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||||
@@ -79,53 +69,55 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
|||||||
this.objectIdentity = objectIdentity;
|
this.objectIdentity = objectIdentity;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||||
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
|
this.auditLogger = auditLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full constructor, which should be used by persistence tools that do not provide
|
* Full constructor, which should be used by persistence tools that do not
|
||||||
* field-level access features.
|
* provide field-level access features.
|
||||||
* @param objectIdentity the object identity this ACL relates to
|
*
|
||||||
* @param id the primary key assigned to this ACL
|
* @param objectIdentity the object identity this ACL relates to (required)
|
||||||
* @param aclAuthorizationStrategy authorization strategy
|
* @param id the primary key assigned to this ACL (required)
|
||||||
* @param grantingStrategy the {@code PermissionGrantingStrategy} which will be used
|
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||||
* by the {@code isGranted()} method
|
* @param auditLogger audit logger (required)
|
||||||
* @param parentAcl the parent (may be may be {@code null})
|
* @param parentAcl the parent (may be <code>null</code>)
|
||||||
* @param loadedSids the loaded SIDs if only a subset were loaded (may be {@code null}
|
* @param loadedSids the loaded SIDs if only a subset were loaded (may be
|
||||||
* )
|
* <code>null</code>)
|
||||||
* @param entriesInheriting if ACEs from the parent should inherit into this ACL
|
* @param entriesInheriting if ACEs from the parent should inherit into
|
||||||
|
* this ACL
|
||||||
* @param owner the owner (required)
|
* @param owner the owner (required)
|
||||||
*/
|
*/
|
||||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||||
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting,
|
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
|
||||||
Sid owner) {
|
|
||||||
Assert.notNull(objectIdentity, "Object Identity required");
|
Assert.notNull(objectIdentity, "Object Identity required");
|
||||||
Assert.notNull(id, "Id required");
|
Assert.notNull(id, "Id required");
|
||||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||||
Assert.notNull(owner, "Owner required");
|
Assert.notNull(owner, "Owner required");
|
||||||
|
Assert.notNull(auditLogger, "AuditLogger required");
|
||||||
this.objectIdentity = objectIdentity;
|
this.objectIdentity = objectIdentity;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||||
|
this.auditLogger = auditLogger;
|
||||||
this.parentAcl = parentAcl; // may be null
|
this.parentAcl = parentAcl; // may be null
|
||||||
this.loadedSids = loadedSids; // may be null
|
this.loadedSids = loadedSids; // may be null
|
||||||
this.entriesInheriting = entriesInheriting;
|
this.entriesInheriting = entriesInheriting;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.permissionGrantingStrategy = grantingStrategy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private no-argument constructor for use by reflection-based persistence tools along
|
* Private no-argument constructor for use by reflection-based persistence
|
||||||
* with field-level access.
|
* tools along with field-level access.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private AclImpl() {
|
private AclImpl() {}
|
||||||
}
|
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteAce(int aceIndex) throws NotFoundException {
|
public void deleteAce(int aceIndex) throws NotFoundException {
|
||||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||||
verifyAceIndexExists(aceIndex);
|
verifyAceIndexExists(aceIndex);
|
||||||
synchronized (this.aces) {
|
|
||||||
|
synchronized (aces) {
|
||||||
this.aces.remove(aceIndex);
|
this.aces.remove(aceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,87 +127,166 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
|||||||
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
||||||
}
|
}
|
||||||
if (aceIndex >= this.aces.size()) {
|
if (aceIndex >= this.aces.size()) {
|
||||||
throw new NotFoundException("aceIndex must refer to an index of the AccessControlEntry list. "
|
throw new NotFoundException("aceIndex must refer to an index of the AccessControlEntry list. " +
|
||||||
+ "List size is " + this.aces.size() + ", index was " + aceIndex);
|
"List size is " + aces.size() + ", index was " + aceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting) throws NotFoundException {
|
||||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||||
throws NotFoundException {
|
|
||||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
|
||||||
Assert.notNull(permission, "Permission required");
|
Assert.notNull(permission, "Permission required");
|
||||||
Assert.notNull(sid, "Sid required");
|
Assert.notNull(sid, "Sid required");
|
||||||
if (atIndexLocation < 0) {
|
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()) {
|
if (atIndexLocation > this.aces.size()) {
|
||||||
throw new NotFoundException(
|
throw new NotFoundException("atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
|
||||||
"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);
|
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
|
||||||
synchronized (this.aces) {
|
|
||||||
|
synchronized (aces) {
|
||||||
this.aces.add(atIndexLocation, ace);
|
this.aces.add(atIndexLocation, ace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AccessControlEntry> getEntries() {
|
public List<AccessControlEntry> getEntries() {
|
||||||
// Can safely return AccessControlEntry directly, as they're immutable outside the
|
// Can safely return AccessControlEntry directly, as they're immutable outside the ACL package
|
||||||
// ACL package
|
return new ArrayList<AccessControlEntry>(aces);
|
||||||
return new ArrayList<>(this.aces);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable getId() {
|
public Serializable getId() {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectIdentity getObjectIdentity() {
|
public ObjectIdentity getObjectIdentity() {
|
||||||
return this.objectIdentity;
|
return objectIdentity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEntriesInheriting() {
|
public boolean isEntriesInheriting() {
|
||||||
return this.entriesInheriting;
|
return entriesInheriting;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegates to the {@link PermissionGrantingStrategy}.
|
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
|
||||||
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the
|
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
|
||||||
* ACL was only loaded for a subset of SIDs
|
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
|
||||||
* @see DefaultPermissionGrantingStrategy
|
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
|
||||||
|
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
|
||||||
|
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
|
||||||
|
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
|
||||||
|
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
|
||||||
|
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
|
||||||
|
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
|
||||||
|
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
|
||||||
|
* the parent ACL will be tried (provided that there is a parent and {@link #isEntriesInheriting()} is
|
||||||
|
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
|
||||||
|
* a <code>NotFoundException</code> will be thrown and the caller will need to 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
|
||||||
|
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the ACL was only loaded for a
|
||||||
|
* subset of SIDs
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||||
throws NotFoundException, UnloadedSidException {
|
throws NotFoundException, UnloadedSidException {
|
||||||
Assert.notEmpty(permission, "Permissions required");
|
Assert.notEmpty(permission, "Permissions required");
|
||||||
Assert.notEmpty(sids, "SIDs required");
|
Assert.notEmpty(sids, "SIDs required");
|
||||||
|
|
||||||
if (!this.isSidLoaded(sids)) {
|
if (!this.isSidLoaded(sids)) {
|
||||||
throw new UnloadedSidException("ACL was not loaded for one or more SID");
|
throw new UnloadedSidException("ACL was not loaded for one or more SID");
|
||||||
}
|
}
|
||||||
return this.permissionGrantingStrategy.isGranted(this, permission, sids, administrativeMode);
|
|
||||||
|
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 ((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) {
|
||||||
|
auditLogger.logIfNeeded(true, ace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failure for this permission, so stop search
|
||||||
|
// We will see if they have a different permission
|
||||||
|
// (this permission is 100% rejected for this SID)
|
||||||
|
if (firstRejection == null) {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstRejection != null) {
|
||||||
|
// We found an ACE to reject the request at this point, as no
|
||||||
|
// other ACEs were found that granted a different permission
|
||||||
|
if (!administrativeMode) {
|
||||||
|
auditLogger.logIfNeeded(false, firstRejection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matches have been found so far
|
||||||
|
if (isEntriesInheriting() && (parentAcl != null)) {
|
||||||
|
// We have a parent, so let them try to find a matching ACE
|
||||||
|
return parentAcl.isGranted(permission, sids, false);
|
||||||
|
} 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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSidLoaded(List<Sid> sids) {
|
public boolean isSidLoaded(List<Sid> sids) {
|
||||||
// If loadedSides is null, this indicates all SIDs were loaded
|
// If loadedSides is null, this indicates all SIDs were loaded
|
||||||
// Also return true if the caller didn't specify a SID to find
|
// Also return true if the caller didn't specify a SID to find
|
||||||
if ((this.loadedSids == null) || (sids == null) || sids.isEmpty()) {
|
if ((this.loadedSids == null) || (sids == null) || (sids.size() == 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This ACL applies to a SID subset only. Iterate to check it applies.
|
// This ACL applies to a SID subset only. Iterate to check it applies.
|
||||||
for (Sid sid: sids) {
|
for (Sid sid: sids) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (Sid loadedSid : this.loadedSids) {
|
|
||||||
|
for (Sid loadedSid : loadedSids) {
|
||||||
if (sid.equals(loadedSid)) {
|
if (sid.equals(loadedSid)) {
|
||||||
// this SID is OK
|
// this SID is OK
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
break; // out of loadedSids for loop
|
break; // out of loadedSids for loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -224,117 +295,114 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEntriesInheriting(boolean entriesInheriting) {
|
public void setEntriesInheriting(boolean entriesInheriting) {
|
||||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||||
this.entriesInheriting = entriesInheriting;
|
this.entriesInheriting = entriesInheriting;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOwner(Sid newOwner) {
|
public void setOwner(Sid newOwner) {
|
||||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||||
Assert.notNull(newOwner, "Owner required");
|
Assert.notNull(newOwner, "Owner required");
|
||||||
this.owner = newOwner;
|
this.owner = newOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Sid getOwner() {
|
public Sid getOwner() {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setParent(Acl newParent) {
|
public void setParent(Acl newParent) {
|
||||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||||
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
||||||
this.parentAcl = newParent;
|
this.parentAcl = newParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Acl getParentAcl() {
|
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);
|
|
||||||
verifyAceIndexExists(aceIndex);
|
|
||||||
synchronized (this.aces) {
|
|
||||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) this.aces.get(aceIndex);
|
|
||||||
ace.setPermission(permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
|
|
||||||
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
|
|
||||||
verifyAceIndexExists(aceIndex);
|
|
||||||
synchronized (this.aces) {
|
|
||||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) this.aces.get(aceIndex);
|
|
||||||
ace.setAuditSuccess(auditSuccess);
|
|
||||||
ace.setAuditFailure(auditFailure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("AclImpl[");
|
sb.append("AclImpl[");
|
||||||
sb.append("id: ").append(this.id).append("; ");
|
sb.append("id: ").append(this.id).append("; ");
|
||||||
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
||||||
sb.append("owner: ").append(this.owner).append("; ");
|
sb.append("owner: ").append(this.owner).append("; ");
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (AccessControlEntry ace : this.aces) {
|
|
||||||
|
for (AccessControlEntry ace : aces) {
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
sb.append("\n");
|
sb.append("\r\n");
|
||||||
}
|
}
|
||||||
sb.append(ace).append("\n");
|
|
||||||
|
sb.append(ace).append("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
sb.append("no ACEs; ");
|
sb.append("no ACEs; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
|
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("; ");
|
||||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
||||||
sb.append("permissionGrantingStrategy: ").append(this.permissionGrantingStrategy);
|
sb.append("auditLogger: ").append(this.auditLogger);
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateAce(int aceIndex, Permission permission)
|
||||||
|
throws NotFoundException {
|
||||||
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||||
|
verifyAceIndexExists(aceIndex);
|
||||||
|
|
||||||
|
synchronized (aces) {
|
||||||
|
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||||
|
ace.setPermission(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
|
||||||
|
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||||
|
verifyAceIndexExists(aceIndex);
|
||||||
|
|
||||||
|
synchronized (aces) {
|
||||||
|
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||||
|
ace.setAuditSuccess(auditSuccess);
|
||||||
|
ace.setAuditFailure(auditFailure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof AclImpl) {
|
||||||
|
AclImpl rhs = (AclImpl) obj;
|
||||||
|
if (this.aces.equals(rhs.aces)) {
|
||||||
|
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
||||||
|
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||||
|
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
||||||
|
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
||||||
|
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||||
|
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,18 +12,19 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.AccessControlEntry;
|
import org.springframework.security.acls.model.AccessControlEntry;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by <code>AclImpl</code> to log audit events.
|
* Used by <code>AclImpl</code> to log audit events.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface AuditLogger {
|
public interface AuditLogger {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
void logIfNeeded(boolean granted, AccessControlEntry ace);
|
void logIfNeeded(boolean granted, AccessControlEntry ace);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,11 +12,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of standard permissions.
|
* A set of standard permissions.
|
||||||
*
|
*
|
||||||
@@ -29,15 +28,10 @@ import org.springframework.security.acls.model.Permission;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class BasePermission extends AbstractPermission {
|
public class BasePermission extends AbstractPermission {
|
||||||
|
|
||||||
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
|
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 WRITE = new BasePermission(1 << 1, 'W'); // 2
|
||||||
|
|
||||||
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
|
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 DELETE = new BasePermission(1 << 3, 'D'); // 8
|
||||||
|
|
||||||
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
||||||
|
|
||||||
protected BasePermission(int mask) {
|
protected BasePermission(int mask) {
|
||||||
@@ -47,5 +41,4 @@ public class BasePermission extends AbstractPermission {
|
|||||||
protected BasePermission(int mask, char code) {
|
protected BasePermission(int mask, char code) {
|
||||||
super(mask, code);
|
super(mask, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,32 +12,33 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.AccessControlEntry;
|
import org.springframework.security.acls.model.AccessControlEntry;
|
||||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic implementation of {@link AuditLogger}.
|
* A basic implementation of {@link AuditLogger}.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class ConsoleAuditLogger implements AuditLogger {
|
public class ConsoleAuditLogger implements AuditLogger {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
|
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
|
||||||
Assert.notNull(ace, "AccessControlEntry required");
|
Assert.notNull(ace, "AccessControlEntry required");
|
||||||
|
|
||||||
if (ace instanceof AuditableAccessControlEntry) {
|
if (ace instanceof AuditableAccessControlEntry) {
|
||||||
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
|
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
|
||||||
|
|
||||||
if (granted && auditableAce.isAuditSuccess()) {
|
if (granted && auditableAce.isAuditSuccess()) {
|
||||||
System.out.println("GRANTED due to ACE: " + ace);
|
System.out.println("GRANTED due to ACE: " + ace);
|
||||||
}
|
} else if (!granted && auditableAce.isAuditFailure()) {
|
||||||
else if (!granted && auditableAce.isAuditFailure()) {
|
|
||||||
System.out.println("DENIED due to ACE: " + ace);
|
System.out.println("DENIED due to ACE: " + ace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-10
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,18 +12,15 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a <code>Permission</code> that is constructed at runtime from other
|
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.
|
||||||
* permissions.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>Methods return <code>this</code>, in order to facilitate method chaining.</p>
|
||||||
* Methods return <code>this</code>, in order to facilitate method chaining.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
@@ -39,22 +35,24 @@ public class CumulativePermission extends AbstractPermission {
|
|||||||
public CumulativePermission clear(Permission permission) {
|
public CumulativePermission clear(Permission permission) {
|
||||||
this.mask &= ~permission.getMask();
|
this.mask &= ~permission.getMask();
|
||||||
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
|
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CumulativePermission clear() {
|
public CumulativePermission clear() {
|
||||||
this.mask = 0;
|
this.mask = 0;
|
||||||
this.pattern = THIRTY_TWO_RESERVED_OFF;
|
this.pattern = THIRTY_TWO_RESERVED_OFF;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CumulativePermission set(Permission permission) {
|
public CumulativePermission set(Permission permission) {
|
||||||
this.mask |= permission.getMask();
|
this.mask |= permission.getMask();
|
||||||
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
|
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPattern() {
|
public String getPattern() {
|
||||||
return this.pattern;
|
return this.pattern;
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-51
@@ -1,19 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@@ -29,8 +13,8 @@ import org.springframework.util.Assert;
|
|||||||
/**
|
/**
|
||||||
* Default implementation of {@link PermissionFactory}.
|
* Default implementation of {@link PermissionFactory}.
|
||||||
* <p>
|
* <p>
|
||||||
* Used as a strategy by classes which wish to map integer masks and permission names to
|
* Used as a strategy by classes which wish to map integer masks and permission names to <tt>Permission</tt>
|
||||||
* <tt>Permission</tt> instances for use with the ACL implementation.
|
* instances for use with the ACL implementation.
|
||||||
* <p>
|
* <p>
|
||||||
* Maintains a registry of permission names and masks to <tt>Permission</tt> instances.
|
* Maintains a registry of permission names and masks to <tt>Permission</tt> instances.
|
||||||
*
|
*
|
||||||
@@ -39,10 +23,8 @@ import org.springframework.util.Assert;
|
|||||||
* @since 2.0.3
|
* @since 2.0.3
|
||||||
*/
|
*/
|
||||||
public class DefaultPermissionFactory implements PermissionFactory {
|
public class DefaultPermissionFactory implements PermissionFactory {
|
||||||
|
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<Integer, Permission>();
|
||||||
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<>();
|
private final Map<String, Permission> registeredPermissionsByName = new HashMap<String, Permission>();
|
||||||
|
|
||||||
private final Map<String, Permission> registeredPermissionsByName = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the <tt>Permission</tt> fields from the <tt>BasePermission</tt> class.
|
* Registers the <tt>Permission</tt> fields from the <tt>BasePermission</tt> class.
|
||||||
@@ -60,6 +42,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a map of named <tt>Permission</tt> instances.
|
* Registers a map of named <tt>Permission</tt> instances.
|
||||||
|
*
|
||||||
* @param namedPermissions the map of <tt>Permission</tt>s, keyed by name.
|
* @param namedPermissions the map of <tt>Permission</tt>s, keyed by name.
|
||||||
*/
|
*/
|
||||||
public DefaultPermissionFactory(Map<String, ? extends Permission> namedPermissions) {
|
public DefaultPermissionFactory(Map<String, ? extends Permission> namedPermissions) {
|
||||||
@@ -71,82 +54,92 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
|||||||
/**
|
/**
|
||||||
* Registers the public static fields of type {@link Permission} for a give class.
|
* Registers the public static fields of type {@link Permission} for a give class.
|
||||||
* <p>
|
* <p>
|
||||||
* These permissions will be registered under the name of the field. See
|
* These permissions will be registered under the name of the field. See {@link BasePermission}
|
||||||
* {@link BasePermission} for an example.
|
* for an example.
|
||||||
|
*
|
||||||
* @param clazz a {@link Permission} class with public static fields to register
|
* @param clazz a {@link Permission} class with public static fields to register
|
||||||
*/
|
*/
|
||||||
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
|
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
|
||||||
Assert.notNull(clazz, "Class required");
|
Assert.notNull(clazz, "Class required");
|
||||||
|
|
||||||
Field[] fields = clazz.getFields();
|
Field[] fields = clazz.getFields();
|
||||||
for (Field field : fields) {
|
|
||||||
|
for (int i = 0; i < fields.length; i++) {
|
||||||
try {
|
try {
|
||||||
Object fieldValue = field.get(null);
|
Object fieldValue = fields[i].get(null);
|
||||||
|
|
||||||
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
|
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||||
// Found a Permission static field
|
// Found a Permission static field
|
||||||
Permission perm = (Permission) fieldValue;
|
Permission perm = (Permission) fieldValue;
|
||||||
String permissionName = field.getName();
|
String permissionName = fields[i].getName();
|
||||||
|
|
||||||
registerPermission(perm, permissionName);
|
registerPermission(perm, permissionName);
|
||||||
}
|
}
|
||||||
}
|
} catch (Exception ignore) {}
|
||||||
catch (Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void registerPermission(Permission perm, String permissionName) {
|
protected void registerPermission(Permission perm, String permissionName) {
|
||||||
Assert.notNull(perm, "Permission required");
|
Assert.notNull(perm, "Permission required");
|
||||||
Assert.hasText(permissionName, "Permission name required");
|
Assert.hasText(permissionName, "Permission name required");
|
||||||
Integer mask = perm.getMask();
|
|
||||||
|
Integer mask = new Integer(perm.getMask());
|
||||||
|
|
||||||
// Ensure no existing Permission uses this integer or code
|
// Ensure no existing Permission uses this integer or code
|
||||||
Assert.isTrue(!this.registeredPermissionsByInteger.containsKey(mask),
|
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
|
||||||
() -> "An existing Permission already provides mask " + mask);
|
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
|
||||||
Assert.isTrue(!this.registeredPermissionsByName.containsKey(permissionName),
|
|
||||||
() -> "An existing Permission already provides name '" + permissionName + "'");
|
|
||||||
|
|
||||||
// Register the new Permission
|
// Register the new Permission
|
||||||
this.registeredPermissionsByInteger.put(mask, perm);
|
registeredPermissionsByInteger.put(mask, perm);
|
||||||
this.registeredPermissionsByName.put(permissionName, perm);
|
registeredPermissionsByName.put(permissionName, perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Permission buildFromMask(int mask) {
|
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
|
// The requested mask has an exact match against a statically-defined Permission, so return it
|
||||||
// Permission, so return it
|
return registeredPermissionsByInteger.get(new Integer(mask));
|
||||||
return this.registeredPermissionsByInteger.get(mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// To get this far, we have to use a CumulativePermission
|
// To get this far, we have to use a CumulativePermission
|
||||||
CumulativePermission permission = new CumulativePermission();
|
CumulativePermission permission = new CumulativePermission();
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
int permissionToCheck = 1 << i;
|
int permissionToCheck = 1 << i;
|
||||||
|
|
||||||
if ((mask & permissionToCheck) == permissionToCheck) {
|
if ((mask & permissionToCheck) == permissionToCheck) {
|
||||||
Permission p = this.registeredPermissionsByInteger.get(permissionToCheck);
|
Permission p = registeredPermissionsByInteger.get(Integer.valueOf(permissionToCheck));
|
||||||
Assert.state(p != null,
|
|
||||||
() -> "Mask '" + permissionToCheck + "' does not have a corresponding static Permission");
|
if (p == null) {
|
||||||
|
throw new IllegalStateException("Mask '" + permissionToCheck + "' does not have a corresponding static Permission");
|
||||||
|
}
|
||||||
permission.set(p);
|
permission.set(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return permission;
|
return permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Permission buildFromName(String name) {
|
public Permission buildFromName(String name) {
|
||||||
Permission p = this.registeredPermissionsByName.get(name);
|
Permission p = registeredPermissionsByName.get(name);
|
||||||
Assert.notNull(p, "Unknown permission '" + name + "'");
|
|
||||||
|
if (p == null) {
|
||||||
|
throw new IllegalArgumentException("Unknown permission '" + name + "'");
|
||||||
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Permission> buildFromNames(List<String> names) {
|
public List<Permission> buildFromNames(List<String> names) {
|
||||||
if ((names == null) || names.isEmpty()) {
|
if ((names == null) || (names.size() == 0)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<Permission> permissions = new ArrayList<>(names.size());
|
|
||||||
|
List<Permission> permissions = new ArrayList<Permission>(names.size());
|
||||||
|
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
permissions.add(buildFromName(name));
|
permissions.add(buildFromName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return permissions;
|
return permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-151
@@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.domain;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.security.acls.model.AccessControlEntry;
|
|
||||||
import org.springframework.security.acls.model.Acl;
|
|
||||||
import org.springframework.security.acls.model.NotFoundException;
|
|
||||||
import org.springframework.security.acls.model.Permission;
|
|
||||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
public class DefaultPermissionGrantingStrategy implements PermissionGrantingStrategy {
|
|
||||||
|
|
||||||
private final transient AuditLogger auditLogger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance with the logger which will be used to record granting and
|
|
||||||
* denial of requested permissions.
|
|
||||||
*/
|
|
||||||
public DefaultPermissionGrantingStrategy(AuditLogger auditLogger) {
|
|
||||||
Assert.notNull(auditLogger, "auditLogger cannot be null");
|
|
||||||
this.auditLogger = auditLogger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines authorization. The order of the <code>permission</code> and
|
|
||||||
* <code>sid</code> arguments is <em>extremely important</em>! The method will iterate
|
|
||||||
* through each of the <code>permission</code>s in the order specified. For each
|
|
||||||
* iteration, all of the <code>sid</code>s will be considered, again in the order they
|
|
||||||
* are presented. A search will then be performed for the first
|
|
||||||
* {@link AccessControlEntry} object that directly matches that
|
|
||||||
* <code>permission:sid</code> combination. When the <em>first full match</em> is
|
|
||||||
* found (ie an ACE that has the SID currently being searched for and the exact
|
|
||||||
* permission bit mask being search for), the grant or deny flag for that ACE will
|
|
||||||
* prevail. If the ACE specifies to grant access, the method will return
|
|
||||||
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the
|
|
||||||
* next <code>permission</code> iteration will be performed. If each permission
|
|
||||||
* indicates to deny access, the first deny ACE found will be considered the reason
|
|
||||||
* for the failure (as it was the first match found, and is therefore the one most
|
|
||||||
* logically requiring changes - although not always). If absolutely no matching ACE
|
|
||||||
* was found at all for any permission, the parent ACL will be tried (provided that
|
|
||||||
* there is a parent and {@link Acl#isEntriesInheriting()} is <code>true</code>. The
|
|
||||||
* parent ACL will also scan its parent and so on. If ultimately no matching ACE is
|
|
||||||
* found, a <code>NotFoundException</code> will be thrown and the caller will need to
|
|
||||||
* 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();
|
|
||||||
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)) {
|
|
||||||
// Found a matching ACE, so its authorization decision will
|
|
||||||
// prevail
|
|
||||||
if (ace.isGranting()) {
|
|
||||||
// Success
|
|
||||||
if (!administrativeMode) {
|
|
||||||
this.auditLogger.logIfNeeded(true, ace);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failure for this permission, so stop search
|
|
||||||
// We will see if they have a different permission
|
|
||||||
// (this permission is 100% rejected for this SID)
|
|
||||||
if (firstRejection == null) {
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstRejection != null) {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No matches have been found so far
|
|
||||||
if (acl.isEntriesInheriting() && (acl.getParentAcl() != null)) {
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/* 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import net.sf.ehcache.CacheException;
|
||||||
|
import net.sf.ehcache.Ehcache;
|
||||||
|
import net.sf.ehcache.Element;
|
||||||
|
|
||||||
|
import org.springframework.security.acls.model.AclCache;
|
||||||
|
import org.springframework.security.acls.model.MutableAcl;
|
||||||
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
|
import org.springframework.security.util.FieldUtils;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
|
||||||
|
* {@link AclImpl} instances share the same {@link AuditLogger} and {@link AclAuthorizationStrategy} instance.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
*/
|
||||||
|
public class EhCacheBasedAclCache implements AclCache {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
|
private Ehcache cache;
|
||||||
|
private AuditLogger auditLogger;
|
||||||
|
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
|
public EhCacheBasedAclCache(Ehcache cache) {
|
||||||
|
Assert.notNull(cache, "Cache required");
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
public void evictFromCache(Serializable pk) {
|
||||||
|
Assert.notNull(pk, "Primary key (identifier) required");
|
||||||
|
|
||||||
|
MutableAcl acl = getFromCache(pk);
|
||||||
|
|
||||||
|
if (acl != null) {
|
||||||
|
cache.remove(acl.getId());
|
||||||
|
cache.remove(acl.getObjectIdentity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictFromCache(ObjectIdentity objectIdentity) {
|
||||||
|
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||||
|
|
||||||
|
MutableAcl acl = getFromCache(objectIdentity);
|
||||||
|
|
||||||
|
if (acl != null) {
|
||||||
|
cache.remove(acl.getId());
|
||||||
|
cache.remove(acl.getObjectIdentity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
|
||||||
|
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||||
|
|
||||||
|
Element element = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
element = cache.get(objectIdentity);
|
||||||
|
} catch (CacheException ignored) {}
|
||||||
|
|
||||||
|
if (element == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initializeTransientFields((MutableAcl)element.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableAcl getFromCache(Serializable pk) {
|
||||||
|
Assert.notNull(pk, "Primary key (identifier) required");
|
||||||
|
|
||||||
|
Element element = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
element = cache.get(pk);
|
||||||
|
} catch (CacheException ignored) {}
|
||||||
|
|
||||||
|
if (element == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initializeTransientFields((MutableAcl) element.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getProtectedFieldValue("aclAuthorizationStrategy", acl);
|
||||||
|
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
|
||||||
|
putInCache((MutableAcl) acl.getParentAcl());
|
||||||
|
}
|
||||||
|
|
||||||
|
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("auditLogger", value, this.auditLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.getParentAcl() != null) {
|
||||||
|
initializeTransientFields((MutableAcl) value.getParentAcl());
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCache() {
|
||||||
|
cache.removeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-18
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,26 +12,27 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a <code>GrantedAuthority</code> as a <code>Sid</code>.
|
* Represents a <code>GrantedAuthority</code> as a <code>Sid</code>.<p>This is a basic implementation that simply
|
||||||
* <p>
|
* uses the <code>String</code>-based principal for <code>Sid</code> comparison. More complex principal objects may
|
||||||
* This is a basic implementation that simply uses the <code>String</code>-based principal
|
* wish to provide an alternative <code>Sid</code> implementation that uses some other identifier.</p>
|
||||||
* for <code>Sid</code> comparison. More complex principal objects may wish to provide an
|
|
||||||
* alternative <code>Sid</code> implementation that uses some other identifier.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class GrantedAuthoritySid implements Sid {
|
public class GrantedAuthoritySid implements Sid {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final String grantedAuthority;
|
private String grantedAuthority;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public GrantedAuthoritySid(String grantedAuthority) {
|
public GrantedAuthoritySid(String grantedAuthority) {
|
||||||
Assert.hasText(grantedAuthority, "GrantedAuthority required");
|
Assert.hasText(grantedAuthority, "GrantedAuthority required");
|
||||||
@@ -46,28 +46,26 @@ public class GrantedAuthoritySid implements Sid {
|
|||||||
this.grantedAuthority = grantedAuthority.getAuthority();
|
this.grantedAuthority = grantedAuthority.getAuthority();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public boolean equals(Object object) {
|
public boolean equals(Object object) {
|
||||||
if ((object == null) || !(object instanceof GrantedAuthoritySid)) {
|
if ((object == null) || !(object instanceof GrantedAuthoritySid)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Delegate to getGrantedAuthority() to perform actual comparison (both should be
|
|
||||||
// identical)
|
// 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() {
|
public int hashCode() {
|
||||||
return this.getGrantedAuthority().hashCode();
|
return this.getGrantedAuthority().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGrantedAuthority() {
|
public String getGrantedAuthority() {
|
||||||
return this.grantedAuthority;
|
return grantedAuthority;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
|
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,9 +20,11 @@ package org.springframework.security.acls.domain;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class IdentityUnavailableException extends RuntimeException {
|
public class IdentityUnavailableException extends RuntimeException {
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
|
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public IdentityUnavailableException(String msg) {
|
public IdentityUnavailableException(String msg) {
|
||||||
@@ -34,11 +34,11 @@ public class IdentityUnavailableException extends RuntimeException {
|
|||||||
/**
|
/**
|
||||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message
|
* Constructs an <code>IdentityUnavailableException</code> with the specified message
|
||||||
* and root cause.
|
* and root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
* @param cause root cause
|
* @param t root cause
|
||||||
*/
|
*/
|
||||||
public IdentityUnavailableException(String msg, Throwable cause) {
|
public IdentityUnavailableException(String msg, Throwable t) {
|
||||||
super(msg, cause);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-50
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -23,30 +21,33 @@ import org.springframework.security.acls.model.ObjectIdentity;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple implementation of {@link ObjectIdentity}.
|
* Simple implementation of {@link ObjectIdentity}.
|
||||||
* <p>
|
* <p>
|
||||||
* Uses <code>String</code>s to store the identity of the domain object instance. Also
|
* Uses <code>String</code>s to store the identity of the domain object instance. Also offers a constructor that uses
|
||||||
* offers a constructor that uses reflection to build the identity information.
|
* reflection to build the identity information.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class ObjectIdentityImpl implements ObjectIdentity {
|
public class ObjectIdentityImpl implements ObjectIdentity {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
private Serializable identifier;
|
private Serializable identifier;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public ObjectIdentityImpl(String type, Serializable identifier) {
|
public ObjectIdentityImpl(String type, Serializable identifier) {
|
||||||
Assert.hasText(type, "Type required");
|
Assert.hasText(type, "Type required");
|
||||||
Assert.notNull(identifier, "identifier required");
|
Assert.notNull(identifier, "identifier required");
|
||||||
|
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor which uses the name of the supplied class as the <tt>type</tt>
|
* Constructor which uses the name of the supplied class as the <tt>type</tt> property.
|
||||||
* property.
|
|
||||||
*/
|
*/
|
||||||
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
|
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
|
||||||
Assert.notNull(javaType, "Java Type required");
|
Assert.notNull(javaType, "Java Type required");
|
||||||
@@ -56,95 +57,101 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the <code>ObjectIdentityImpl</code> based on the passed object instance.
|
* Creates the <code>ObjectIdentityImpl</code> based on the passed
|
||||||
* The passed object must provide a <code>getId()</code> method, otherwise an
|
* object instance. The passed object must provide a <code>getId()</code>
|
||||||
* exception will be thrown.
|
* method, otherwise an exception will be thrown.
|
||||||
* <p>
|
* <p>
|
||||||
* The class name of the object passed will be considered the {@link #type}, so if
|
* The class name of the object passed will be considered the {@link #type}, so if more control is required,
|
||||||
* more control is required, a different constructor should be used.
|
* a different constructor should be used.
|
||||||
|
*
|
||||||
* @param object the domain object instance to create an identity for.
|
* @param object the domain object instance to create an identity for.
|
||||||
|
*
|
||||||
* @throws IdentityUnavailableException if identity could not be extracted
|
* @throws IdentityUnavailableException if identity could not be extracted
|
||||||
*/
|
*/
|
||||||
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
||||||
Assert.notNull(object, "object cannot be null");
|
Assert.notNull(object, "object cannot be null");
|
||||||
|
|
||||||
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
|
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
|
||||||
this.type = typeClass.getName();
|
type = typeClass.getName();
|
||||||
Object result = invokeGetIdMethod(object, typeClass);
|
|
||||||
|
Object result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Method method = typeClass.getMethod("getId", new Class[] {});
|
||||||
|
result = method.invoke(object, new 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.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;
|
this.identifier = (Serializable) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object invokeGetIdMethod(Object object, Class<?> typeClass) {
|
//~ Methods ========================================================================================================
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Important so caching operates properly.
|
* Important so caching operates properly.
|
||||||
* <p>
|
* <p>
|
||||||
* Considers an object of the same class equal if it has the same
|
* Considers an object of the same class equal if it has the same <code>classname</code> and
|
||||||
* <code>classname</code> and <code>id</code> properties.
|
* <code>id</code> properties.
|
||||||
* <p>
|
* <p>
|
||||||
* Numeric identities (Integer and Long values) are considered equal if they are
|
* Numeric identities (Integer and Long values) are considered equal if they are numerically equal. Other
|
||||||
* numerically equal. Other serializable types are evaluated using a simple equality.
|
* 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
|
* @return <code>true</code> if the presented object matches this object
|
||||||
*/
|
*/
|
||||||
@Override
|
public boolean equals(Object arg0) {
|
||||||
public boolean equals(Object obj) {
|
if (arg0 == null || !(arg0 instanceof ObjectIdentityImpl)) {
|
||||||
if (obj == null || !(obj instanceof ObjectIdentityImpl)) {
|
|
||||||
return false;
|
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
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Use plain equality for other serializable types
|
// Use plain equality for other serializable types
|
||||||
if (!this.identifier.equals(other.identifier)) {
|
if (!identifier.equals(other.identifier)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.type.equals(other.type);
|
|
||||||
|
return type.equals(other.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Serializable getIdentifier() {
|
public Serializable getIdentifier() {
|
||||||
return this.identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return this.type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Important so caching operates properly.
|
* Important so caching operates properly.
|
||||||
|
*
|
||||||
* @return the hash
|
* @return the hash
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = this.type.hashCode();
|
int code = 31;
|
||||||
result = 31 * result + this.identifier.hashCode();
|
code ^= this.type.hashCode();
|
||||||
return result;
|
code ^= this.identifier.hashCode();
|
||||||
|
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(this.getClass().getName()).append("[");
|
sb.append(this.getClass().getName()).append("[");
|
||||||
sb.append("Type: ").append(this.type);
|
sb.append("Type: ").append(this.type);
|
||||||
sb.append("; Identifier: ").append(this.identifier).append("]");
|
sb.append("; Identifier: ").append(this.identifier).append("]");
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-9
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -23,22 +22,19 @@ import org.springframework.security.acls.model.ObjectIdentityGenerator;
|
|||||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} and
|
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} and <tt>ObjectIdentityGenerator</tt>
|
||||||
* <tt>ObjectIdentityGenerator</tt> that uses the constructors of
|
* that uses the constructors of {@link ObjectIdentityImpl} to create the {@link ObjectIdentity}.
|
||||||
* {@link ObjectIdentityImpl} to create the {@link ObjectIdentity}.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {
|
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectIdentity getObjectIdentity(Object domainObject) {
|
public ObjectIdentity getObjectIdentity(Object domainObject) {
|
||||||
return new ObjectIdentityImpl(domainObject);
|
return new ObjectIdentityImpl(domainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectIdentity createObjectIdentity(Serializable id, String type) {
|
public ObjectIdentity createObjectIdentity(Serializable id, String type) {
|
||||||
return new ObjectIdentityImpl(type, id);
|
return new ObjectIdentityImpl(type, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -21,24 +5,27 @@ import java.util.List;
|
|||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a simple mechanism to retrieve {@link Permission} instances from integer
|
* Provides a simple mechanism to retrieve {@link Permission} instances from integer masks.
|
||||||
* masks.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @since 2.0.3
|
* @since 2.0.3
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface PermissionFactory {
|
public interface PermissionFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dynamically creates a <code>CumulativePermission</code> or
|
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
|
||||||
* <code>BasePermission</code> representing the active bits in the passed mask.
|
* active bits in the passed mask.
|
||||||
|
*
|
||||||
* @param mask to build
|
* @param mask to build
|
||||||
|
*
|
||||||
* @return a Permission representing the requested object
|
* @return a Permission representing the requested object
|
||||||
*/
|
*/
|
||||||
Permission buildFromMask(int mask);
|
Permission buildFromMask(int mask);
|
||||||
|
|
||||||
|
|
||||||
Permission buildFromName(String name);
|
Permission buildFromName(String name);
|
||||||
|
|
||||||
List<Permission> buildFromNames(List<String> names);
|
|
||||||
|
|
||||||
|
List<Permission> buildFromNames(List<String> names);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,26 +12,29 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an <code>Authentication.getPrincipal()</code> as a <code>Sid</code>.
|
* Represents an <code>Authentication.getPrincipal()</code> as a <code>Sid</code>.<p>This is a basic implementation
|
||||||
* <p>
|
* that simply uses the <code>String</code>-based principal for <code>Sid</code> comparison. More complex principal
|
||||||
* This is a basic implementation that simply uses the <code>String</code>-based principal
|
* objects may wish to provide an alternative <code>Sid</code> implementation that uses some other identifier.</p>
|
||||||
* for <code>Sid</code> comparison. More complex principal objects may wish to provide an
|
|
||||||
* alternative <code>Sid</code> implementation that uses some other identifier.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class PrincipalSid implements Sid {
|
public class PrincipalSid implements Sid {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private final String principal;
|
private String principal;
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public PrincipalSid(String principal) {
|
public PrincipalSid(String principal) {
|
||||||
Assert.hasText(principal, "Principal required");
|
Assert.hasText(principal, "Principal required");
|
||||||
@@ -42,31 +44,34 @@ public class PrincipalSid implements Sid {
|
|||||||
public PrincipalSid(Authentication authentication) {
|
public PrincipalSid(Authentication authentication) {
|
||||||
Assert.notNull(authentication, "Authentication required");
|
Assert.notNull(authentication, "Authentication required");
|
||||||
Assert.notNull(authentication.getPrincipal(), "Principal 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) {
|
public boolean equals(Object object) {
|
||||||
if ((object == null) || !(object instanceof PrincipalSid)) {
|
if ((object == null) || !(object instanceof PrincipalSid)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Delegate to getPrincipal() to perform actual comparison (both should be
|
|
||||||
// identical)
|
// Delegate to getPrincipal() to perform actual comparison (both should be identical)
|
||||||
return ((PrincipalSid) object).getPrincipal().equals(this.getPrincipal());
|
return ((PrincipalSid) object).getPrincipal().equals(this.getPrincipal());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return this.getPrincipal().hashCode();
|
return this.getPrincipal().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPrincipal() {
|
public String getPrincipal() {
|
||||||
return this.principal;
|
return principal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PrincipalSid[" + this.principal + "]";
|
return "PrincipalSid[" + this.principal + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-14
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -29,13 +28,11 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the
|
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
|
||||||
* principal, as well as every granted authority the principal holds. Can optionally have
|
* every granted authority the principal holds. Can optionally have a <tt>RoleHierarchy</tt> injected in order to
|
||||||
* a <tt>RoleHierarchy</tt> injected in order to determine the extended list of
|
* determine the extended list of authorities that the principal is assigned.
|
||||||
* authorities that the principal is assigned.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The returned array will always contain the {@link PrincipalSid} before any
|
* The returned array will always contain the {@link PrincipalSid} before any {@link GrantedAuthoritySid} elements.
|
||||||
* {@link GrantedAuthoritySid} elements.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
@@ -51,16 +48,18 @@ public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
|
|||||||
this.roleHierarchy = roleHierarchy;
|
this.roleHierarchy = roleHierarchy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public List<Sid> getSids(Authentication authentication) {
|
public List<Sid> getSids(Authentication authentication) {
|
||||||
Collection<? extends GrantedAuthority> authorities = this.roleHierarchy
|
Collection<GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||||
.getReachableGrantedAuthorities(authentication.getAuthorities());
|
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
|
||||||
List<Sid> sids = new ArrayList<>(authorities.size() + 1);
|
|
||||||
sids.add(new PrincipalSid(authentication));
|
sids.add(new PrincipalSid(authentication));
|
||||||
|
|
||||||
for (GrantedAuthority authority : authorities) {
|
for (GrantedAuthority authority : authorities) {
|
||||||
sids.add(new GrantedAuthoritySid(authority));
|
sids.add(new GrantedAuthoritySid(authority));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sids;
|
return sids;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-128
@@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.domain;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import org.springframework.cache.Cache;
|
|
||||||
import org.springframework.security.acls.model.AclCache;
|
|
||||||
import org.springframework.security.acls.model.MutableAcl;
|
|
||||||
import org.springframework.security.acls.model.ObjectIdentity;
|
|
||||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
|
||||||
import org.springframework.security.util.FieldUtils;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple implementation of {@link org.springframework.security.acls.model.AclCache} that
|
|
||||||
* delegates to {@link Cache} implementation.
|
|
||||||
* <p>
|
|
||||||
* Designed to handle the transient fields in
|
|
||||||
* {@link org.springframework.security.acls.domain.AclImpl}. Note that this implementation
|
|
||||||
* assumes all {@link org.springframework.security.acls.domain.AclImpl} instances share
|
|
||||||
* the same {@link org.springframework.security.acls.model.PermissionGrantingStrategy} and
|
|
||||||
* {@link org.springframework.security.acls.domain.AclAuthorizationStrategy} instances.
|
|
||||||
*
|
|
||||||
* @author Marten Deinum
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public class SpringCacheBasedAclCache implements AclCache {
|
|
||||||
|
|
||||||
private final Cache cache;
|
|
||||||
|
|
||||||
private PermissionGrantingStrategy permissionGrantingStrategy;
|
|
||||||
|
|
||||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
|
||||||
|
|
||||||
public SpringCacheBasedAclCache(Cache cache, PermissionGrantingStrategy permissionGrantingStrategy,
|
|
||||||
AclAuthorizationStrategy aclAuthorizationStrategy) {
|
|
||||||
Assert.notNull(cache, "Cache required");
|
|
||||||
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
|
|
||||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
|
||||||
this.cache = cache;
|
|
||||||
this.permissionGrantingStrategy = permissionGrantingStrategy;
|
|
||||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MutableAcl getFromCache(Object key) {
|
|
||||||
Cache.ValueWrapper element = this.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);
|
|
||||||
}
|
|
||||||
if (value.getParentAcl() != null) {
|
|
||||||
initializeTransientFields((MutableAcl) value.getParentAcl());
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearCache() {
|
|
||||||
this.cache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,5 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic implementation of access control lists (ACLs) interfaces.
|
* Basic implementation of access control lists (ACLs) interfaces.
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.acls.domain;
|
package org.springframework.security.acls.domain;
|
||||||
|
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+235
-277
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006, 2017 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.jdbc;
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -31,18 +29,17 @@ import java.util.Set;
|
|||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.springframework.core.convert.ConversionException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.core.convert.ConversionService;
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||||
import org.springframework.security.acls.domain.AclImpl;
|
import org.springframework.security.acls.domain.AclImpl;
|
||||||
import org.springframework.security.acls.domain.AuditLogger;
|
import org.springframework.security.acls.domain.AuditLogger;
|
||||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||||
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
|
|
||||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||||
import org.springframework.security.acls.domain.PermissionFactory;
|
import org.springframework.security.acls.domain.PermissionFactory;
|
||||||
import org.springframework.security.acls.domain.PrincipalSid;
|
import org.springframework.security.acls.domain.PrincipalSid;
|
||||||
import org.springframework.security.acls.model.AccessControlEntry;
|
import org.springframework.security.acls.model.AccessControlEntry;
|
||||||
@@ -51,174 +48,158 @@ import org.springframework.security.acls.model.AclCache;
|
|||||||
import org.springframework.security.acls.model.MutableAcl;
|
import org.springframework.security.acls.model.MutableAcl;
|
||||||
import org.springframework.security.acls.model.NotFoundException;
|
import org.springframework.security.acls.model.NotFoundException;
|
||||||
import org.springframework.security.acls.model.ObjectIdentity;
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
import org.springframework.security.acls.model.ObjectIdentityGenerator;
|
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.security.acls.model.UnloadedSidException;
|
import org.springframework.security.acls.model.UnloadedSidException;
|
||||||
import org.springframework.security.util.FieldUtils;
|
import org.springframework.security.util.FieldUtils;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs lookups in a manner that is compatible with ANSI SQL.
|
* Performs lookups in a manner that is compatible with ANSI SQL.
|
||||||
* <p>
|
* <p>
|
||||||
* NB: This implementation does attempt to provide reasonably optimised lookups - within
|
* NB: This implementation does attempt to provide reasonably optimised lookups - within the constraints of a normalised
|
||||||
* the constraints of a normalised database and standard ANSI SQL features. If you are
|
* database and standard ANSI SQL features. If you are willing to sacrifice either of these constraints
|
||||||
* willing to sacrifice either of these constraints (e.g. use a particular database
|
* (e.g. use a particular database feature such as hierarchical queries or materalized views, or reduce normalisation)
|
||||||
* feature such as hierarchical queries or materalized views, or reduce normalisation) you
|
* you are likely to achieve better performance. In such situations you will need to provide your own custom
|
||||||
* are likely to achieve better performance. In such situations you will need to provide
|
* <code>LookupStrategy</code>. This class does not support subclassing, as it is likely to change in future releases
|
||||||
* your own custom <code>LookupStrategy</code>. This class does not support subclassing,
|
* and therefore subclassing is unsupported.
|
||||||
* as it is likely to change in future releases and therefore subclassing is unsupported.
|
|
||||||
* <p>
|
* <p>
|
||||||
* There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and
|
* There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and one in
|
||||||
* one in <tt>lookupObjectIdentities</tt>. These are built from the same select and "order
|
* <tt>lookupObjectIdentities</tt>. These are built from the same select and "order by" clause, using a different
|
||||||
* by" clause, using a different where clause in each case. In order to use custom schema
|
* where clause in each case. In order to use custom schema or column names, each of these SQL clauses can be
|
||||||
* or column names, each of these SQL clauses can be customized, but they must be
|
* customized, but they must be consistent with each other and with the expected result set
|
||||||
* consistent with each other and with the expected result set generated by the default
|
* generated by the the default values.
|
||||||
* values.
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class BasicLookupStrategy implements LookupStrategy {
|
public final class BasicLookupStrategy implements LookupStrategy {
|
||||||
|
|
||||||
private static final String DEFAULT_SELECT_CLAUSE_COLUMNS = "select acl_object_identity.object_id_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_entry.ace_order, "
|
||||||
+ "acl_object_identity.entries_inheriting, " + "acl_entry.id as ace_id, " + "acl_entry.mask, "
|
+ "acl_object_identity.id as acl_id, "
|
||||||
+ "acl_entry.granting, " + "acl_entry.audit_success, " + "acl_entry.audit_failure, "
|
+ "acl_object_identity.parent_object, "
|
||||||
+ "acl_sid.principal as ace_principal, " + "acl_sid.sid as ace_sid, "
|
+ "acl_object_identity.entries_inheriting, "
|
||||||
+ "acli_sid.principal as acl_principal, " + "acli_sid.sid as acl_sid, " + "acl_class.class ";
|
+ "acl_entry.id as ace_id, "
|
||||||
|
+ "acl_entry.mask, "
|
||||||
private static final String DEFAULT_SELECT_CLAUSE_ACL_CLASS_ID_TYPE_COLUMN = ", acl_class.class_id_type ";
|
+ "acl_entry.granting, "
|
||||||
|
+ "acl_entry.audit_success, "
|
||||||
private static final String DEFAULT_SELECT_CLAUSE_FROM = "from acl_object_identity "
|
+ "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_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_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_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id " + "where ( ";
|
+ "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
|
private final static String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
|
||||||
+ DEFAULT_SELECT_CLAUSE_ACL_CLASS_ID_TYPE_COLUMN + DEFAULT_SELECT_CLAUSE_FROM;
|
|
||||||
|
|
||||||
private static final String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
|
public final static String DEFAULT_ORDER_BY_CLAUSE = ") order by acl_object_identity.object_id_identity"
|
||||||
|
|
||||||
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"
|
|
||||||
+ " asc, acl_entry.ace_order asc";
|
+ " asc, acl_entry.ace_order asc";
|
||||||
|
|
||||||
private final AclAuthorizationStrategy aclAuthorizationStrategy;
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private ObjectIdentityGenerator objectIdentityGenerator;
|
|
||||||
|
|
||||||
|
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||||
|
private AclCache aclCache;
|
||||||
private final AclCache aclCache;
|
private AuditLogger auditLogger;
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
private final PermissionGrantingStrategy grantingStrategy;
|
|
||||||
|
|
||||||
private final JdbcTemplate jdbcTemplate;
|
|
||||||
|
|
||||||
private int batchSize = 50;
|
private int batchSize = 50;
|
||||||
|
|
||||||
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
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
|
// SQL Customization fields
|
||||||
private String selectClause = DEFAULT_SELECT_CLAUSE;
|
private String selectClause = DEFAULT_SELECT_CLAUSE;
|
||||||
|
|
||||||
private String lookupPrimaryKeysWhereClause = DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE;
|
private String lookupPrimaryKeysWhereClause = DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE;
|
||||||
|
|
||||||
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
|
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
|
||||||
|
|
||||||
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
|
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
|
||||||
|
|
||||||
private AclClassIdUtils aclClassIdUtils;
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor accepting mandatory arguments
|
* Constructor accepting mandatory arguments
|
||||||
|
*
|
||||||
* @param dataSource to access the database
|
* @param dataSource to access the database
|
||||||
* @param aclCache the cache where fully-loaded elements can be stored
|
* @param aclCache the cache where fully-loaded elements can be stored
|
||||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||||
*/
|
*/
|
||||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||||
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
|
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger 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) {
|
|
||||||
Assert.notNull(dataSource, "DataSource required");
|
Assert.notNull(dataSource, "DataSource required");
|
||||||
Assert.notNull(aclCache, "AclCache required");
|
Assert.notNull(aclCache, "AclCache required");
|
||||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||||
Assert.notNull(grantingStrategy, "grantingStrategy required");
|
Assert.notNull(auditLogger, "AuditLogger required");
|
||||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
this.aclCache = aclCache;
|
this.aclCache = aclCache;
|
||||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||||
this.grantingStrategy = grantingStrategy;
|
this.auditLogger = auditLogger;
|
||||||
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
fieldAces.setAccessible(true);
|
||||||
this.aclClassIdUtils = new AclClassIdUtils();
|
fieldAcl.setAccessible(true);
|
||||||
this.fieldAces.setAccessible(true);
|
|
||||||
this.fieldAcl.setAccessible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||||
Assert.isTrue(requiredRepetitions > 0, "requiredRepetitions must be > 0");
|
assert requiredRepetitions > 0 : "requiredRepetitions must be > 0";
|
||||||
String startSql = this.selectClause;
|
|
||||||
String endSql = this.orderByClause;
|
final String startSql = selectClause;
|
||||||
StringBuilder sqlStringBldr = new StringBuilder(
|
|
||||||
startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
|
final String endSql = orderByClause;
|
||||||
|
|
||||||
|
StringBuilder sqlStringBldr =
|
||||||
|
new StringBuilder(startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
|
||||||
sqlStringBldr.append(startSql);
|
sqlStringBldr.append(startSql);
|
||||||
|
|
||||||
for (int i = 1; i <= requiredRepetitions; i++) {
|
for (int i = 1; i <= requiredRepetitions; i++) {
|
||||||
sqlStringBldr.append(repeatingSql);
|
sqlStringBldr.append(repeatingSql);
|
||||||
|
|
||||||
if (i != requiredRepetitions) {
|
if (i != requiredRepetitions) {
|
||||||
sqlStringBldr.append(" or ");
|
sqlStringBldr.append(" or ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlStringBldr.append(endSql);
|
sqlStringBldr.append(endSql);
|
||||||
|
|
||||||
return sqlStringBldr.toString();
|
return sqlStringBldr.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private List<AccessControlEntryImpl> readAces(AclImpl acl) {
|
private List<AccessControlEntryImpl> readAces(AclImpl acl) {
|
||||||
try {
|
try {
|
||||||
return (List<AccessControlEntryImpl>) this.fieldAces.get(acl);
|
return (List<AccessControlEntryImpl>) fieldAces.get(acl);
|
||||||
}
|
} catch (IllegalAccessException e) {
|
||||||
catch (IllegalAccessException ex) {
|
throw new IllegalStateException("Could not obtain AclImpl.aces field", e);
|
||||||
throw new IllegalStateException("Could not obtain AclImpl.aces field", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAclOnAce(AccessControlEntryImpl ace, AclImpl acl) {
|
private void setAclOnAce(AccessControlEntryImpl ace, AclImpl acl) {
|
||||||
try {
|
try {
|
||||||
this.fieldAcl.set(ace, acl);
|
fieldAcl.set(ace, acl);
|
||||||
}
|
} catch (IllegalAccessException e) {
|
||||||
catch (IllegalAccessException ex) {
|
throw new IllegalStateException("Could not or set AclImpl on AccessControlEntryImpl fields", e);
|
||||||
throw new IllegalStateException("Could not or set AclImpl on AccessControlEntryImpl fields", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAces(AclImpl acl, List<AccessControlEntryImpl> aces) {
|
private void setAces(AclImpl acl, List<AccessControlEntryImpl> aces) {
|
||||||
try {
|
try {
|
||||||
this.fieldAces.set(acl, aces);
|
fieldAces.set(acl, aces);
|
||||||
}
|
} catch (IllegalAccessException e) {
|
||||||
catch (IllegalAccessException ex) {
|
throw new IllegalStateException("Could not set AclImpl entries", e);
|
||||||
throw new IllegalStateException("Could not set AclImpl entries", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locates the primary key IDs specified in "findNow", adding AclImpl instances with
|
* Locates the primary key IDs specified in "findNow", adding AclImpl instances with StubAclParents to the
|
||||||
* StubAclParents to the "acls" Map.
|
* "acls" Map.
|
||||||
|
*
|
||||||
* @param acls the AclImpls (with StubAclParents)
|
* @param acls the AclImpls (with StubAclParents)
|
||||||
* @param findNow Long-based primary keys to retrieve
|
* @param findNow Long-based primary keys to retrieve
|
||||||
* @param sids
|
* @param sids
|
||||||
@@ -226,126 +207,159 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
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.notNull(acls, "ACLs are required");
|
||||||
Assert.notEmpty(findNow, "Items to find now 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));
|
|
||||||
// Lookup the parents, now that our JdbcTemplate has released the database
|
|
||||||
// connection (SEC-547)
|
|
||||||
if (parentsToLookup.size() > 0) {
|
|
||||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setKeys(PreparedStatement ps, Set<Long> findNow) throws SQLException {
|
String sql = computeRepeatingSql(lookupPrimaryKeysWhereClause, findNow.size());
|
||||||
|
|
||||||
|
Set<Long> parentsToLookup = jdbcTemplate.query(sql,
|
||||||
|
new PreparedStatementSetter() {
|
||||||
|
public void setValues(PreparedStatement ps) throws SQLException {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (Long toFind : findNow) {
|
for (Long toFind : findNow) {
|
||||||
i++;
|
i++;
|
||||||
ps.setLong(i, toFind);
|
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) {
|
||||||
|
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main method.
|
* The main method.
|
||||||
* <p>
|
* <p>
|
||||||
* WARNING: This implementation completely disregards the "sids" argument! Every item
|
* WARNING: This implementation completely disregards the "sids" argument! Every item in the cache is expected to
|
||||||
* in the cache is expected to contain all SIDs. If you have serious performance needs
|
* contain all SIDs. If you have serious performance needs (e.g. a very large number of
|
||||||
* (e.g. a very large number of SIDs per object identity), you'll probably want to
|
* SIDs per object identity), you'll probably want to develop a custom {@link LookupStrategy} implementation
|
||||||
* develop a custom {@link LookupStrategy} implementation instead.
|
* instead.
|
||||||
* <p>
|
* <p>
|
||||||
* The implementation works in batch sizes specified by {@link #batchSize}.
|
* The implementation works in batch sizes specified by {@link #batchSize}.
|
||||||
|
*
|
||||||
* @param objects the identities to lookup (required)
|
* @param objects the identities to lookup (required)
|
||||||
* @param sids the SIDs for which identities are required (ignored by this
|
* @param sids the SIDs for which identities are required (ignored by this implementation)
|
||||||
* implementation)
|
*
|
||||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the
|
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||||
* located {@link Acl} and values are the located {@link Acl} (never <tt>null</tt>
|
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||||
* although some entries may be missing; this method should not throw
|
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||||
* {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used to
|
* to automatically create entries if required)
|
||||||
* automatically create entries if required)
|
|
||||||
*/
|
*/
|
||||||
@Override
|
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||||
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||||
Assert.isTrue(this.batchSize >= 1, "BatchSize must be >= 1");
|
|
||||||
Assert.notEmpty(objects, "Objects to lookup required");
|
Assert.notEmpty(objects, "Objects to lookup required");
|
||||||
|
|
||||||
// Map<ObjectIdentity,Acl>
|
// Map<ObjectIdentity,Acl>
|
||||||
// contains FULLY loaded Acl objects
|
Map<ObjectIdentity, Acl> result = new HashMap<ObjectIdentity, Acl>(); // contains FULLY loaded Acl objects
|
||||||
Map<ObjectIdentity, Acl> result = new HashMap<>();
|
|
||||||
Set<ObjectIdentity> currentBatchToLoad = new HashSet<>();
|
Set<ObjectIdentity> currentBatchToLoad = new HashSet<ObjectIdentity>();
|
||||||
|
|
||||||
for (int i = 0; i < objects.size(); i++) {
|
for (int i = 0; i < objects.size(); i++) {
|
||||||
final ObjectIdentity oid = objects.get(i);
|
final ObjectIdentity oid = objects.get(i);
|
||||||
boolean aclFound = false;
|
boolean aclFound = false;
|
||||||
|
|
||||||
// Check we don't already have this ACL in the results
|
// Check we don't already have this ACL in the results
|
||||||
if (result.containsKey(oid)) {
|
if (result.containsKey(oid)) {
|
||||||
aclFound = true;
|
aclFound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cache for the present ACL entry
|
// Check cache for the present ACL entry
|
||||||
if (!aclFound) {
|
if (!aclFound) {
|
||||||
Acl acl = this.aclCache.getFromCache(oid);
|
Acl acl = aclCache.getFromCache(oid);
|
||||||
|
|
||||||
// Ensure any cached element supports all the requested SIDs
|
// Ensure any cached element supports all the requested SIDs
|
||||||
// (they should always, as our base impl doesn't filter on SID)
|
// (they should always, as our base impl doesn't filter on SID)
|
||||||
if (acl != null) {
|
if (acl != null) {
|
||||||
Assert.state(acl.isSidLoaded(sids),
|
if (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);
|
result.put(acl.getObjectIdentity(), acl);
|
||||||
aclFound = true;
|
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
|
// Load the ACL from the database
|
||||||
if (!aclFound) {
|
if (!aclFound) {
|
||||||
currentBatchToLoad.add(oid);
|
currentBatchToLoad.add(oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is it time to load from JDBC the currentBatchToLoad?
|
// 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) {
|
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
|
// Add loaded batch (all elements 100% initialized) to results
|
||||||
result.putAll(loadedBatch);
|
result.putAll(loadedBatch);
|
||||||
|
|
||||||
// Add the loaded batch to the cache
|
// Add the loaded batch to the cache
|
||||||
|
|
||||||
for (Acl loadedAcl : loadedBatch.values()) {
|
for (Acl loadedAcl : loadedBatch.values()) {
|
||||||
this.aclCache.putInCache((AclImpl) loadedAcl);
|
aclCache.putInCache((AclImpl) loadedAcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentBatchToLoad.clear();
|
currentBatchToLoad.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.
|
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* The caller is responsible for optimization issues, such as selecting the identities
|
* The caller is responsible for optimization issues, such as selecting the identities to lookup, ensuring the
|
||||||
* to lookup, ensuring the cache doesn't contain them already, and adding the returned
|
* cache doesn't contain them already, and adding the returned elements to the cache etc.
|
||||||
* elements to the cache etc.
|
|
||||||
* <p>
|
* <p>
|
||||||
* This subclass is required to return fully valid <code>Acl</code>s, including
|
* This subclass is required to return fully valid <code>Acl</code>s, including properly-configured
|
||||||
* properly-configured parent ACLs.
|
* parent ACLs.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities,
|
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities, List<Sid> sids) {
|
||||||
List<Sid> sids) {
|
|
||||||
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
||||||
|
|
||||||
// contains Acls with StubAclParents
|
final Map<Serializable, Acl> acls = new HashMap<Serializable, Acl>(); // contains Acls with StubAclParents
|
||||||
Map<Serializable, Acl> acls = new HashMap<>();
|
|
||||||
|
|
||||||
// Make the "acls" map contain all requested objectIdentities
|
// Make the "acls" map contain all requested objectIdentities
|
||||||
// (including markers to each parent in the hierarchy)
|
// (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,
|
Set<Long> parentsToLookup = jdbcTemplate.query(sql,
|
||||||
(ps) -> setupLookupObjectIdentitiesStatement(ps, objectIdentities), new ProcessResultSet(acls, sids));
|
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();
|
||||||
|
|
||||||
// Lookup the parents, now that our JdbcTemplate has released the database
|
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
|
||||||
// connection (SEC-547)
|
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)
|
||||||
if (parentsToLookup.size() > 0) {
|
if (parentsToLookup.size() > 0) {
|
||||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, convert our "acls" containing StubAclParents into true Acls
|
// 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()) {
|
for (Acl inputAcl : acls.values()) {
|
||||||
Assert.isInstanceOf(AclImpl.class, inputAcl, "Map should have contained an AclImpl");
|
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(Long.class, ((AclImpl) inputAcl).getId(), "Acl.getId() must be Long");
|
||||||
|
|
||||||
Acl result = convert(acls, (Long) ((AclImpl) inputAcl).getId());
|
Acl result = convert(acls, (Long) ((AclImpl) inputAcl).getId());
|
||||||
resultMap.put(result.getObjectIdentity(), result);
|
resultMap.put(result.getObjectIdentity(), result);
|
||||||
}
|
}
|
||||||
@@ -353,31 +367,13 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
return resultMap;
|
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>
|
* The final phase of converting the <code>Map</code> of <code>AclImpl</code> instances which contain
|
||||||
* instances which contain <code>StubAclParent</code>s into proper, valid
|
* <code>StubAclParent</code>s into proper, valid <code>AclImpl</code>s with correct ACL parents.
|
||||||
* <code>AclImpl</code>s with correct ACL parents.
|
*
|
||||||
* @param inputMap the unconverted <code>AclImpl</code>s
|
* @param inputMap the unconverted <code>AclImpl</code>s
|
||||||
* @param currentIdentity the current<code>Acl</code> that we wish to convert (this
|
* @param currentIdentity the current<code>Acl</code> that we wish to convert (this may be
|
||||||
* may be
|
*
|
||||||
*/
|
*/
|
||||||
private AclImpl convert(Map<Serializable, Acl> inputMap, Long currentIdentity) {
|
private AclImpl convert(Map<Serializable, Acl> inputMap, Long currentIdentity) {
|
||||||
Assert.notEmpty(inputMap, "InputMap required");
|
Assert.notEmpty(inputMap, "InputMap required");
|
||||||
@@ -398,8 +394,8 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now we have the parent (if there is one), create the true AclImpl
|
// Now we have the parent (if there is one), create the true AclImpl
|
||||||
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), inputAcl.getId(), this.aclAuthorizationStrategy,
|
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long) inputAcl.getId(), aclAuthorizationStrategy,
|
||||||
this.grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||||
|
|
||||||
// Copy the "aces" from the input to the destination
|
// Copy the "aces" from the input to the destination
|
||||||
|
|
||||||
@@ -407,148 +403,114 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
List<AccessControlEntryImpl> aces = readAces(inputAcl);
|
List<AccessControlEntryImpl> aces = readAces(inputAcl);
|
||||||
|
|
||||||
// Create a list in which to store the "aces" for the "result" AclImpl instance
|
// 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
|
// Iterate over the "aces" input and replace each nested AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
||||||
// AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
|
||||||
// This ensures StubAclParent instances are removed, as per SEC-951
|
// This ensures StubAclParent instances are removed, as per SEC-951
|
||||||
for (AccessControlEntryImpl ace : aces) {
|
for (AccessControlEntryImpl ace : aces) {
|
||||||
setAclOnAce(ace, result);
|
setAclOnAce(ace, result);
|
||||||
acesNew.add(ace);
|
acesNew.add(ace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, now that the "aces" have been converted to have the "result" AclImpl
|
// Finally, now that the "aces" have been converted to have the "result" AclImpl instance, modify the "result" AclImpl instance
|
||||||
// instance, modify the "result" AclImpl instance
|
|
||||||
setAces(result, acesNew);
|
setAces(result, acesNew);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a particular implementation of {@link Sid} depending on the arguments.
|
* Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
|
||||||
* @param sid the name of the sid representing its unique identifier. In typical ACL
|
* data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
|
||||||
* 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
|
|
||||||
* @return the instance of Sid with the {@code sidName} as an identifier
|
|
||||||
*/
|
|
||||||
protected Sid createSid(boolean isPrincipal, String sid) {
|
|
||||||
if (isPrincipal) {
|
|
||||||
return new PrincipalSid(sid);
|
|
||||||
}
|
|
||||||
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
|
* @param permissionFactory
|
||||||
*/
|
*/
|
||||||
public final void setPermissionFactory(PermissionFactory permissionFactory) {
|
public void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||||
this.permissionFactory = permissionFactory;
|
this.permissionFactory = permissionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setBatchSize(int batchSize) {
|
public void setBatchSize(int batchSize) {
|
||||||
this.batchSize = batchSize;
|
this.batchSize = batchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SQL for the select clause. If customizing in order to modify column names,
|
* The SQL for the select clause. If customizing in order to modify
|
||||||
* schema etc, the other SQL customization fields must also be set to match.
|
* 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}.
|
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
|
||||||
*/
|
*/
|
||||||
public final void setSelectClause(String selectClause) {
|
public void setSelectClause(String selectClause) {
|
||||||
this.selectClause = selectClause;
|
this.selectClause = selectClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
|
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
|
||||||
*/
|
*/
|
||||||
public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
|
public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
|
||||||
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
|
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
|
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
|
||||||
*/
|
*/
|
||||||
public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
|
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
|
||||||
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
|
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SQL for the "order by" clause used in both queries.
|
* The SQL for the "order by" clause used in both queries.
|
||||||
*/
|
*/
|
||||||
public final void setOrderByClause(String orderByClause) {
|
public void setOrderByClause(String orderByClause) {
|
||||||
this.orderByClause = orderByClause;
|
this.orderByClause = orderByClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setAclClassIdSupported(boolean aclClassIdSupported) {
|
//~ Inner Classes ==================================================================================================
|
||||||
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 setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
|
|
||||||
Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
|
|
||||||
this.objectIdentityGenerator = objectIdentityGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setConversionService(ConversionService conversionService) {
|
|
||||||
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
|
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
|
||||||
|
private Map<Serializable, Acl> acls;
|
||||||
|
private List<Sid> sids;
|
||||||
|
|
||||||
private final Map<Serializable, Acl> acls;
|
public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||||
|
|
||||||
private final List<Sid> sids;
|
|
||||||
|
|
||||||
ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
|
||||||
Assert.notNull(acls, "ACLs cannot be null");
|
Assert.notNull(acls, "ACLs cannot be null");
|
||||||
this.acls = acls;
|
this.acls = acls;
|
||||||
this.sids = sids; // can be null
|
this.sids = sids; // can be null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@link ResultSetExtractor#extractData(ResultSet)}. Creates an
|
* Implementation of {@link ResultSetExtractor#extractData(ResultSet)}.
|
||||||
* {@link Acl} for each row in the {@link ResultSet} and ensures it is in member
|
* Creates an {@link Acl} for each row in the {@link ResultSet} and
|
||||||
* field <tt>acls</tt>. Any {@link Acl} with a parent will have the parents id
|
* ensures it is in member field <tt>acls</tt>. Any {@link Acl} with
|
||||||
* returned in a set. The returned set of ids may requires further processing.
|
* a parent will have the parents id returned in a set. The returned
|
||||||
|
* set of ids may requires further processing.
|
||||||
* @param rs The {@link ResultSet} to be processed
|
* @param rs The {@link ResultSet} to be processed
|
||||||
* @return a list of parent IDs remaining to be looked up (may be empty, but never
|
* @return a list of parent IDs remaining to be looked up (may be empty, but never <tt>null</tt>)
|
||||||
* <tt>null</tt>)
|
|
||||||
* @throws SQLException
|
* @throws SQLException
|
||||||
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
@Override
|
public Set<Long> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||||
public Set<Long> extractData(ResultSet rs) throws SQLException {
|
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
|
||||||
Set<Long> parentIdsToLookup = new HashSet<>(); // Set of parent_id Longs
|
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
// Convert current row into an Acl (albeit with a StubAclParent)
|
// 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
|
// Figure out if this row means we need to lookup another parent
|
||||||
long parentId = rs.getLong("parent_object");
|
long parentId = rs.getLong("parent_object");
|
||||||
|
|
||||||
if (parentId != 0) {
|
if (parentId != 0) {
|
||||||
// See if it's already in the "acls"
|
// See if it's already in the "acls"
|
||||||
if (this.acls.containsKey(parentId)) {
|
if (acls.containsKey(new Long(parentId))) {
|
||||||
continue; // skip this while iteration
|
continue; // skip this while iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now try to find it in the cache
|
// Now try to find it in the cache
|
||||||
MutableAcl cached = BasicLookupStrategy.this.aclCache.getFromCache(parentId);
|
MutableAcl cached = aclCache.getFromCache(new Long(parentId));
|
||||||
if ((cached == null) || !cached.isSidLoaded(this.sids)) {
|
|
||||||
parentIdsToLookup.add(parentId);
|
if ((cached == null) || !cached.isSidLoaded(sids)) {
|
||||||
}
|
parentIdsToLookup.add(new Long(parentId));
|
||||||
else {
|
} else {
|
||||||
// Pop into the acls map, so our convert method doesn't
|
// Pop into the acls map, so our convert method doesn't
|
||||||
// need to deal with an unsynchronized AclCache
|
// need to deal with an unsynchronized AclCache
|
||||||
this.acls.put(cached.getId(), cached);
|
acls.put(cached.getId(), cached);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -558,54 +520,61 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts the current <code>ResultSet</code> row, and converts it into an
|
* Accepts the current <code>ResultSet</code> row, and converts it into an <code>AclImpl</code> that
|
||||||
* <code>AclImpl</code> that contains a <code>StubAclParent</code>
|
* contains a <code>StubAclParent</code>
|
||||||
|
*
|
||||||
* @param acls the Map we should add the converted Acl to
|
* @param acls the Map we should add the converted Acl to
|
||||||
* @param rs the ResultSet focused on a current row
|
* @param rs the ResultSet focused on a current row
|
||||||
|
*
|
||||||
* @throws SQLException if something goes wrong converting values
|
* @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 {
|
private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultSet rs) throws SQLException {
|
||||||
Long id = rs.getLong("acl_id");
|
Long id = new Long(rs.getLong("acl_id"));
|
||||||
|
|
||||||
// If we already have an ACL for this ID, just create the ACE
|
// If we already have an ACL for this ID, just create the ACE
|
||||||
Acl acl = acls.get(id);
|
Acl acl = acls.get(id);
|
||||||
|
|
||||||
if (acl == null) {
|
if (acl == null) {
|
||||||
// Make an AclImpl and pop it into the Map
|
// Make an AclImpl and pop it into the Map
|
||||||
|
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||||
// If the Java type is a String, check to see if we can convert it to the
|
Long.valueOf(rs.getLong("object_id_identity")));
|
||||||
// target id type, e.g. UUID.
|
|
||||||
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
|
|
||||||
identifier = BasicLookupStrategy.this.aclClassIdUtils.identifierFrom(identifier, rs);
|
|
||||||
ObjectIdentity objectIdentity = BasicLookupStrategy.this.objectIdentityGenerator
|
|
||||||
.createObjectIdentity(identifier, rs.getString("class"));
|
|
||||||
|
|
||||||
Acl parentAcl = null;
|
Acl parentAcl = null;
|
||||||
long parentAclId = rs.getLong("parent_object");
|
long parentAclId = rs.getLong("parent_object");
|
||||||
|
|
||||||
if (parentAclId != 0) {
|
if (parentAclId != 0) {
|
||||||
parentAcl = new StubAclParent(parentAclId);
|
parentAcl = new StubAclParent(Long.valueOf(parentAclId));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||||
Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
|
Sid owner;
|
||||||
|
|
||||||
acl = new AclImpl(objectIdentity, id, BasicLookupStrategy.this.aclAuthorizationStrategy,
|
if (rs.getBoolean("acl_principal")) {
|
||||||
BasicLookupStrategy.this.grantingStrategy, parentAcl, null, entriesInheriting, owner);
|
owner = new PrincipalSid(rs.getString("acl_sid"));
|
||||||
|
} else {
|
||||||
|
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
|
||||||
|
entriesInheriting, owner);
|
||||||
|
|
||||||
acls.put(id, acl);
|
acls.put(id, acl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
||||||
// It is permissible to have no ACEs in an ACL (which is detected by a null
|
// It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||||
// ACE_SID)
|
|
||||||
if (rs.getString("ace_sid") != null) {
|
if (rs.getString("ace_sid") != null) {
|
||||||
Long aceId = rs.getLong("ace_id");
|
Long aceId = new Long(rs.getLong("ace_id"));
|
||||||
Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
|
Sid recipient;
|
||||||
|
|
||||||
|
if (rs.getBoolean("ace_principal")) {
|
||||||
|
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||||
|
} else {
|
||||||
|
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||||
|
}
|
||||||
|
|
||||||
int mask = rs.getInt("mask");
|
int mask = rs.getInt("mask");
|
||||||
Permission permission = BasicLookupStrategy.this.permissionFactory.buildFromMask(mask);
|
Permission permission = permissionFactory.buildFromMask(mask);
|
||||||
boolean granting = rs.getBoolean("granting");
|
boolean granting = rs.getBoolean("granting");
|
||||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||||
@@ -622,57 +591,46 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class StubAclParent implements Acl {
|
private class StubAclParent implements Acl {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
private final Long id;
|
public StubAclParent(Long id) {
|
||||||
|
|
||||||
StubAclParent(Long id) {
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<AccessControlEntry> getEntries() {
|
public List<AccessControlEntry> getEntries() {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public ObjectIdentity getObjectIdentity() {
|
public ObjectIdentity getObjectIdentity() {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Sid getOwner() {
|
public Sid getOwner() {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Acl getParentAcl() {
|
public Acl getParentAcl() {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEntriesInheriting() {
|
public boolean isEntriesInheriting() {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||||
throws NotFoundException, UnloadedSidException {
|
throws NotFoundException, UnloadedSidException {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSidLoaded(List<Sid> sids) {
|
public boolean isSidLoaded(List<Sid> sids) {
|
||||||
throw new UnsupportedOperationException("Stub only");
|
throw new UnsupportedOperationException("Stub only");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006, 2017, 2018 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,13 +12,11 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.jdbc;
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Collections;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -27,155 +24,107 @@ import javax.sql.DataSource;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.JdbcTemplate;
|
||||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
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.Acl;
|
||||||
import org.springframework.security.acls.model.AclService;
|
import org.springframework.security.acls.model.AclService;
|
||||||
import org.springframework.security.acls.model.NotFoundException;
|
import org.springframework.security.acls.model.NotFoundException;
|
||||||
import org.springframework.security.acls.model.ObjectIdentity;
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
import org.springframework.security.acls.model.ObjectIdentityGenerator;
|
|
||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple JDBC-based implementation of <code>AclService</code>.
|
* Simple JDBC-based implementation of <code>AclService</code>.
|
||||||
* <p>
|
* <p>
|
||||||
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl}
|
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl} and
|
||||||
* and {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set,
|
* {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set, so that the implementation can
|
||||||
* so that the implementation can detect changed parameters easily.
|
* detect changed parameters easily.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class JdbcAclService implements AclService {
|
public class JdbcAclService implements AclService {
|
||||||
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
||||||
|
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, class.class as 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 "
|
+ "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 "
|
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||||
+ "select id FROM acl_class where acl_class.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, "
|
//~ Instance fields ================================================================================================
|
||||||
+ 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;
|
|
||||||
|
|
||||||
private final LookupStrategy lookupStrategy;
|
|
||||||
|
|
||||||
private boolean aclClassIdSupported;
|
|
||||||
|
|
||||||
|
protected JdbcTemplate jdbcTemplate;
|
||||||
|
private LookupStrategy lookupStrategy;
|
||||||
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
||||||
|
|
||||||
private AclClassIdUtils aclClassIdUtils;
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
private ObjectIdentityGenerator objectIdentityGenerator;
|
|
||||||
|
|
||||||
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
|
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
|
||||||
this(new JdbcTemplate(dataSource), lookupStrategy);
|
Assert.notNull(dataSource, "DataSource required");
|
||||||
}
|
|
||||||
|
|
||||||
public JdbcAclService(JdbcOperations jdbcOperations, LookupStrategy lookupStrategy) {
|
|
||||||
Assert.notNull(jdbcOperations, "JdbcOperations required");
|
|
||||||
Assert.notNull(lookupStrategy, "LookupStrategy required");
|
Assert.notNull(lookupStrategy, "LookupStrategy required");
|
||||||
this.jdbcOperations = jdbcOperations;
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
this.lookupStrategy = lookupStrategy;
|
this.lookupStrategy = lookupStrategy;
|
||||||
this.aclClassIdUtils = new AclClassIdUtils();
|
|
||||||
this.objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||||
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
|
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()};
|
||||||
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql,
|
List<ObjectIdentity> objects = jdbcTemplate.query(findChildrenSql, args,
|
||||||
(rs, rowNum) -> mapObjectIdentityRow(rs), args);
|
new RowMapper<ObjectIdentity>() {
|
||||||
return (!objects.isEmpty()) ? objects : null;
|
public ObjectIdentity mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||||
}
|
|
||||||
|
|
||||||
private ObjectIdentity mapObjectIdentityRow(ResultSet rs) throws SQLException {
|
|
||||||
String javaType = rs.getString("class");
|
String javaType = rs.getString("class");
|
||||||
Serializable identifier = (Serializable) rs.getObject("obj_id");
|
Long identifier = new Long(rs.getLong("obj_id"));
|
||||||
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
|
|
||||||
return this.objectIdentityGenerator.createObjectIdentity(identifier, javaType);
|
return new ObjectIdentityImpl(javaType, identifier);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (objects.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
|
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
|
||||||
Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
|
Map<ObjectIdentity, Acl> map = readAclsById(Arrays.asList(object), sids);
|
||||||
Assert.isTrue(map.containsKey(object),
|
Assert.isTrue(map.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object);
|
||||||
() -> "There should have been an Acl entry for ObjectIdentity " + object);
|
|
||||||
return map.get(object);
|
return (Acl) map.get(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
|
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
|
||||||
return readAclById(object, null);
|
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);
|
return readAclsById(objects, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException {
|
||||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
|
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
|
||||||
throws NotFoundException {
|
|
||||||
Map<ObjectIdentity, Acl> result = this.lookupStrategy.readAclsById(objects, sids);
|
// Check every requested object identity was found (throw NotFoundException if needed)
|
||||||
// Check every requested object identity was found (throw NotFoundException if
|
for (int i = 0; i < objects.size(); i++) {
|
||||||
// needed)
|
if (!result.containsKey(objects.get(i))) {
|
||||||
for (ObjectIdentity oid : objects) {
|
throw new NotFoundException("Unable to find ACL information for object identity '"
|
||||||
if (!result.containsKey(oid)) {
|
+ objects.get(i) + "'");
|
||||||
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows customization of the SQL query used to find child object identities.
|
* Allows customization of the SQL query used to find child object identities.
|
||||||
|
*
|
||||||
* @param findChildrenSql
|
* @param findChildrenSql
|
||||||
*/
|
*/
|
||||||
public void setFindChildrenQuery(String findChildrenSql) {
|
public void setFindChildrenQuery(String findChildrenSql) {
|
||||||
this.findChildrenSql = 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
|
|
||||||
Assert.notNull(objectIdentityGenerator, "objectIdentityGenerator cannot be null");
|
|
||||||
this.objectIdentityGenerator = objectIdentityGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAclClassIdSupported() {
|
|
||||||
return this.aclClassIdSupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+119
-174
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006, 2017, 2018 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.jdbc;
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
@@ -40,75 +38,59 @@ import org.springframework.security.acls.model.ObjectIdentity;
|
|||||||
import org.springframework.security.acls.model.Sid;
|
import org.springframework.security.acls.model.Sid;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a base JDBC implementation of {@link MutableAclService}.
|
* Provides a base JDBC implementation of {@link MutableAclService}.
|
||||||
* <p>
|
* <p>
|
||||||
* The default settings are for HSQLDB. If you are using a different database you will
|
* The default settings are for HSQLDB. If you are using a different database you
|
||||||
* probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
|
* will probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
|
||||||
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The
|
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The other queries,
|
||||||
* other queries, SQL inserts and updates can also be customized to accomodate schema
|
* SQL inserts and updates can also be customized to accomodate schema variations, but must produce results
|
||||||
* variations, but must produce results consistent with those expected by the defaults.
|
* consistent with those expected by the defaults.
|
||||||
* <p>
|
* <p>
|
||||||
* See the appendix of the Spring Security reference manual for more information on the
|
* See the appendix of the Spring Security reference manual for more information on the expected schema
|
||||||
* expected schema and how it is used. Information on using PostgreSQL is also included.
|
* and how it is used. Information on using PostgreSQL is also included.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Johannes Zlattinger
|
* @author Johannes Zlattinger
|
||||||
*/
|
*/
|
||||||
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
||||||
|
//~ Instance fields ================================================================================================
|
||||||
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 (?, ?)";
|
|
||||||
|
|
||||||
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
|
||||||
.getContextHolderStrategy();
|
|
||||||
|
|
||||||
private boolean foreignKeysInDatabase = true;
|
private boolean foreignKeysInDatabase = true;
|
||||||
|
private AclCache aclCache;
|
||||||
private final AclCache aclCache;
|
|
||||||
|
|
||||||
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
||||||
|
|
||||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||||
|
|
||||||
private String classIdentityQuery = "call identity()";
|
private String classIdentityQuery = "call identity()";
|
||||||
|
|
||||||
private String sidIdentityQuery = "call identity()";
|
private String sidIdentityQuery = "call identity()";
|
||||||
|
private String insertClass = "insert into acl_class (class) values (?)";
|
||||||
private String insertClass = DEFAULT_INSERT_INTO_ACL_CLASS;
|
|
||||||
|
|
||||||
private String insertEntry = "insert into acl_entry "
|
private String insertEntry = "insert into acl_entry "
|
||||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||||
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
|
||||||
private String insertObjectIdentity = "insert into acl_object_identity "
|
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 insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
|
||||||
|
|
||||||
private String selectClassPrimaryKey = "select id from acl_class where class=?";
|
private String selectClassPrimaryKey = "select id from acl_class where class=?";
|
||||||
|
|
||||||
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_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=? "
|
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
|
||||||
+ "and acl_object_identity.object_id_identity = ?";
|
+ "and acl_object_identity.object_id_identity = ?";
|
||||||
|
|
||||||
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
|
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
|
||||||
|
|
||||||
private String updateObjectIdentity = "update acl_object_identity set "
|
private String updateObjectIdentity = "update acl_object_identity set "
|
||||||
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
|
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
|
||||||
|
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
|
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
|
||||||
super(dataSource, lookupStrategy);
|
super(dataSource, lookupStrategy);
|
||||||
Assert.notNull(aclCache, "AclCache required");
|
Assert.notNull(aclCache, "AclCache required");
|
||||||
this.aclCache = aclCache;
|
this.aclCache = aclCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
|
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
|
||||||
Assert.notNull(objectIdentity, "Object Identity required");
|
Assert.notNull(objectIdentity, "Object Identity required");
|
||||||
|
|
||||||
@@ -117,16 +99,14 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
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
|
// Need to retrieve the current principal, in order to know who "owns" this ACL (can be changed later on)
|
||||||
// (can be changed later on)
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
|
|
||||||
PrincipalSid sid = new PrincipalSid(auth);
|
PrincipalSid sid = new PrincipalSid(auth);
|
||||||
|
|
||||||
// Create the acl_object_identity row
|
// Create the acl_object_identity row
|
||||||
createObjectIdentity(objectIdentity, sid);
|
createObjectIdentity(objectIdentity, sid);
|
||||||
|
|
||||||
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval
|
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
|
||||||
// etc)
|
|
||||||
Acl acl = readAclById(objectIdentity);
|
Acl acl = readAclById(objectIdentity);
|
||||||
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
|
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
|
||||||
|
|
||||||
@@ -134,146 +114,133 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl
|
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl object.
|
||||||
* object.
|
*
|
||||||
* @param acl containing the ACEs to insert
|
* @param acl containing the ACEs to insert
|
||||||
*/
|
*/
|
||||||
protected void createEntries(final MutableAcl acl) {
|
protected void createEntries(final MutableAcl acl) {
|
||||||
if (acl.getEntries().isEmpty()) {
|
jdbcTemplate.batchUpdate(insertEntry,
|
||||||
return;
|
new BatchPreparedStatementSetter() {
|
||||||
}
|
|
||||||
this.jdbcOperations.batchUpdate(this.insertEntry, new BatchPreparedStatementSetter() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBatchSize() {
|
public int getBatchSize() {
|
||||||
return acl.getEntries().size();
|
return acl.getEntries().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValues(PreparedStatement stmt, int i) throws SQLException {
|
public void setValues(PreparedStatement stmt, int i) throws SQLException {
|
||||||
AccessControlEntry entry_ = acl.getEntries().get(i);
|
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_;
|
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
|
||||||
|
|
||||||
stmt.setLong(1, (Long) acl.getId());
|
stmt.setLong(1, ((Long) acl.getId()).longValue());
|
||||||
stmt.setInt(2, i);
|
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.setInt(4, entry.getPermission().getMask());
|
||||||
stmt.setBoolean(5, entry.isGranting());
|
stmt.setBoolean(5, entry.isGranting());
|
||||||
stmt.setBoolean(6, entry.isAuditSuccess());
|
stmt.setBoolean(6, entry.isAuditSuccess());
|
||||||
stmt.setBoolean(7, entry.isAuditFailure());
|
stmt.setBoolean(7, entry.isAuditFailure());
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity.
|
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity. The Sid is also
|
||||||
* The Sid is also necessary, as acl_object_identity has defined the sid column as
|
* necessary, as acl_object_identity has defined the sid column as non-null.
|
||||||
* non-null.
|
*
|
||||||
* @param object to represent an acl_object_identity for
|
* @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
|
* @param owner for the SID column (will be created if there is no acl_sid entry for this particular Sid already)
|
||||||
* this particular Sid already)
|
|
||||||
*/
|
*/
|
||||||
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
||||||
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
||||||
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true, object.getIdentifier().getClass());
|
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true);
|
||||||
this.jdbcOperations.update(this.insertObjectIdentity, classId, object.getIdentifier().toString(), sidId,
|
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId, Boolean.TRUE);
|
||||||
Boolean.TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the primary key from {@code acl_class}, creating a new row if needed and
|
* Retrieves the primary key from {@code acl_class}, creating a new row if needed and the
|
||||||
* the {@code allowCreate} property is {@code true}.
|
* {@code allowCreate} property is {@code true}.
|
||||||
|
*
|
||||||
* @param type to find or create an entry for (often the fully-qualified class name)
|
* @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
|
* @param allowCreate true if creation is permitted if not found
|
||||||
|
*
|
||||||
* @return the primary key or null if not found
|
* @return the primary key or null if not found
|
||||||
*/
|
*/
|
||||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate) {
|
||||||
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, Long.class, type);
|
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {type}, Long.class);
|
||||||
|
|
||||||
if (!classIds.isEmpty()) {
|
if (!classIds.isEmpty()) {
|
||||||
return classIds.get(0);
|
return classIds.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowCreate) {
|
if (allowCreate) {
|
||||||
if (!isAclClassIdSupported()) {
|
jdbcTemplate.update(insertClass, type);
|
||||||
this.jdbcOperations.update(this.insertClass, type);
|
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||||
}
|
"Transaction must be running");
|
||||||
else {
|
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||||
this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName());
|
|
||||||
}
|
|
||||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
|
||||||
return this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the primary key from acl_sid, creating a new row if needed and the
|
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
|
||||||
* allowCreate property is true.
|
* true.
|
||||||
|
*
|
||||||
* @param sid to find or create
|
* @param sid to find or create
|
||||||
* @param allowCreate true if creation is permitted if not found
|
* @param allowCreate true if creation is permitted if not found
|
||||||
|
*
|
||||||
* @return the primary key or null if not found
|
* @return the primary key or null if not found
|
||||||
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized
|
*
|
||||||
* implementation.
|
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized implementation.
|
||||||
*/
|
*/
|
||||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||||
Assert.notNull(sid, "Sid required");
|
Assert.notNull(sid, "Sid required");
|
||||||
|
|
||||||
|
String sidName = null;
|
||||||
|
boolean sidIsPrincipal = true;
|
||||||
|
|
||||||
if (sid instanceof PrincipalSid) {
|
if (sid instanceof PrincipalSid) {
|
||||||
String sidName = ((PrincipalSid) sid).getPrincipal();
|
sidName = ((PrincipalSid) sid).getPrincipal();
|
||||||
return createOrRetrieveSidPrimaryKey(sidName, true, allowCreate);
|
} else if (sid instanceof GrantedAuthoritySid) {
|
||||||
}
|
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
|
||||||
if (sid instanceof GrantedAuthoritySid) {
|
sidIsPrincipal = false;
|
||||||
String sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
|
} else {
|
||||||
return createOrRetrieveSidPrimaryKey(sidName, false, allowCreate);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
|
||||||
* Retrieves the primary key from acl_sid, creating a new row if needed and the
|
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
|
||||||
* allowCreate property is true.
|
|
||||||
* @param sidName name of Sid to find or to create
|
|
||||||
* @param sidIsPrincipal whether it's a user or granted authority like role
|
|
||||||
* @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, Long.class, sidIsPrincipal,
|
|
||||||
sidName);
|
|
||||||
if (!sidIds.isEmpty()) {
|
if (!sidIds.isEmpty()) {
|
||||||
return sidIds.get(0);
|
return sidIds.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowCreate) {
|
if (allowCreate) {
|
||||||
this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName);
|
jdbcTemplate.update(insertSid, new Object[] {Boolean.valueOf(sidIsPrincipal), sidName});
|
||||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||||
return this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
|
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
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, "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) {
|
if (deleteChildren) {
|
||||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
for (ObjectIdentity child : children) {
|
for (int i = 0; i < children.size(); i++) {
|
||||||
deleteAcl(child, true);
|
deleteAcl(children.get(i), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (!foreignKeysInDatabase) {
|
||||||
if (!this.foreignKeysInDatabase) {
|
// We need to perform a manual verification for what a FK would normally do
|
||||||
// We need to perform a manual verification for what a FK would normally
|
// 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);
|
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
throw new ChildrenExistException(
|
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.size()
|
||||||
"Cannot delete '" + objectIdentity + "' (has " + children.size() + " children)");
|
+ " children)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,55 +254,55 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
deleteObjectIdentity(oidPrimaryKey);
|
deleteObjectIdentity(oidPrimaryKey);
|
||||||
|
|
||||||
// Clear the cache
|
// Clear the cache
|
||||||
this.aclCache.evictFromCache(objectIdentity);
|
aclCache.evictFromCache(objectIdentity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes all ACEs defined in the acl_entry table belonging to the presented
|
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity primary key.
|
||||||
* ObjectIdentity primary key.
|
*
|
||||||
* @param oidPrimaryKey the rows in acl_entry to delete
|
* @param oidPrimaryKey the rows in acl_entry to delete
|
||||||
*/
|
*/
|
||||||
protected void deleteEntries(Long oidPrimaryKey) {
|
protected void deleteEntries(Long oidPrimaryKey) {
|
||||||
this.jdbcOperations.update(this.deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
|
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
|
||||||
|
new Object[] {oidPrimaryKey});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a single row from acl_object_identity that is associated with the presented
|
* Deletes a single row from acl_object_identity that is associated with the presented ObjectIdentity primary key.
|
||||||
* ObjectIdentity primary key.
|
|
||||||
* <p>
|
* <p>
|
||||||
* We do not delete any entries from acl_class, even if no classes are using that
|
* We do not delete any entries from acl_class, even if no classes are using that class any longer. This is a
|
||||||
* class any longer. This is a deadlock avoidance approach.
|
* deadlock avoidance approach.
|
||||||
|
*
|
||||||
* @param oidPrimaryKey to delete the acl_object_identity
|
* @param oidPrimaryKey to delete the acl_object_identity
|
||||||
*/
|
*/
|
||||||
protected void deleteObjectIdentity(Long oidPrimaryKey) {
|
protected void deleteObjectIdentity(Long oidPrimaryKey) {
|
||||||
// Delete the acl_object_identity row
|
// Delete the acl_object_identity row
|
||||||
this.jdbcOperations.update(this.deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
|
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the primary key from the acl_object_identity table for the passed
|
* Retrieves the primary key from the acl_object_identity table for the passed ObjectIdentity. Unlike some
|
||||||
* ObjectIdentity. Unlike some other methods in this implementation, this method will
|
* other methods in this implementation, this method will NOT create a row (use {@link
|
||||||
* NOT create a row (use {@link #createObjectIdentity(ObjectIdentity, Sid)} instead).
|
* #createObjectIdentity(ObjectIdentity, Sid)} instead).
|
||||||
|
*
|
||||||
* @param oid to find
|
* @param oid to find
|
||||||
|
*
|
||||||
* @return the object identity or null if not found
|
* @return the object identity or null if not found
|
||||||
*/
|
*/
|
||||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||||
try {
|
try {
|
||||||
return this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, oid.getType(),
|
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
||||||
oid.getIdentifier().toString());
|
new Object[] {oid.getType(), oid.getIdentifier()}));
|
||||||
}
|
} catch (DataAccessException notFound) {
|
||||||
catch (DataAccessException notFound) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implementation will simply delete all ACEs in the database and recreate them
|
* This implementation will simply delete all ACEs in the database and recreate them on each invocation of
|
||||||
* on each invocation of this method. A more comprehensive implementation might use
|
* this method. A more comprehensive implementation might use dirty state checking, or more likely use ORM
|
||||||
* dirty state checking, or more likely use ORM capabilities for create, update and
|
* capabilities for create, update and delete operations of {@link MutableAcl}.
|
||||||
* delete operations of {@link MutableAcl}.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
||||||
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
||||||
|
|
||||||
@@ -351,8 +318,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
// Clear the cache, including children
|
// Clear the cache, including children
|
||||||
clearCacheIncludingChildren(acl.getObjectIdentity());
|
clearCacheIncludingChildren(acl.getObjectIdentity());
|
||||||
|
|
||||||
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval
|
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
|
||||||
// etc)
|
|
||||||
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
|
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,42 +326,48 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
for (ObjectIdentity child : children) {
|
for (int i = 0; i < children.size(); i++) {
|
||||||
clearCacheIncludingChildren(child);
|
clearCacheIncludingChildren(children.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.aclCache.evictFromCache(objectIdentity);
|
aclCache.evictFromCache(objectIdentity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an existing acl_object_identity row, with new information presented in the
|
* Updates an existing acl_object_identity row, with new information presented in the passed MutableAcl
|
||||||
* passed MutableAcl object. Also will create an acl_sid entry if needed for the Sid
|
* object. Also will create an acl_sid entry if needed for the Sid that owns the MutableAcl.
|
||||||
* that owns the MutableAcl.
|
*
|
||||||
* @param acl to modify (a row must already exist in acl_object_identity)
|
* @param acl to modify (a row must already exist in acl_object_identity)
|
||||||
|
*
|
||||||
* @throws NotFoundException if the ACL could not be found to update.
|
* @throws NotFoundException if the ACL could not be found to update.
|
||||||
*/
|
*/
|
||||||
protected void updateObjectIdentity(MutableAcl acl) {
|
protected void updateObjectIdentity(MutableAcl acl) {
|
||||||
Long parentId = null;
|
Long parentId = null;
|
||||||
|
|
||||||
if (acl.getParentAcl() != null) {
|
if (acl.getParentAcl() != null) {
|
||||||
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
|
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
|
||||||
"Implementation only supports ObjectIdentityImpl");
|
"Implementation only supports ObjectIdentityImpl");
|
||||||
|
|
||||||
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
|
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
|
||||||
parentId = retrieveObjectIdentityPrimaryKey(oii);
|
parentId = retrieveObjectIdentityPrimaryKey(oii);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
|
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
|
||||||
|
|
||||||
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
|
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
|
||||||
int count = this.jdbcOperations.update(this.updateObjectIdentity, parentId, ownerSid, acl.isEntriesInheriting(),
|
int count = jdbcTemplate.update(updateObjectIdentity,
|
||||||
acl.getId());
|
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
|
||||||
|
|
||||||
if (count != 1) {
|
if (count != 1) {
|
||||||
throw new NotFoundException("Unable to locate ACL to update");
|
throw new NotFoundException("Unable to locate ACL to update");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the query that will be used to retrieve the identity of a newly created row in
|
* Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_class</tt>
|
||||||
* the <tt>acl_class</tt> table.
|
* table.
|
||||||
* @param classIdentityQuery the query, which should return the identifier. Defaults
|
*
|
||||||
* to <tt>call identity()</tt>
|
* @param classIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
|
||||||
*/
|
*/
|
||||||
public void setClassIdentityQuery(String classIdentityQuery) {
|
public void setClassIdentityQuery(String classIdentityQuery) {
|
||||||
Assert.hasText(classIdentityQuery, "New classIdentityQuery query is required");
|
Assert.hasText(classIdentityQuery, "New classIdentityQuery query is required");
|
||||||
@@ -403,10 +375,10 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the query that will be used to retrieve the identity of a newly created row in
|
* Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_sid</tt>
|
||||||
* the <tt>acl_sid</tt> table.
|
* table.
|
||||||
* @param sidIdentityQuery the query, which should return the identifier. Defaults to
|
*
|
||||||
* <tt>call identity()</tt>
|
* @param sidIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
|
||||||
*/
|
*/
|
||||||
public void setSidIdentityQuery(String sidIdentityQuery) {
|
public void setSidIdentityQuery(String sidIdentityQuery) {
|
||||||
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
|
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
|
||||||
@@ -454,37 +426,10 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param foreignKeysInDatabase if false this class will perform additional FK
|
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
|
||||||
* constrain checking, which may cause deadlocks (the default is true, so deadlocks
|
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||||
* are avoided but the database is expected to enforce FKs)
|
|
||||||
*/
|
*/
|
||||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||||
this.foreignKeysInDatabase = 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
|
|
||||||
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
|
|
||||||
*
|
|
||||||
* @since 5.8
|
|
||||||
*/
|
|
||||||
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
|
||||||
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
|
|
||||||
this.securityContextHolderStrategy = securityContextHolderStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,35 +12,36 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.jdbc;
|
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.Acl;
|
||||||
import org.springframework.security.acls.model.NotFoundException;
|
import org.springframework.security.acls.model.NotFoundException;
|
||||||
import org.springframework.security.acls.model.ObjectIdentity;
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
import org.springframework.security.acls.model.Sid;
|
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}.
|
* Performs lookups for {@link org.springframework.security.acls.model.AclService}.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface LookupStrategy {
|
public interface LookupStrategy {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform database-specific optimized lookup.
|
* Perform database-specific optimized lookup.
|
||||||
|
*
|
||||||
* @param objects the identities to lookup (required)
|
* @param objects the identities to lookup (required)
|
||||||
* @param sids the SIDs for which identities are required (may be <tt>null</tt> -
|
* @param sids the SIDs for which identities are required (may be <tt>null</tt> - implementations may elect not
|
||||||
* implementations may elect not to provide SID optimisations)
|
* 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>
|
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||||
* although some entries may be missing; this method should not throw
|
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||||
* {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used to
|
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||||
* automatically create entries if required)
|
* to automatically create entries if required)
|
||||||
*/
|
*/
|
||||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
|
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,5 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JDBC-based persistence of ACL information
|
* JDBC-based persistence of ACL information
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.acls.jdbc;
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,27 +12,31 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an individual permission assignment within an {@link Acl}.
|
* Represents an individual permission assignment within an {@link Acl}.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Instances MUST be immutable, as they are returned by <code>Acl</code> and should not
|
* Instances MUST be immutable, as they are returned by <code>Acl</code>
|
||||||
* allow client modification.
|
* and should not allow client modification.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface AccessControlEntry extends Serializable {
|
public interface AccessControlEntry extends Serializable {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
Acl getAcl();
|
Acl getAcl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains an identifier that represents this ACE.
|
* Obtains an identifier that represents this ACE.
|
||||||
|
*
|
||||||
* @return the identifier, or <code>null</code> if unsaved
|
* @return the identifier, or <code>null</code> if unsaved
|
||||||
*/
|
*/
|
||||||
Serializable getId();
|
Serializable getId();
|
||||||
@@ -43,10 +46,10 @@ public interface AccessControlEntry extends Serializable {
|
|||||||
Sid getSid();
|
Sid getSid();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates the permission is being granted to the relevant Sid. If false, indicates
|
* Indicates the a Permission is being granted to the relevant Sid. If false, indicates the permission is
|
||||||
* the permission is being revoked/blocked.
|
* being revoked/blocked.
|
||||||
|
*
|
||||||
* @return true if being granted, false otherwise
|
* @return true if being granted, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean isGranting();
|
boolean isGranting();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,27 +12,30 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an access control list (ACL) for a domain object.
|
* Represents an access control list (ACL) for a domain object.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In order to avoid
|
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In
|
||||||
* needing references to the domain object itself, this interface handles indirection
|
* order to avoid needing references to the domain object itself, this
|
||||||
* between a domain object and an ACL object identity via the
|
* interface handles indirection between a domain object and an ACL object
|
||||||
* {@link org.springframework.security.acls.model.ObjectIdentity} interface.
|
* identity via the {@link
|
||||||
|
* org.springframework.security.acls.model.ObjectIdentity} interface.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Implementing classes may elect to return instances that represent
|
* Implementing classes may elect to return instances that represent
|
||||||
* {@link org.springframework.security.acls.model.Permission} information for either some
|
* {@link org.springframework.security.acls.model.Permission} information for either
|
||||||
* OR all {@link org.springframework.security.acls.model.Sid} instances. Therefore, an
|
* some OR all {@link org.springframework.security.acls.model.Sid}
|
||||||
* instance may NOT necessarily contain ALL <tt>Sid</tt>s for a given domain object.
|
* instances. Therefore, an instance may NOT necessarily contain ALL <tt>Sid</tt>s
|
||||||
|
* for a given domain object.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
@@ -41,154 +43,126 @@ import java.util.List;
|
|||||||
public interface Acl extends Serializable {
|
public interface Acl extends Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries
|
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries associated with
|
||||||
* associated with the <tt>Acl</tt> parents are not returned.
|
* the <tt>Acl</tt> parents are not returned.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>This method is typically used for administrative purposes.</p>
|
||||||
* This method is typically used for administrative purposes.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>The order that entries appear in the array is important for methods declared in the
|
||||||
* The order that entries appear in the array is important for methods declared in the
|
|
||||||
* {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
|
* {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
|
||||||
* part of advanced permission checking.
|
* part of advanced permission checking.</p>
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
|
||||||
* Do <em>NOT</em> use this method for making authorization decisions. Instead use
|
* #isGranted(List, List, boolean)}.</p>
|
||||||
* {@link #isGranted(List, List, boolean)}.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||||
* This method must operate correctly even if the <tt>Acl</tt> only represents a
|
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||||
* subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
|
* <tt>Sid</tt>s is represented.</p>
|
||||||
* 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
|
||||||
* @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if
|
* no entries presently associated with this <tt>Acl</tt>.
|
||||||
* there are no entries presently associated with this <tt>Acl</tt>.
|
|
||||||
*/
|
*/
|
||||||
List<AccessControlEntry> getEntries();
|
List<AccessControlEntry> getEntries();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable
|
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable once an
|
||||||
* once an <tt>Acl</tt> is created.
|
* <tt>Acl</tt> is created.
|
||||||
|
*
|
||||||
* @return the object identity (never <tt>null</tt>)
|
* @return the object identity (never <tt>null</tt>)
|
||||||
*/
|
*/
|
||||||
ObjectIdentity getObjectIdentity();
|
ObjectIdentity getObjectIdentity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by
|
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by implementation and is
|
||||||
* implementation and is unspecified.
|
* unspecified.
|
||||||
* @return the owner (may be <tt>null</tt> if the implementation does not use
|
*
|
||||||
* ownership concepts)
|
* @return the owner (may be <tt>null</tt> if the implementation does not use ownership concepts)
|
||||||
*/
|
*/
|
||||||
Sid getOwner();
|
Sid getOwner();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A domain object may have a parent for the purpose of ACL inheritance. If there is a
|
* A domain object may have a parent for the purpose of ACL inheritance. If there is a parent, its ACL can
|
||||||
* parent, its ACL can be accessed via this method. In turn, the parent's parent
|
* be accessed via this method. In turn, the parent's parent (grandparent) can be accessed and so on.
|
||||||
* (grandparent) can be accessed and so on.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>This method solely represents the presence of a navigation hierarchy between the parent <tt>Acl</tt> and this
|
||||||
* This method solely represents the presence of a navigation hierarchy between the
|
* <tt>Acl</tt>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
|
||||||
* parent <tt>Acl</tt> and this <tt>Acl</tt>. For actual inheritance to take place,
|
* <tt>true</tt>.</p>
|
||||||
* the {@link #isEntriesInheriting()} must also be <tt>true</tt>.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||||
* This method must operate correctly even if the <tt>Acl</tt> only represents a
|
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||||
* subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
|
* <tt>Sid</tt>s is represented.</p>
|
||||||
* 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)
|
||||||
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not
|
|
||||||
* have a parent)
|
|
||||||
*/
|
*/
|
||||||
Acl getParentAcl();
|
Acl getParentAcl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down
|
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
|
||||||
* into the current <tt>Acl</tt>.
|
* <tt>Acl</tt>.<p>The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own
|
||||||
* <p>
|
* is insufficient to cause ACL entries to inherit down. This is because a domain object may wish to have entirely
|
||||||
* The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own is
|
* independent entries, but maintain the link with the parent for navigation purposes. Thus, this method denotes
|
||||||
* insufficient to cause ACL entries to inherit down. This is because a domain object
|
* whether or not the navigation relationship also extends to the actual inheritance of entries.</p>
|
||||||
* may wish to have entirely independent entries, but maintain the link with the
|
*
|
||||||
* 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>
|
* @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
|
||||||
*/
|
*/
|
||||||
boolean isEntriesInheriting();
|
boolean isEntriesInheriting();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the actual authorization logic method, and must be used whenever ACL
|
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
|
||||||
* authorization decisions are required.
|
* required.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>An array of <tt>Sid</tt>s are presented, representing security identifies of the current
|
||||||
* An array of <tt>Sid</tt>s are presented, representing security identifies of the
|
* principal. In addition, an array of <tt>Permission</tt>s is presented which will have one or more bits set
|
||||||
* current principal. In addition, an array of <tt>Permission</tt>s is presented which
|
* in order to indicate the permissions needed for an affirmative authorization decision. An array is presented
|
||||||
* will have one or more bits set in order to indicate the permissions needed for an
|
* because holding <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
|
||||||
* affirmative authorization decision. An array is presented because holding
|
* affirmative authorization.</p>
|
||||||
* <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
|
*
|
||||||
* affirmative authorization.
|
* <p>The actual approach used to make authorization decisions is left to the implementation and is not
|
||||||
|
* specified by this interface. For example, an implementation <em>MAY</em> search the current ACL in the order
|
||||||
|
* the ACL entries have been stored. If a single entry is found that has the same active bits as are shown in a
|
||||||
|
* passed <tt>Permission</tt>, that entry's grant or deny state may determine the authorization decision. If
|
||||||
|
* the case of a deny state, the deny decision will only be relevant if all other <tt>Permission</tt>s passed
|
||||||
|
* in the array have also been unsuccessfully searched. If no entry is found that match the bits in the current
|
||||||
|
* ACL, provided that {@link #isEntriesInheriting()} is <tt>true</tt>, the authorization decision may be
|
||||||
|
* passed to the parent ACL. If there is no matching entry, the implementation MAY throw an exception, or make a
|
||||||
|
* predefined authorization decision.</p>
|
||||||
|
*
|
||||||
|
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of <tt>Sid</tt>s,
|
||||||
|
* although the implementation is permitted to throw one of the signature-defined exceptions if the method
|
||||||
|
* is called requesting an authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* @param permission the permission or permissions required (at least one entry required)
|
||||||
* The actual approach used to make authorization decisions is left to the
|
* @param sids the security identities held by the principal (at least one entry required)
|
||||||
* implementation and is not specified by this interface. For example, an
|
* @param administrativeMode if <tt>true</tt> denotes the query is for administrative purposes and no logging
|
||||||
* implementation <em>MAY</em> search the current ACL in the order the ACL entries
|
* or auditing (if supported by the implementation) should be undertaken
|
||||||
* have been stored. If a single entry is found that has the same active bits as are
|
|
||||||
* shown in a passed <tt>Permission</tt>, that entry's grant or deny state may
|
|
||||||
* determine the authorization decision. If the case of a deny state, the deny
|
|
||||||
* decision will only be relevant if all other <tt>Permission</tt>s passed in the
|
|
||||||
* array have also been unsuccessfully searched. If no entry is found that match the
|
|
||||||
* bits in the current ACL, provided that {@link #isEntriesInheriting()} is
|
|
||||||
* <tt>true</tt>, the authorization decision may be passed to the parent ACL. If there
|
|
||||||
* is no matching entry, the implementation MAY throw an exception, or make a
|
|
||||||
* predefined authorization decision.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* This method must operate correctly even if the <tt>Acl</tt> only represents a
|
|
||||||
* subset of <tt>Sid</tt>s, although the implementation is permitted to throw one of
|
|
||||||
* the signature-defined exceptions if the method is called requesting an
|
|
||||||
* 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
|
|
||||||
* required)
|
|
||||||
* @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
|
* @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
|
* @throws NotFoundException MUST be thrown if an implementation cannot make an authoritative authorization
|
||||||
* for this particular permission and/or SID
|
* 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
|
* @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for one or more of the
|
||||||
* one or more of the <tt>Sid</tt>s passed as arguments
|
* <tt>Sid</tt>s passed as arguments
|
||||||
*/
|
*/
|
||||||
boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||||
throws NotFoundException, UnloadedSidException;
|
throws NotFoundException, UnloadedSidException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain
|
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain entries for every
|
||||||
* entries for every <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded
|
* <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded and does not represent every
|
||||||
* and does not represent every <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only
|
* <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only be used within the limited scope of the
|
||||||
* be used within the limited scope of the <tt>Sid</tt> instances it actually
|
* <tt>Sid</tt> instances it actually represents.
|
||||||
* represents.
|
|
||||||
* <p>
|
* <p>
|
||||||
* It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only
|
* It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only authorization
|
||||||
* authorization decisions are being made. However, if user interface reporting or
|
* decisions are being made. However, if user interface reporting or modification of <tt>Acl</tt>s are
|
||||||
* modification of <tt>Acl</tt>s are desired, an <tt>Acl</tt> should be loaded with
|
* desired, an <tt>Acl</tt> should be loaded with all <tt>Sid</tt>s. This method denotes whether or
|
||||||
* all <tt>Sid</tt>s. This method denotes whether or not the specified <tt>Sid</tt>s
|
* not the specified <tt>Sid</tt>s have been loaded or not.
|
||||||
* have been loaded or not.
|
|
||||||
* </p>
|
* </p>
|
||||||
* @param sids one or more security identities the caller is interest in knowing
|
*
|
||||||
* whether this <tt>Sid</tt> supports
|
* @param sids one or more security identities the caller is interest in knowing whether this <tt>Sid</tt>
|
||||||
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this
|
* supports
|
||||||
* <tt>Acl</tt> instance
|
*
|
||||||
|
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this <tt>Acl</tt> instance
|
||||||
*/
|
*/
|
||||||
boolean isSidLoaded(List<Sid> sids);
|
boolean isSidLoaded(List<Sid> sids);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,19 +12,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
import org.springframework.security.acls.jdbc.JdbcAclService;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.springframework.security.acls.jdbc.JdbcAclService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A caching layer for {@link JdbcAclService}.
|
* A caching layer for {@link JdbcAclService}.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface AclCache {
|
public interface AclCache {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
void evictFromCache(Serializable pk);
|
void evictFromCache(Serializable pk);
|
||||||
|
|
||||||
@@ -38,5 +39,4 @@ public interface AclCache {
|
|||||||
void putInCache(MutableAcl acl);
|
void putInCache(MutableAcl acl);
|
||||||
|
|
||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-21
@@ -1,19 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,8 +9,9 @@ package org.springframework.security.acls.model;
|
|||||||
public abstract class AclDataAccessException extends RuntimeException {
|
public abstract class AclDataAccessException extends RuntimeException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>AclDataAccessException</code> with the specified message and
|
* Constructs an <code>AclDataAccessException</code> with the specified
|
||||||
* root cause.
|
* message and root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
* @param cause the root cause
|
* @param cause the root cause
|
||||||
*/
|
*/
|
||||||
@@ -35,12 +20,12 @@ public abstract class AclDataAccessException extends RuntimeException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>AclDataAccessException</code> with the specified message and no
|
* Constructs an <code>AclDataAccessException</code> with the specified
|
||||||
* root cause.
|
* message and no root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public AclDataAccessException(String msg) {
|
public AclDataAccessException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,23 +12,26 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides retrieval of {@link Acl} instances.
|
* Provides retrieval of {@link Acl} instances.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface AclService {
|
public interface AclService {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locates all object identities that use the specified parent. This is useful for
|
* Locates all object identities that use the specified parent. This is useful for administration tools.
|
||||||
* administration tools.
|
*
|
||||||
* @param parentIdentity to locate children of
|
* @param parentIdentity to locate children of
|
||||||
|
*
|
||||||
* @return the children (or <tt>null</tt> if none were found)
|
* @return the children (or <tt>null</tt> if none were found)
|
||||||
*/
|
*/
|
||||||
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||||
@@ -37,67 +39,60 @@ public interface AclService {
|
|||||||
/**
|
/**
|
||||||
* Same as {@link #readAclsById(List)} except it returns only a single Acl.
|
* Same as {@link #readAclsById(List)} except it returns only a single Acl.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should not be called as it does not leverage the underlying
|
* This method should not be called as it does not leverage the underlying implementation's potential ability to
|
||||||
* implementation's potential ability to filter <tt>Acl</tt> entries based on a
|
* filter <tt>Acl</tt> entries based on a {@link Sid} parameter.</p>
|
||||||
* {@link Sid} parameter.
|
*
|
||||||
* </p>
|
|
||||||
* @param object to locate an {@link Acl} for
|
* @param object to locate an {@link Acl} for
|
||||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never
|
*
|
||||||
* <tt>null</tt>)
|
* @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}
|
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||||
*/
|
*/
|
||||||
Acl readAclById(ObjectIdentity object) throws NotFoundException;
|
Acl readAclById(ObjectIdentity object) throws NotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as {@link #readAclsById(List, List)} except it returns only a single Acl.
|
* Same as {@link #readAclsById(List, List)} except it returns only a single Acl.
|
||||||
|
*
|
||||||
* @param object to locate an {@link Acl} for
|
* @param object to locate an {@link Acl} for
|
||||||
* @param sids the security identities for which {@link Acl} information is required
|
* @param sids the security identities for which {@link Acl} information is required
|
||||||
* (may be <tt>null</tt> to denote all entries)
|
* (may be <tt>null</tt> to denote all entries)
|
||||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never
|
*
|
||||||
* <tt>null</tt>)
|
* @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}
|
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||||
*/
|
*/
|
||||||
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
|
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.
|
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.<p>The returned map is
|
||||||
* <p>
|
* keyed on the passed objects, with the values being the <tt>Acl</tt> instances. Any unknown objects will not
|
||||||
* The returned map is keyed on the passed objects, with the values being the
|
* have a map key.</p>
|
||||||
* <tt>Acl</tt> instances. Any unknown objects will not have a map key.
|
*
|
||||||
* </p>
|
|
||||||
* @param objects the objects to find {@link Acl} information for
|
* @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>)
|
* @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}
|
* @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
|
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only for the
|
||||||
* for the security identifies passed.
|
* security identifies passed.<p>Implementations <em>MAY</em> provide a subset of the ACLs via this method
|
||||||
* <p>
|
* although this is NOT a requirement. This is intended to allow performance optimisations within implementations.
|
||||||
* Implementations <em>MAY</em> provide a subset of the ACLs via this method although
|
* Callers should therefore use this method in preference to the alternative overloaded version which does not
|
||||||
* this is NOT a requirement. This is intended to allow performance optimisations
|
* have performance optimisation opportunities.</p>
|
||||||
* within implementations. Callers should therefore use this method in preference to
|
* <p>The returned map is keyed on the passed objects, with the values being the <tt>Acl</tt>
|
||||||
* the alternative overloaded version which does not have performance optimisation
|
* instances. Any unknown objects (or objects for which the interested <tt>Sid</tt>s do not have entries) will
|
||||||
* opportunities.
|
* not have a map key.</p>
|
||||||
* </p>
|
*
|
||||||
* <p>
|
|
||||||
* The returned map is keyed on the passed objects, with the values being the
|
|
||||||
* <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 objects the objects to find {@link Acl} information for
|
||||||
* @param sids the security identities for which {@link Acl} information is required
|
* @param sids the security identities for which {@link Acl} information is required
|
||||||
* (may be <tt>null</tt> to denote all entries)
|
* (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>)
|
* @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}
|
* @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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-10
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,18 +12,20 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if an <code>Acl</code> entry already exists for the object.
|
* Thrown if an <code>Acl</code> entry already exists for the object.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class AlreadyExistsException extends AclDataAccessException {
|
public class AlreadyExistsException extends AclDataAccessException {
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>AlreadyExistsException</code> with the specified message.
|
* Constructs an <code>AlreadyExistsException</code> with the specified message.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public AlreadyExistsException(String msg) {
|
public AlreadyExistsException(String msg) {
|
||||||
@@ -32,13 +33,13 @@ public class AlreadyExistsException extends AclDataAccessException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>AlreadyExistsException</code> with the specified message and
|
* Constructs an <code>AlreadyExistsException</code> with the specified message
|
||||||
* root cause.
|
* and root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
* @param cause root cause
|
* @param t root cause
|
||||||
*/
|
*/
|
||||||
public AlreadyExistsException(String msg, Throwable cause) {
|
public AlreadyExistsException(String msg, Throwable t) {
|
||||||
super(msg, cause);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,18 +12,19 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an ACE that provides auditing information.
|
* Represents an ACE that provides auditing information.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface AuditableAccessControlEntry extends AccessControlEntry {
|
public interface AuditableAccessControlEntry extends AccessControlEntry {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
boolean isAuditFailure();
|
boolean isAuditFailure();
|
||||||
|
|
||||||
boolean isAuditSuccess();
|
boolean isAuditSuccess();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,16 +12,17 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mutable ACL that provides audit capabilities.
|
* A mutable ACL that provides audit capabilities.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface AuditableAcl extends MutableAcl {
|
public interface AuditableAcl extends MutableAcl {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
|
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-11
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,18 +12,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if an {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
|
* Thrown if an {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class ChildrenExistException extends AclDataAccessException {
|
public class ChildrenExistException extends AclDataAccessException {
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>ChildrenExistException</code> with the specified message.
|
* Constructs an <code>ChildrenExistException</code> with the specified
|
||||||
|
* message.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public ChildrenExistException(String msg) {
|
public ChildrenExistException(String msg) {
|
||||||
@@ -32,13 +34,13 @@ public class ChildrenExistException extends AclDataAccessException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>ChildrenExistException</code> with the specified message and
|
* Constructs an <code>ChildrenExistException</code> with the specified
|
||||||
* root cause.
|
* message and root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
* @param cause root cause
|
* @param t root cause
|
||||||
*/
|
*/
|
||||||
public ChildrenExistException(String msg, Throwable cause) {
|
public ChildrenExistException(String msg, Throwable t) {
|
||||||
super(msg, cause);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,49 +12,56 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mutable <tt>Acl</tt>.
|
* A mutable <tt>Acl</tt>.
|
||||||
* <p>
|
* <p>
|
||||||
* A mutable ACL must ensure that appropriate security checks are performed before
|
* A mutable ACL must ensure that appropriate security checks are performed
|
||||||
* allowing access to its methods.
|
* before allowing access to its methods.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface MutableAcl extends Acl {
|
public interface MutableAcl extends Acl {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
void deleteAce(int aceIndex) throws NotFoundException;
|
void deleteAce(int aceIndex) throws NotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
|
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
|
||||||
|
*
|
||||||
* @return the identifier, or <tt>null</tt> if unsaved
|
* @return the identifier, or <tt>null</tt> if unsaved
|
||||||
*/
|
*/
|
||||||
Serializable getId();
|
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.
|
* Changes the present owner to a different owner.
|
||||||
|
*
|
||||||
* @param newOwner the new owner (mandatory; cannot be null)
|
* @param newOwner the new owner (mandatory; cannot be null)
|
||||||
*/
|
*/
|
||||||
void setOwner(Sid newOwner);
|
void setOwner(Sid newOwner);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the value returned by {@link Acl#isEntriesInheriting()}.
|
* Change the value returned by {@link Acl#isEntriesInheriting()}.
|
||||||
|
*
|
||||||
* @param entriesInheriting the new value
|
* @param entriesInheriting the new value
|
||||||
*/
|
*/
|
||||||
void setEntriesInheriting(boolean entriesInheriting);
|
void setEntriesInheriting(boolean entriesInheriting);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the parent of this ACL.
|
* Changes the parent of this ACL.
|
||||||
|
*
|
||||||
* @param newParent the new parent
|
* @param newParent the new parent
|
||||||
*/
|
*/
|
||||||
void setParent(Acl newParent);
|
void setParent(Acl newParent);
|
||||||
|
|
||||||
void updateAce(int aceIndex, Permission permission) throws NotFoundException;
|
void updateAce(int aceIndex, Permission permission)
|
||||||
|
throws NotFoundException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,41 +12,50 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides support for creating and storing <code>Acl</code> instances.
|
* Provides support for creating and storing <code>Acl</code> instances.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface MutableAclService extends AclService {
|
public interface MutableAclService extends AclService {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty <code>Acl</code> object in the database. It will have no entries.
|
* Creates an empty <code>Acl</code> object in the database. It will have no entries. The returned object
|
||||||
* The returned object will then be used to add entries.
|
* will then be used to add entries.
|
||||||
|
*
|
||||||
* @param objectIdentity the object identity to create
|
* @param objectIdentity the object identity to create
|
||||||
|
*
|
||||||
* @return an ACL object with its ID set
|
* @return an ACL object with its ID set
|
||||||
|
*
|
||||||
* @throws AlreadyExistsException if the passed object identity already has a record
|
* @throws AlreadyExistsException if the passed object identity already has a record
|
||||||
*/
|
*/
|
||||||
MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException;
|
MutableAcl createAcl(ObjectIdentity objectIdentity)
|
||||||
|
throws AlreadyExistsException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the specified entry from the database.
|
* Removes the specified entry from the database.
|
||||||
|
*
|
||||||
* @param objectIdentity the object identity to remove
|
* @param objectIdentity the object identity to remove
|
||||||
* @param deleteChildren whether to cascade the delete to children
|
* @param deleteChildren whether to cascade the delete to children
|
||||||
* @throws ChildrenExistException if the deleteChildren argument was
|
*
|
||||||
* <code>false</code> but children exist
|
* @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.
|
* Changes an existing <code>Acl</code> in the database.
|
||||||
|
*
|
||||||
* @param acl to modify
|
* @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
|
* @throws NotFoundException if the relevant record could not be found (did you remember to use {@link
|
||||||
* than creating it with the <code>new</code> keyword?)
|
* #createAcl(ObjectIdentity)} to create the object, rather than creating it with the <code>new</code>
|
||||||
|
* keyword?)
|
||||||
*/
|
*/
|
||||||
MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
|
MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,18 +12,20 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if an ACL-related object cannot be found.
|
* Thrown if an ACL-related object cannot be found.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class NotFoundException extends AclDataAccessException {
|
public class NotFoundException extends AclDataAccessException {
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public NotFoundException(String msg) {
|
public NotFoundException(String msg) {
|
||||||
@@ -32,13 +33,13 @@ public class NotFoundException extends AclDataAccessException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>NotFoundException</code> with the specified message and root
|
* Constructs an <code>NotFoundException</code> with the specified message
|
||||||
* cause.
|
* and root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
* @param cause root cause
|
* @param t root cause
|
||||||
*/
|
*/
|
||||||
public NotFoundException(String msg, Throwable cause) {
|
public NotFoundException(String msg, Throwable t) {
|
||||||
super(msg, cause);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,53 +12,53 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the identity of an individual domain object instance.
|
* Represents the identity of an individual domain object instance.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent domain
|
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
||||||
* objects in the ACL subsystem, it is essential that implementations provide methods so
|
* domain objects in the ACL subsystem, it is essential that implementations provide
|
||||||
* that object-equality rather than reference-equality can be relied upon reliably. In
|
* methods so that object-equality rather than reference-equality can be relied upon
|
||||||
* other words, the ACL subsystem can consider two <tt>ObjectIdentity</tt>s equal if
|
* reliably. In other words, the ACL subsystem can consider two
|
||||||
* <tt>identity1.equals(identity2)</tt>, rather than reference-equality of
|
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
||||||
* <tt>identity1==identity2</tt>.
|
* reference-equality of <tt>identity1==identity2</tt>.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface ObjectIdentity extends Serializable {
|
public interface ObjectIdentity extends Serializable {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param obj to be compared
|
* @param obj to be compared
|
||||||
|
*
|
||||||
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
|
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
|
||||||
* @see Object#equals(Object)
|
* @see Object#equals(Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
boolean equals(Object obj);
|
boolean equals(Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the actual identifier. This identifier must not be reused to represent
|
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
|
||||||
* other domain objects with the same <tt>javaType</tt>.
|
* the same <tt>javaType</tt>.
|
||||||
|
*
|
||||||
|
* <p>Because ACLs are largely immutable, it is strongly recommended to use
|
||||||
|
* a synthetic identifier (such as a database sequence number for the primary key). Do not use an identifier with
|
||||||
|
* business meaning, as that business meaning may change in the future such change will cascade to the ACL
|
||||||
|
* subsystem data.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
|
||||||
* Because ACLs are largely immutable, it is strongly recommended to use a synthetic
|
|
||||||
* identifier (such as a database sequence number for the primary key). Do not use an
|
|
||||||
* 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>)
|
* @return the identifier (unique within this <tt>type</tt>; never <tt>null</tt>)
|
||||||
*/
|
*/
|
||||||
Serializable getIdentifier();
|
Serializable getIdentifier();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains the "type" metadata for the domain object. This will often be a Java type
|
* Obtains the "type" metadata for the domain object. This will often be a Java type name (an interface or a class)
|
||||||
* name (an interface or a class) – traditionally it is the name of the domain
|
* – traditionally it is the name of the domain object implementation class.
|
||||||
* object implementation class.
|
*
|
||||||
* @return the "type" of the domain object (never <tt>null</tt>).
|
* @return the "type" of the domain object (never <tt>null</tt>).
|
||||||
*/
|
*/
|
||||||
String getType();
|
String getType();
|
||||||
@@ -68,7 +67,5 @@ public interface ObjectIdentity extends Serializable {
|
|||||||
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
||||||
* @see Object#hashCode()
|
* @see Object#hashCode()
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
int hashCode();
|
int hashCode();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-22
@@ -1,29 +1,14 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy which creates an {@link ObjectIdentity} from an object identifier (such as a
|
* Strategy which creates an {@link ObjectIdentity} from an object identifier (such as a primary key)
|
||||||
* primary key) and type information.
|
* and type information.
|
||||||
* <p>
|
* <p>
|
||||||
* Differs from {@link ObjectIdentityRetrievalStrategy} in that it is used in situations
|
* Differs from {@link ObjectIdentityRetrievalStrategy} in that it is used in situations when the actual object
|
||||||
* when the actual object instance isn't available.
|
* instance isn't available.
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
@@ -31,10 +16,10 @@ import java.io.Serializable;
|
|||||||
public interface ObjectIdentityGenerator {
|
public interface ObjectIdentityGenerator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* @param id the identifier of the domain object, not null
|
* @param id the identifier of the domain object, not null
|
||||||
* @param type the type of the object (often a class name), 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
|
* @return the identity constructed using the supplied identifier and type information.
|
||||||
* information.
|
|
||||||
*/
|
*/
|
||||||
ObjectIdentity createObjectIdentity(Serializable id, String type);
|
ObjectIdentity createObjectIdentity(Serializable id, String type);
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -16,14 +15,16 @@
|
|||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
|
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
|
||||||
* will be returned for a particular domain object
|
* will be returned for a particular domain object
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public interface ObjectIdentityRetrievalStrategy {
|
public interface ObjectIdentityRetrievalStrategy {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
ObjectIdentity getObjectIdentity(Object domainObject);
|
ObjectIdentity getObjectIdentity(Object domainObject);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,21 +12,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mutable ACL that provides ownership capabilities.
|
* A mutable ACL that provides ownership capabilities.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Generally the owner of an ACL is able to call any ACL mutator method, as well as assign
|
* Generally the owner of an ACL is able to call any ACL mutator method, as
|
||||||
* a new owner.
|
* well as assign a new owner.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface OwnershipAcl extends MutableAcl {
|
public interface OwnershipAcl extends MutableAcl {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
@Override
|
|
||||||
void setOwner(Sid newOwner);
|
void setOwner(Sid newOwner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -24,37 +22,36 @@ import java.io.Serializable;
|
|||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface Permission extends Serializable {
|
public interface Permission extends Serializable {
|
||||||
|
//~ Static fields/initializers =====================================================================================
|
||||||
|
|
||||||
char RESERVED_ON = '~';
|
char RESERVED_ON = '~';
|
||||||
|
|
||||||
char RESERVED_OFF = '.';
|
char RESERVED_OFF = '.';
|
||||||
|
|
||||||
String THIRTY_TWO_RESERVED_OFF = "................................";
|
String THIRTY_TWO_RESERVED_OFF = "................................";
|
||||||
|
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bits that represents the permission.
|
* Returns the bits that represents the permission.
|
||||||
|
*
|
||||||
* @return the bits that represent the permission
|
* @return the bits that represent the permission
|
||||||
*/
|
*/
|
||||||
int getMask();
|
int getMask();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a 32-character long bit pattern <code>String</code> representing this
|
* Returns a 32-character long bit pattern <code>String</code> representing this permission.
|
||||||
* permission.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Implementations are free to format the pattern as they see fit, although under no
|
* Implementations are free to format the pattern as they see fit, although under no circumstances may
|
||||||
* circumstances may {@link #RESERVED_OFF} or {@link #RESERVED_ON} be used within the
|
* {@link #RESERVED_OFF} or {@link #RESERVED_ON} be used within the pattern. An exemption is in the case of
|
||||||
* pattern. An exemption is in the case of {@link #RESERVED_OFF} which is used to
|
* {@link #RESERVED_OFF} which is used to denote a bit that is off (clear).
|
||||||
* denote a bit that is off (clear). Implementations may also elect to use
|
* Implementations may also elect to use {@link #RESERVED_ON} internally for computation purposes,
|
||||||
* {@link #RESERVED_ON} internally for computation purposes, although this method may
|
* although this method may not return any <code>String</code> containing {@link #RESERVED_ON}.
|
||||||
* not return any <code>String</code> containing {@link #RESERVED_ON}.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The returned String must be 32 characters in length.
|
* The returned String must be 32 characters in length.
|
||||||
* <p>
|
* <p>
|
||||||
* This method is only used for user interface and logging purposes. It is not used in
|
* This method is only used for user interface and logging purposes. It is not used in any permission
|
||||||
* any permission calculations. Therefore, duplication of characters within the output
|
* calculations. Therefore, duplication of characters within the output is permitted.
|
||||||
* is permitted.
|
*
|
||||||
* @return a 32-character bit pattern
|
* @return a 32-character bit pattern
|
||||||
*/
|
*/
|
||||||
String getPattern();
|
String getPattern();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.model;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow customization of the logic for determining whether a permission or permissions
|
|
||||||
* are granted to a particular sid or sids by an {@link Acl}.
|
|
||||||
*
|
|
||||||
* @author Luke Taylor
|
|
||||||
* @since 3.0.2
|
|
||||||
*/
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,7 +12,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@@ -22,32 +20,32 @@ import java.io.Serializable;
|
|||||||
* A security identity recognised by the ACL system.
|
* A security identity recognised by the ACL system.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This interface provides indirection between actual security objects (eg principals,
|
* This interface provides indirection between actual security objects (eg
|
||||||
* roles, groups etc) and what is stored inside an <code>Acl</code>. This is because an
|
* principals, roles, groups etc) and what is stored inside an
|
||||||
* <code>Acl</code> will not store an entire security object, but only an abstraction of
|
* <code>Acl</code>. This is because an <code>Acl</code> will not store an
|
||||||
* it. This interface therefore provides a simple way to compare these abstracted security
|
* entire security object, but only an abstraction of it. This interface
|
||||||
|
* therefore provides a simple way to compare these abstracted security
|
||||||
* identities with other security identities and actual security objects.
|
* identities with other security identities and actual security objects.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface Sid extends Serializable {
|
public interface Sid extends Serializable {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refer to the <code>java.lang.Object</code> documentation for the interface
|
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
|
||||||
* contract.
|
*
|
||||||
* @param obj to be compared
|
* @param obj to be compared
|
||||||
|
*
|
||||||
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
|
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
boolean equals(Object obj);
|
boolean equals(Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refer to the <code>java.lang.Object</code> documentation for the interface
|
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
|
||||||
* contract.
|
*
|
||||||
* @return a hash code representation of this object
|
* @return a hash code representation of this object
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
int hashCode();
|
int hashCode();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -20,14 +19,15 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy interface that provides an ability to determine the {@link Sid} instances
|
* Strategy interface that provides an ability to determine the {@link Sid} instances applicable
|
||||||
* applicable for an {@link Authentication}.
|
* for an {@link Authentication}.
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public interface SidRetrievalStrategy {
|
public interface SidRetrievalStrategy {
|
||||||
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
List<Sid> getSids(Authentication authentication);
|
List<Sid> getSids(Authentication authentication);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -1,11 +1,10 @@
|
|||||||
/*
|
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@@ -13,20 +12,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if an {@link Acl} cannot perform an operation because it only loaded a subset of
|
* Thrown if an {@link Acl} cannot perform an operation because it only loaded a subset of <code>Sid</code>s and
|
||||||
* <code>Sid</code>s and the caller has requested details for an unloaded <code>Sid</code>
|
* the caller has requested details for an unloaded <code>Sid</code>.
|
||||||
* .
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
*/
|
*/
|
||||||
public class UnloadedSidException extends AclDataAccessException {
|
public class UnloadedSidException extends AclDataAccessException {
|
||||||
|
//~ Constructors ===================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
*/
|
*/
|
||||||
public UnloadedSidException(String msg) {
|
public UnloadedSidException(String msg) {
|
||||||
@@ -34,13 +34,13 @@ public class UnloadedSidException extends AclDataAccessException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an <code>NotFoundException</code> with the specified message and root
|
* Constructs an <code>NotFoundException</code> with the specified message
|
||||||
* cause.
|
* and root cause.
|
||||||
|
*
|
||||||
* @param msg the detail message
|
* @param msg the detail message
|
||||||
* @param cause root cause
|
* @param t root cause
|
||||||
*/
|
*/
|
||||||
public UnloadedSidException(String msg, Throwable cause) {
|
public UnloadedSidException(String msg, Throwable t) {
|
||||||
super(msg, cause);
|
super(msg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,5 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interfaces and shared classes to manage access control lists (ACLs) for domain object
|
* Interfaces and shared classes to manage access control lists (ACLs) for domain object instances.
|
||||||
* instances.
|
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.acls.model;
|
package org.springframework.security.acls.model;
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,9 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Spring Security ACL package which implements instance-based security for domain
|
* The Spring Security ACL package which implements instance-based security for domain objects.
|
||||||
* objects.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Consider using the annotation based approach ({@code @PreAuthorize},
|
* Consider using the annotation based approach ({@code @PreAuthorize}, {@code @PostFilter} annotations) combined
|
||||||
* {@code @PostFilter} annotations) combined with a
|
* with a {@link org.springframework.security.acls.AclPermissionEvaluator} in preference to the older and more verbose
|
||||||
* {@link org.springframework.security.acls.AclPermissionEvaluator} in preference to the
|
* attribute/voter/after-invocation approach from versions before Spring Security 3.0.
|
||||||
* older and more verbose attribute/voter/after-invocation approach from versions before
|
|
||||||
* Spring Security 3.0.
|
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.acls;
|
package org.springframework.security.acls;
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
-- drop table acl_class;
|
-- drop table acl_class;
|
||||||
-- drop table acl_sid;
|
-- drop table acl_sid;
|
||||||
|
|
||||||
|
|
||||||
create table acl_sid(
|
create table acl_sid(
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
id bigint generated by default as identity(start with 100) not null primary key,
|
||||||
principal boolean not null,
|
principal boolean not null,
|
||||||
sid varchar_ignorecase(100) not null,
|
sid varchar_ignorecase(100) not null,
|
||||||
constraint unique_uk_1 unique(sid,principal)
|
constraint unique_uk_1 unique(sid,principal));
|
||||||
);
|
|
||||||
|
|
||||||
create table acl_class(
|
create table acl_class(
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
id bigint generated by default as identity(start with 100) not null primary key,
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
-- ACL Schema SQL for MySQL 5.5+ / MariaDB equivalent
|
|
||||||
|
|
||||||
-- drop table acl_entry;
|
|
||||||
-- drop table acl_object_identity;
|
|
||||||
-- drop table acl_class;
|
|
||||||
-- drop table acl_sid;
|
|
||||||
|
|
||||||
CREATE TABLE acl_sid (
|
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
principal BOOLEAN NOT NULL,
|
|
||||||
sid VARCHAR(100) NOT NULL,
|
|
||||||
UNIQUE KEY unique_acl_sid (sid, principal)
|
|
||||||
) ENGINE=InnoDB;
|
|
||||||
|
|
||||||
CREATE TABLE acl_class (
|
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
class VARCHAR(100) NOT NULL,
|
|
||||||
UNIQUE KEY uk_acl_class (class)
|
|
||||||
) ENGINE=InnoDB;
|
|
||||||
|
|
||||||
CREATE TABLE acl_object_identity (
|
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
object_id_class BIGINT UNSIGNED NOT NULL,
|
|
||||||
object_id_identity VARCHAR(36) NOT NULL,
|
|
||||||
parent_object BIGINT UNSIGNED,
|
|
||||||
owner_sid BIGINT UNSIGNED,
|
|
||||||
entries_inheriting BOOLEAN NOT NULL,
|
|
||||||
UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity),
|
|
||||||
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
|
|
||||||
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
|
|
||||||
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
|
|
||||||
) ENGINE=InnoDB;
|
|
||||||
|
|
||||||
CREATE TABLE acl_entry (
|
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
acl_object_identity BIGINT UNSIGNED NOT NULL,
|
|
||||||
ace_order INTEGER NOT NULL,
|
|
||||||
sid BIGINT UNSIGNED NOT NULL,
|
|
||||||
mask INTEGER UNSIGNED NOT NULL,
|
|
||||||
granting BOOLEAN NOT NULL,
|
|
||||||
audit_success BOOLEAN NOT NULL,
|
|
||||||
audit_failure BOOLEAN NOT NULL,
|
|
||||||
UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order),
|
|
||||||
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
|
|
||||||
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
|
|
||||||
) ENGINE=InnoDB;
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
-- ACL Schema SQL for Oracle Database 10g+
|
|
||||||
|
|
||||||
-- drop trigger acl_sid_id_trigger;
|
|
||||||
-- drop trigger acl_class_id_trigger;
|
|
||||||
-- drop trigger acl_object_identity_id_trigger;
|
|
||||||
-- drop trigger acl_entry_id_trigger;
|
|
||||||
-- drop sequence acl_sid_sequence;
|
|
||||||
-- drop sequence acl_class_sequence;
|
|
||||||
-- drop sequence acl_object_identity_sequence;
|
|
||||||
-- drop sequence acl_entry_sequence;
|
|
||||||
-- drop table acl_entry;
|
|
||||||
-- drop table acl_object_identity;
|
|
||||||
-- drop table acl_class;
|
|
||||||
-- drop table acl_sid;
|
|
||||||
|
|
||||||
CREATE TABLE acl_sid (
|
|
||||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
|
||||||
principal NUMBER(1) NOT NULL CHECK (principal in (0, 1)),
|
|
||||||
sid NVARCHAR2(100) NOT NULL,
|
|
||||||
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
|
|
||||||
);
|
|
||||||
CREATE SEQUENCE acl_sid_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
|
||||||
CREATE OR REPLACE TRIGGER acl_sid_id_trigger
|
|
||||||
BEFORE INSERT ON acl_sid
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
SELECT acl_sid_sequence.nextval INTO :new.id FROM dual;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TABLE acl_class (
|
|
||||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
|
||||||
class NVARCHAR2(100) NOT NULL,
|
|
||||||
CONSTRAINT uk_acl_class UNIQUE (class)
|
|
||||||
);
|
|
||||||
CREATE SEQUENCE acl_class_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
|
||||||
CREATE OR REPLACE TRIGGER acl_class_id_trigger
|
|
||||||
BEFORE INSERT ON acl_class
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
SELECT acl_class_sequence.nextval INTO :new.id FROM dual;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TABLE acl_object_identity (
|
|
||||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
|
||||||
object_id_class NUMBER(38) NOT NULL,
|
|
||||||
object_id_identity NVARCHAR2(36) NOT NULL,
|
|
||||||
parent_object NUMBER(38),
|
|
||||||
owner_sid NUMBER(38),
|
|
||||||
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
|
|
||||||
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
|
|
||||||
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
|
|
||||||
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
|
|
||||||
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
|
|
||||||
);
|
|
||||||
CREATE SEQUENCE acl_object_identity_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
|
||||||
CREATE OR REPLACE TRIGGER acl_object_identity_id_trigger
|
|
||||||
BEFORE INSERT ON acl_object_identity
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
SELECT acl_object_identity_sequence.nextval INTO :new.id FROM dual;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TABLE acl_entry (
|
|
||||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
|
||||||
acl_object_identity NUMBER(38) NOT NULL,
|
|
||||||
ace_order INTEGER NOT NULL,
|
|
||||||
sid NUMBER(38) NOT NULL,
|
|
||||||
mask INTEGER NOT NULL,
|
|
||||||
granting NUMBER(1) NOT NULL CHECK (granting in (0, 1)),
|
|
||||||
audit_success NUMBER(1) NOT NULL CHECK (audit_success in (0, 1)),
|
|
||||||
audit_failure NUMBER(1) NOT NULL CHECK (audit_failure in (0, 1)),
|
|
||||||
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
|
|
||||||
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
|
|
||||||
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
|
|
||||||
);
|
|
||||||
CREATE SEQUENCE acl_entry_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
|
|
||||||
CREATE OR REPLACE TRIGGER acl_entry_id_trigger
|
|
||||||
BEFORE INSERT ON acl_entry
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
SELECT acl_entry_sequence.nextval INTO :new.id FROM dual;
|
|
||||||
END;
|
|
||||||
@@ -15,14 +15,13 @@ create table acl_sid(
|
|||||||
create table acl_class(
|
create table acl_class(
|
||||||
id bigserial not null primary key,
|
id bigserial not null primary key,
|
||||||
class varchar(100) not null,
|
class varchar(100) not null,
|
||||||
class_id_type varchar(100),
|
|
||||||
constraint unique_uk_2 unique(class)
|
constraint unique_uk_2 unique(class)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table acl_object_identity(
|
create table acl_object_identity(
|
||||||
id bigserial primary key,
|
id bigserial primary key,
|
||||||
object_id_class bigint not null,
|
object_id_class bigint not null,
|
||||||
object_id_identity varchar(36) not null,
|
object_id_identity bigint not null,
|
||||||
parent_object bigint,
|
parent_object bigint,
|
||||||
owner_sid bigint,
|
owner_sid bigint,
|
||||||
entries_inheriting boolean not null,
|
entries_inheriting boolean not null,
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
-- ACL Schema SQL for Microsoft SQL Server 2008+
|
|
||||||
|
|
||||||
-- drop table acl_entry;
|
|
||||||
-- drop table acl_object_identity;
|
|
||||||
-- drop table acl_class;
|
|
||||||
-- drop table acl_sid;
|
|
||||||
|
|
||||||
CREATE TABLE acl_sid (
|
|
||||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
|
||||||
principal BIT NOT NULL,
|
|
||||||
sid VARCHAR(100) NOT NULL,
|
|
||||||
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE acl_class (
|
|
||||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
|
||||||
class VARCHAR(100) NOT NULL,
|
|
||||||
CONSTRAINT uk_acl_class UNIQUE (class)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE acl_object_identity (
|
|
||||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
|
||||||
object_id_class BIGINT NOT NULL,
|
|
||||||
object_id_identity VARCHAR(36) NOT NULL,
|
|
||||||
parent_object BIGINT,
|
|
||||||
owner_sid BIGINT,
|
|
||||||
entries_inheriting BIT NOT NULL,
|
|
||||||
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
|
|
||||||
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
|
|
||||||
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
|
|
||||||
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE acl_entry (
|
|
||||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
|
||||||
acl_object_identity BIGINT NOT NULL,
|
|
||||||
ace_order INTEGER NOT NULL,
|
|
||||||
sid BIGINT NOT NULL,
|
|
||||||
mask INTEGER NOT NULL,
|
|
||||||
granting BIT NOT NULL,
|
|
||||||
audit_success BIT NOT NULL,
|
|
||||||
audit_failure BIT NOT NULL,
|
|
||||||
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
|
|
||||||
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
|
|
||||||
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
|
|
||||||
);
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
-- ACL schema sql used in HSQLDB
|
|
||||||
|
|
||||||
-- drop table acl_entry;
|
|
||||||
-- drop table acl_object_identity;
|
|
||||||
-- drop table acl_class;
|
|
||||||
-- drop table acl_sid;
|
|
||||||
|
|
||||||
create table acl_sid(
|
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
|
||||||
principal boolean not null,
|
|
||||||
sid varchar_ignorecase(100) not null,
|
|
||||||
constraint unique_uk_1 unique(sid,principal)
|
|
||||||
);
|
|
||||||
|
|
||||||
create table acl_class(
|
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
|
||||||
class varchar_ignorecase(100) not null,
|
|
||||||
class_id_type varchar_ignorecase(100),
|
|
||||||
constraint unique_uk_2 unique(class)
|
|
||||||
);
|
|
||||||
|
|
||||||
create table acl_object_identity(
|
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
|
||||||
object_id_class bigint not null,
|
|
||||||
object_id_identity varchar_ignorecase(36) not null,
|
|
||||||
parent_object bigint,
|
|
||||||
owner_sid bigint,
|
|
||||||
entries_inheriting boolean not null,
|
|
||||||
constraint unique_uk_3 unique(object_id_class,object_id_identity),
|
|
||||||
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
|
|
||||||
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
|
|
||||||
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
|
|
||||||
);
|
|
||||||
|
|
||||||
create table acl_entry(
|
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
|
||||||
acl_object_identity bigint not null,
|
|
||||||
ace_order int not null,
|
|
||||||
sid bigint not null,
|
|
||||||
mask integer not null,
|
|
||||||
granting boolean not null,
|
|
||||||
audit_success boolean not null,
|
|
||||||
audit_failure boolean not null,
|
|
||||||
constraint unique_uk_4 unique(acl_object_identity,ace_order),
|
|
||||||
constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
|
|
||||||
constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
|
|
||||||
);
|
|
||||||
@@ -1,92 +1,127 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004-present 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;
|
package org.springframework.security.acls;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import org.springframework.security.acls.domain.AclFormattingUtils;
|
import org.springframework.security.acls.domain.AclFormattingUtils;
|
||||||
import org.springframework.security.acls.model.Permission;
|
import org.springframework.security.acls.model.Permission;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import junit.framework.Assert;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import junit.framework.TestCase;
|
||||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link AclFormattingUtils}.
|
* Tests for {@link AclFormattingUtils}.
|
||||||
*
|
*
|
||||||
* @author Andrei Stefan
|
* @author Andrei Stefan
|
||||||
*/
|
*/
|
||||||
public class AclFormattingUtilsTests {
|
public class AclFormattingUtilsTests extends TestCase {
|
||||||
|
|
||||||
@Test
|
//~ Methods ========================================================================================================
|
||||||
public final void testDemergePatternsParametersConstraints() {
|
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.demergePatterns(null, "SOME STRING"));
|
public final void testDemergePatternsParametersConstraints() throws Exception {
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", null));
|
try {
|
||||||
assertThatIllegalArgumentException()
|
AclFormattingUtils.demergePatterns(null, "SOME STRING");
|
||||||
.isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", "LONGER SOME STRING"));
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
assertThatNoException().isThrownBy(() -> AclFormattingUtils.demergePatterns("SOME STRING", "SAME LENGTH"));
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
try {
|
||||||
public final void testDemergePatterns() {
|
AclFormattingUtils.demergePatterns("SOME STRING", null);
|
||||||
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AclFormattingUtils.demergePatterns("SOME STRING", "LONGER SOME STRING");
|
||||||
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AclFormattingUtils.demergePatterns("SOME STRING", "SAME LENGTH");
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException notExpected) {
|
||||||
|
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void testDemergePatterns() throws Exception {
|
||||||
String original = "...........................A...R";
|
String original = "...........................A...R";
|
||||||
String removeBits = "...............................R";
|
String removeBits = "...............................R";
|
||||||
assertThat(AclFormattingUtils.demergePatterns(original, removeBits))
|
Assert.assertEquals("...........................A....", AclFormattingUtils
|
||||||
.isEqualTo("...........................A....");
|
.demergePatterns(original, removeBits));
|
||||||
assertThat(AclFormattingUtils.demergePatterns("ABCDEF", "......")).isEqualTo("ABCDEF");
|
|
||||||
assertThat(AclFormattingUtils.demergePatterns("ABCDEF", "GHIJKL")).isEqualTo("......");
|
Assert.assertEquals("ABCDEF", AclFormattingUtils.demergePatterns("ABCDEF", "......"));
|
||||||
|
Assert.assertEquals("......", AclFormattingUtils.demergePatterns("ABCDEF", "GHIJKL"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
public final void testMergePatternsParametersConstraints() throws Exception {
|
||||||
public final void testMergePatternsParametersConstraints() {
|
try {
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.mergePatterns(null, "SOME STRING"));
|
AclFormattingUtils.mergePatterns(null, "SOME STRING");
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", null));
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
assertThatIllegalArgumentException()
|
}
|
||||||
.isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", "LONGER SOME STRING"));
|
catch (IllegalArgumentException expected) {
|
||||||
assertThatNoException().isThrownBy(() -> AclFormattingUtils.mergePatterns("SOME STRING", "SAME LENGTH"));
|
Assert.assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
try {
|
||||||
public final void testMergePatterns() {
|
AclFormattingUtils.mergePatterns("SOME STRING", null);
|
||||||
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AclFormattingUtils.mergePatterns("SOME STRING", "LONGER SOME STRING");
|
||||||
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AclFormattingUtils.mergePatterns("SOME STRING", "SAME LENGTH");
|
||||||
|
Assert.assertTrue(true);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException notExpected) {
|
||||||
|
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void testMergePatterns() throws Exception {
|
||||||
String original = "...............................R";
|
String original = "...............................R";
|
||||||
String extraBits = "...........................A....";
|
String extraBits = "...........................A....";
|
||||||
assertThat(AclFormattingUtils.mergePatterns(original, extraBits)).isEqualTo("...........................A...R");
|
Assert.assertEquals("...........................A...R", AclFormattingUtils
|
||||||
assertThat(AclFormattingUtils.mergePatterns("ABCDEF", "......")).isEqualTo("ABCDEF");
|
.mergePatterns(original, extraBits));
|
||||||
assertThat(AclFormattingUtils.mergePatterns("ABCDEF", "GHIJKL")).isEqualTo("GHIJKL");
|
|
||||||
|
Assert.assertEquals("ABCDEF", AclFormattingUtils.mergePatterns("ABCDEF", "......"));
|
||||||
|
Assert.assertEquals("GHIJKL", AclFormattingUtils.mergePatterns("ABCDEF", "GHIJKL"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
public final void testBinaryPrints() throws Exception {
|
||||||
public final void testBinaryPrints() {
|
Assert.assertEquals("............................****", AclFormattingUtils.printBinary(15));
|
||||||
assertThat(AclFormattingUtils.printBinary(15)).isEqualTo("............................****");
|
|
||||||
assertThatIllegalArgumentException()
|
try {
|
||||||
.isThrownBy(() -> AclFormattingUtils.printBinary(15, Permission.RESERVED_ON));
|
AclFormattingUtils.printBinary(15, Permission.RESERVED_ON);
|
||||||
assertThatIllegalArgumentException()
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
.isThrownBy(() -> AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF));
|
}
|
||||||
assertThat(AclFormattingUtils.printBinary(15, 'x')).isEqualTo("............................xxxx");
|
catch (IllegalArgumentException notExpected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
try {
|
||||||
public void testPrintBinaryNegative() {
|
AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF);
|
||||||
assertThat(AclFormattingUtils.printBinary(0x80000000)).isEqualTo("*...............................");
|
Assert.fail("It should have thrown IllegalArgumentException");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException notExpected) {
|
||||||
|
Assert.assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
Assert.assertEquals("............................xxxx", AclFormattingUtils.printBinary(15, 'x'));
|
||||||
public void testPrintBinaryMinusOne() {
|
|
||||||
assertThat(AclFormattingUtils.printBinary(0xffffffff)).isEqualTo("********************************");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user