Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b97237c6ef | |||
| e15470e783 | |||
| bdec47bd4a | |||
| 48c7285872 | |||
| 464115320f | |||
| a1afe18af5 | |||
| bcdbbb4f24 | |||
| b2be58e5da | |||
| 1a738553b4 | |||
| 71a046eb0a | |||
| c733611568 | |||
| a6294cb701 | |||
| 7862d9965b | |||
| 2620d036ab | |||
| eed779c7e9 | |||
| dd53b3533c | |||
| 005e0a6730 | |||
| af3d62e9b5 | |||
| df5166e82d | |||
| 36978a49e8 | |||
| 06a7a5099a | |||
| e7438db1de | |||
| d14f6c1347 | |||
| ebe3c742cc | |||
| ee9ea07249 | |||
| ce422b042e | |||
| ce11407d96 | |||
| 1c2c952e2a | |||
| 48804fff88 | |||
| 00077cdd4d | |||
| c7ae9c6eeb | |||
| 25706255a3 | |||
| 83a616b02c | |||
| 9191438acf | |||
| 86f37ce7c1 | |||
| d244e8e0cb | |||
| 2aa8d18531 | |||
| d25f656a48 | |||
| 8227656cb0 | |||
| 086e2b3d2b | |||
| 7d63246f6b | |||
| 8c5e83cf34 | |||
| bf15ee8a6d | |||
| 1c90e77100 | |||
| 62319b4d1c | |||
| 0c7490a25d | |||
| b80c25224c | |||
| 1690b17cb4 | |||
| fc0cf54962 | |||
| 650b0f71b1 | |||
| b67c026a16 | |||
| ccb4a8a2bb | |||
| 1a150a334a | |||
| c340c6914f | |||
| 77167c0d39 | |||
| 1ca26dffbf | |||
| 56978cfc90 | |||
| 874b7f5d2a | |||
| 79f6cf8995 | |||
| c3ac7c0412 | |||
| b8773f1166 | |||
| 9c7287c64f | |||
| b2d37a048f | |||
| 9cf6869c5d | |||
| 34fb3af7d3 | |||
| 7e6493ef7b | |||
| 92c5b852c1 | |||
| c8c4904199 | |||
| c0bf3ce1b5 | |||
| 85ed196cf4 | |||
| 1075f57db4 | |||
| c50a836cd3 | |||
| 8281d5c33b | |||
| 171918e41a |
@@ -1,7 +0,0 @@
|
||||
dist
|
||||
target
|
||||
build.properties
|
||||
*.log
|
||||
.clover
|
||||
*.keystore
|
||||
server-work
|
||||
@@ -0,0 +1,8 @@
|
||||
#*
|
||||
.#*
|
||||
*~
|
||||
_site
|
||||
.idea
|
||||
*.sw[op]
|
||||
.project
|
||||
sample-pages
|
||||
@@ -0,0 +1 @@
|
||||
spring-gh-pages
|
||||
@@ -0,0 +1 @@
|
||||
ruby-2.2.0
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (4.2.6)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.4.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
colorator (0.1)
|
||||
ethon (0.9.0)
|
||||
ffi (>= 1.3.0)
|
||||
execjs (2.7.0)
|
||||
faraday (0.9.2)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.9.13)
|
||||
gemoji (2.1.0)
|
||||
github-pages (86)
|
||||
github-pages-health-check (= 1.1.0)
|
||||
jekyll (= 3.1.6)
|
||||
jekyll-coffeescript (= 1.0.1)
|
||||
jekyll-feed (= 0.5.1)
|
||||
jekyll-gist (= 1.4.0)
|
||||
jekyll-github-metadata (= 2.0.2)
|
||||
jekyll-mentions (= 1.1.3)
|
||||
jekyll-paginate (= 1.1.0)
|
||||
jekyll-redirect-from (= 0.10.0)
|
||||
jekyll-sass-converter (= 1.3.0)
|
||||
jekyll-seo-tag (= 2.0.0)
|
||||
jekyll-sitemap (= 0.10.0)
|
||||
jemoji (= 0.6.2)
|
||||
kramdown (= 1.11.1)
|
||||
liquid (= 3.0.6)
|
||||
listen (= 3.0.6)
|
||||
mercenary (~> 0.3)
|
||||
rouge (= 1.11.1)
|
||||
terminal-table (~> 1.4)
|
||||
github-pages-health-check (1.1.0)
|
||||
addressable (~> 2.3)
|
||||
net-dns (~> 0.8)
|
||||
octokit (~> 4.0)
|
||||
public_suffix (~> 1.4)
|
||||
typhoeus (~> 0.7)
|
||||
html-pipeline (2.4.1)
|
||||
activesupport (>= 2, < 5)
|
||||
nokogiri (>= 1.4)
|
||||
i18n (0.7.0)
|
||||
jekyll (3.1.6)
|
||||
colorator (~> 0.1)
|
||||
jekyll-sass-converter (~> 1.0)
|
||||
jekyll-watch (~> 1.1)
|
||||
kramdown (~> 1.3)
|
||||
liquid (~> 3.0)
|
||||
mercenary (~> 0.3.3)
|
||||
rouge (~> 1.7)
|
||||
safe_yaml (~> 1.0)
|
||||
jekyll-coffeescript (1.0.1)
|
||||
coffee-script (~> 2.2)
|
||||
jekyll-feed (0.5.1)
|
||||
jekyll-gist (1.4.0)
|
||||
octokit (~> 4.2)
|
||||
jekyll-github-metadata (2.0.2)
|
||||
jekyll (~> 3.1)
|
||||
octokit (~> 4.0)
|
||||
jekyll-mentions (1.1.3)
|
||||
html-pipeline (~> 2.3)
|
||||
jekyll (~> 3.0)
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-redirect-from (0.10.0)
|
||||
jekyll (>= 2.0)
|
||||
jekyll-sass-converter (1.3.0)
|
||||
sass (~> 3.2)
|
||||
jekyll-seo-tag (2.0.0)
|
||||
jekyll (~> 3.1)
|
||||
jekyll-sitemap (0.10.0)
|
||||
jekyll-watch (1.4.0)
|
||||
listen (~> 3.0, < 3.1)
|
||||
jemoji (0.6.2)
|
||||
gemoji (~> 2.0)
|
||||
html-pipeline (~> 2.2)
|
||||
jekyll (>= 3.0)
|
||||
json (1.8.3)
|
||||
kramdown (1.11.1)
|
||||
liquid (3.0.6)
|
||||
listen (3.0.6)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9.7)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.9.0)
|
||||
multipart-post (2.0.0)
|
||||
net-dns (0.8.0)
|
||||
nokogiri (1.6.8)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
pkg-config (~> 1.1.7)
|
||||
octokit (4.3.0)
|
||||
sawyer (~> 0.7.0, >= 0.5.3)
|
||||
pkg-config (1.1.7)
|
||||
public_suffix (1.5.3)
|
||||
rb-fsevent (0.9.7)
|
||||
rb-inotify (0.9.7)
|
||||
ffi (>= 0.5.0)
|
||||
rouge (1.11.1)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.4.22)
|
||||
sawyer (0.7.0)
|
||||
addressable (>= 2.3.5, < 2.5)
|
||||
faraday (~> 0.8, < 0.10)
|
||||
terminal-table (1.6.0)
|
||||
thread_safe (0.3.5)
|
||||
typhoeus (0.8.0)
|
||||
ethon (>= 0.8.0)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
github-pages
|
||||
rouge
|
||||
|
||||
BUNDLED WITH
|
||||
1.12.5
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
# Introduction
|
||||
|
||||
Spring's project pages are based on [Jekyll](https://jekyllrb.com) and [GitHub Pages](https://pages.github.com/). This means that each project's website is stored within the project repo, in a special branch called "gh-pages". In order to keep everything looking similar across the many individual Spring projects, common elements of the Jekyll site layout, css, etc are stored in [a shared gh-pages repository](https://github.com/spring-projects/gh-pages). If you're seeing this README in the gh-pages branch of an actual Spring project, that's because this file, along with all the other common files get merged periodically into each project.
|
||||
|
||||
This approach may sound a little funky (and it is), but it's way better than the misery of Git submodules. In fact, it's actually pretty easy. If you're just getting started, then follow the directions immediately below. If you're needing a refresher on how to keep things up to date, then head to the section at the bottom on "keeping up to date".
|
||||
|
||||
> ***Note:*** Github changed their rendering (a lot) in April 2016. If you are seeing pages build failures since that time, then you probably need to merge some changes from this upstream. Follow the instructions below, and for testing locally use rubiy 2.x and don't forget to `bundle exec ...` everything.
|
||||
|
||||
|
||||
|
||||
# How to start a new `gh-pages` project page
|
||||
|
||||
From within your Spring project's git checkout directory:
|
||||
|
||||
### Create and checkout the gh-pages branch
|
||||
|
||||
git checkout --orphan gh-pages
|
||||
|
||||
### Remove all files
|
||||
|
||||
git rm -rf `git ls-files` && rm -rf *
|
||||
|
||||
### Add the gh-pages-upstream remote
|
||||
|
||||
git remote add gh-pages-upstream https://github.com/spring-projects/gh-pages.git
|
||||
|
||||
### Pull in the common site infrastructure
|
||||
|
||||
git pull gh-pages-upstream gh-pages
|
||||
|
||||
|
||||
## Edit `_config.yml`
|
||||
|
||||
You'll need to tweak a few settings in `_config.yml`, sitting in the root directory. Edit this file and follow the instructions within. It should be self explanatory; you'll see that there are lots of instances of "spring-framework" as a project name. You should replace these with your own project's information as appropriate.
|
||||
|
||||
|
||||
## Create the project home page
|
||||
|
||||
### What kind of project are you?
|
||||
|
||||
At this point, you just need to give your project a home page. There are pre-fab samples included in the `_sample-pages` directory:
|
||||
|
||||
$ ls -1 _sample-pages
|
||||
documentation.md
|
||||
project_group.html
|
||||
project.html
|
||||
vaniall.md
|
||||
|
||||
At this point you need to make a decision: is your project a "grouping project", like Spring Data, acting as a parent for one or more child projects? If so, you should choose `project_group.html` in the following step. Otherwise, if you're dealing with an individual, concrete Spring project, e.g. Spring Data JPA, or Spring Security OAuth, you should choose `project.html`. The `documentation.md` can be used when you want to expose README.md files on your site.
|
||||
|
||||
### Copy the sample page to `index.html`
|
||||
|
||||
Based on your choice above, copy the correct sample page to `index.html`, e.g.:
|
||||
|
||||
$ cp _sample-pages/project.html index.html
|
||||
|
||||
or
|
||||
|
||||
$ cp _sample-pages/project_group.html index.html
|
||||
|
||||
|
||||
## Edit the content of your home page
|
||||
|
||||
### Edit the YAML front matter
|
||||
|
||||
Open up `index.html` in your favorite text editor. Within, you'll find "YAML front matter" at the top of the file, i.e. everything between the triple dashes that look like `---`. This section contains some basic metadata, and—if you've copied the `project.html` sample—also contains a custom section of information for your project "badges". These are icons that will render in the sidebar of your project page.
|
||||
|
||||
Edit the URLs and other values in the YAML front matter as appropriate. This should be self-explanatory.
|
||||
|
||||
> **Tip**: If a particular "badge" (e.g. Sonar) does not apply to your project, just delete that entry from the YAML.
|
||||
|
||||
### Understand the use of "captures" and "includes"
|
||||
|
||||
Next, you'll see a series of `{% capture variable_name %}` blocks that look like this:
|
||||
|
||||
{% capture billboard_description %}
|
||||
...
|
||||
{% endcapture %}
|
||||
|
||||
At the end of the file you'll see a `{% include %}` directive that looks like this:
|
||||
|
||||
{% include project_page.html %}
|
||||
|
||||
That `include` directive is the most important part. It brings in `project_page.html`, which will actually be responsible for rendering the page content.
|
||||
|
||||
The net effect is that you have one simple place to edit actual page content, and the actual rendering and placement of that content is handled for you by the include.
|
||||
|
||||
Ideally, you shouldn't have to touch any other files besides `_config.yml` and `index.html`, but of course if you need to you always can.
|
||||
|
||||
### Replace the filler text with copy specific to your project
|
||||
|
||||
Of course the next step is simply to change the prose within each `{% capture %}` block to read as you want it to. It's just Markdown, so do as you please with that in mind. Note that you'll want to move on to the next step to view the site locally before you get too far into the editing process; this will allow you view your changes live as you make them.
|
||||
|
||||
|
||||
## View the site locally
|
||||
|
||||
Assuming you're already within your project's clone directory, and you've already checked out the `gh-pages` branch, follow these simple directions to view your site locally:
|
||||
|
||||
### Install jekyll if you have not already
|
||||
|
||||
> **Note:** Jekyll 3.0.4 is a known good version, and it is specifically referred to in `Gemfile.lock` so you have to use `bundle` (not `gem install ...`) to install it:
|
||||
|
||||
gem install bundler
|
||||
bundle
|
||||
|
||||
### Run jekyll
|
||||
|
||||
Use the `--watch` flag to pick up changes to files as you make them, allowing you a nice edit-and-refresh workflow.
|
||||
|
||||
bundle exec jekyll serve --watch
|
||||
|
||||
> **Important:** Because the `baseurl` is set explicitly within your project's `_config.yml` file, you'll need to fully-qualify the URL to view your project. For example, if your project is named "spring-xyz", your URL when running Jekyll locally will be <http://localhost:4000/spring-xyz/>. Don't forget the trailing slash! You'll get a 404 without it.
|
||||
|
||||
|
||||
## Commit your changes
|
||||
|
||||
Once you're satisified with your edits, commit your changes and push the `gh-pages` pages up to your project's `origin` remote.
|
||||
|
||||
git commit -m "Initialize project page"
|
||||
git push --set-upstream origin gh-pages
|
||||
git push
|
||||
|
||||
|
||||
## View your site live on the web
|
||||
|
||||
That's it! After not more than a few minutes, you should be able to see your site at https://spring-projects.github.io/{your-spring-project}
|
||||
|
||||
|
||||
# How to keep common gh-pages content up to date
|
||||
|
||||
Once you've set up your project's gh-pages infrastructure above, you'll get notified whenever
|
||||
changes are made to the shared gh-pages project. Actually, _your project_ will get notified,
|
||||
because a webhook configured on the gh-pages project will fire that ultimately creates a new
|
||||
issue in your project's GH Issues.
|
||||
> Yeah, it would have been nice to do proper pull requests instead of issues, but this arrangement
|
||||
with gh-pages branches and upstreams isn't based on forking. That means pull requests are no can do.
|
||||
This also means that if your project doesn't have issues turned on, you won't get notified! So you
|
||||
might consider doing that if you haven't already.
|
||||
|
||||
In any case, whether or not you get notified via the issue coming in from the webhook, sync'ing
|
||||
up to the latest from the shared gh-pages project is easy enough:
|
||||
|
||||
> This assumes you've got the `gh-pages-upstream` remote set up, per the instructions in sections
|
||||
above.
|
||||
|
||||
git checkout gh-pages
|
||||
git pull --no-ff gh-pages-upstream gh-pages
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
### Global gh-pages pre-amble
|
||||
safe: true
|
||||
lsi: false
|
||||
highlighter: rouge
|
||||
markdown: kramdown
|
||||
encoding: UTF-8
|
||||
github: [metadata]
|
||||
kramdown:
|
||||
input: GFM
|
||||
hard_wrap: false
|
||||
smart_quotes: ["apos", "apos", "quot", "quot"]
|
||||
gems:
|
||||
- jekyll-coffeescript
|
||||
- jekyll-paginate
|
||||
|
||||
### The following properties will change on a project-by-project basis
|
||||
|
||||
# Context path in the remote website (usually /<project>), will be prepended to absolute URLs for static resources
|
||||
baseurl: /spring-security
|
||||
|
||||
# Name of the project for display in places like page titles
|
||||
name: Spring Security
|
||||
|
||||
# ID of the project in the metadata API at spring.io (if this is not a
|
||||
# valid project ID the javascript widgets in the home page will not work)
|
||||
project: spring-security
|
||||
|
||||
# Project github URL
|
||||
github_repo_url: https://github.com/spring-projects/spring-security
|
||||
|
||||
## Custom properties
|
||||
guides_base_url: https://docs.spring.io/spring-security/site/docs/current/guides/html5/
|
||||
|
||||
# If you want to include a custom pom.xml or gradle template set these value to true and add _include files
|
||||
custom_pom_template: false
|
||||
custom_gradle_template: false
|
||||
|
||||
# If you want to include a custom pom.xml or gradle template set these value to true and add _include files
|
||||
custom_pom_template: false
|
||||
custom_gradle_template: false
|
||||
|
||||
|
||||
### The following properties are constant for most projects
|
||||
|
||||
main_site_url: https://spring.io
|
||||
projects_site_url: https://projects.spring.io
|
||||
questions_url: https://spring.io/questions
|
||||
@@ -0,0 +1,16 @@
|
||||
{% if page.badges.twitter %}
|
||||
<div class="project-sub-link">
|
||||
<a href="https://twitter.com/{{ page.badges.twitter }}">
|
||||
<div class="spring-icon project-badges twitter" title="Twitter">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% for badge in page.badges.custom %}
|
||||
<div class="project-sub-link">
|
||||
<a href="{{ badge.url }}">
|
||||
<div class="spring-icon project-badges {{ badge.icon }}" title="{{ badge.name }}">
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,38 @@
|
||||
<div class="billboard--wrapper project-header--wrapper">
|
||||
<div class="billboard--container">
|
||||
<div class="project-icon">
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="span8 billboard--area">
|
||||
<div class="content--title">
|
||||
{% capture breadcrumb %}
|
||||
[Projects]({{ site.projects_site_url }}){% if parent_link %} : {{ parent_link }}{% endif %}
|
||||
{% endcapture %}
|
||||
{{ breadcrumb | markdownify }}
|
||||
</div>
|
||||
|
||||
<div class="project--title">{{ site.name }}
|
||||
<div class="project--links--container">
|
||||
<a href="{{ site.github_repo_url }}" class="project-link">
|
||||
<i class="icon-github"></i>
|
||||
</a>
|
||||
{% if site.forum %}
|
||||
<a href="{{ site.forum }}" class="project-link project-link-forum">
|
||||
<div class="spring-icon spring-icon-forum">
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project--description">
|
||||
{{ billboard_description | markdownify }}
|
||||
</div>
|
||||
|
||||
{{ billboard_quickstart_button }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compile '{@= groupId @}:spring-security-web:{@= version @}'
|
||||
compile '{@= groupId @}:spring-security-config:{@= version @}'
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<div class="js-documentation-widget">
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<div id="download-widget">
|
||||
<div class="row-fluid download-widget--container">
|
||||
<div class="download-widget--header js-item-dropdown-widget--wrapper">
|
||||
<div class="download-widget--title">
|
||||
Download
|
||||
</div>
|
||||
<div data-download-widget-controls style="display: inline-block"></div>
|
||||
</div>
|
||||
<div class="download-widget--body">
|
||||
<p>The recommended way to get started using <code>{{ site.project }}</code> in
|
||||
your project is with a dependency management system – the snippet below can
|
||||
be copied and pasted into your build. Need help? See our getting started guides
|
||||
on building with <a href="https://spring.io/guides/gs/maven/">Maven</a> and
|
||||
<a href="https://spring.io/guides/gs/gradle/">Gradle</a>.
|
||||
</p>
|
||||
<div class="js-download-maven-widget"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,128 @@
|
||||
<head>
|
||||
<title>{{ site.name }}</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="{{site.baseurl}}/favicon.png" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/bootstrap/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Varela+Round|Montserrat:400,700" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/font-awesome/css/font-awesome.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/bootstrap/css/bootstrap-select.css" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/main.css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/typography.css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/icons.css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/projects.css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/buttons.css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/guide.css.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/highlight.css.css" />
|
||||
|
||||
{{ head_links }}
|
||||
|
||||
<script src="{{site.baseurl}}/js/jquery.js"></script>
|
||||
<script src="{{site.baseurl}}/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="{{site.baseurl}}/bootstrap/js/bootstrap-select.js"></script>
|
||||
|
||||
<script src="{{site.baseurl}}/js/underscore.js"></script>
|
||||
<script src="{{site.baseurl}}/js/backbone.js"></script>
|
||||
<script src="{{site.baseurl}}/js/projectDocumentationWidget.js"></script>
|
||||
<script src="{{site.baseurl}}/js/application.js"></script>
|
||||
<script src="{{site.baseurl}}/js/clipboard.min.js"></script>
|
||||
<script>
|
||||
var apiBaseUrl = "{{ site.main_site_url }}",
|
||||
projectId = "{{ site.project }}",
|
||||
siteBaseUrl = "{{ site.baseurl }}";
|
||||
</script>
|
||||
<script src="{{site.baseurl}}/js/copySnippets.js"></script>
|
||||
<meta name="google-site-verification" content="7qGntFPD9lWAVCtUu5U77v4l68PsTHf6xpzgjQv2j2M" />
|
||||
<script>
|
||||
var _gaq = _gaq || [];
|
||||
var pluginUrl = '//www.google-analytics.com/plugins/ga/inpage_linkid.js';
|
||||
_gaq.push(
|
||||
['_require', 'inpage_linkid', pluginUrl],
|
||||
['_setAccount', 'UA-2728886-22'],
|
||||
['_trackPageview'],
|
||||
['b._require', 'inpage_linkid', pluginUrl],
|
||||
['b._setAccount', 'UA-2728886-19'],
|
||||
['b._trackPageview']
|
||||
);
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
{{ head }}
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header class="navbar header--navbar">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<div class="spring-logo--container">
|
||||
<a class="spring-logo" href="{{site.main_site_url}}"><span></span></a>
|
||||
</div>
|
||||
<ul class="nav pull-right">
|
||||
<li class="navbar-link"><a href="{{site.main_site_url}}/docs">Docs</a>
|
||||
</li>
|
||||
<li class="navbar-link"><a
|
||||
href="{{site.main_site_url}}/guides">Guides</a></li>
|
||||
<li class="navbar-link active"><a
|
||||
href="{{site.main_site_url}}/projects">Projects</a></li>
|
||||
<li class="navbar-link"><a href="{{site.main_site_url}}/blog">Blog</a>
|
||||
</li>
|
||||
<li class="navbar-link"><a href="{{site.questions_url}}">Questions</a>
|
||||
</li>
|
||||
<li class="navbar-link nav-search"><i
|
||||
class="icon-search navbar-search--icon js-search-input-open"></i>
|
||||
<div class="search-input-close js-search-input-close">x</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-dropdown--container js-search-dropdown">
|
||||
<div class="container-fluid">
|
||||
<div class="search-form--container">
|
||||
<form class="form-inline form-search"
|
||||
action="{{site.main_site_url}}/search">
|
||||
<input type="search"
|
||||
class="search-query search-form--form js-search-input"
|
||||
placeholder="Search for documention, guides, and posts..."
|
||||
name="q" />
|
||||
<button class="search-form--submit">
|
||||
<i class="icon-search"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="body--container">{{ content }}</div>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="navbar">
|
||||
<div class="container">
|
||||
<ul class="nav">
|
||||
<li><a href="{{site.main_site_url}}/team">Team</a></li>
|
||||
<li><a href="{{site.main_site_url}}/services">Services</a></li>
|
||||
<li><a href="{{site.main_site_url}}/tools">Tools</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
© <script> var d = new Date();
|
||||
document.write(d.getFullYear());</script> <a href="https://www.pivotal.io">Pivotal Software</a>, Inc. All Rights Reserved.
|
||||
<a href="https://pivotal.io/terms-of-use">Terms of Use</a> and
|
||||
<a href="https://pivotal.io/privacy-policy">Privacy</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<div id="scrim"></div>
|
||||
|
||||
{{ end_content }}
|
||||
|
||||
</body>
|
||||
@@ -0,0 +1,24 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>{@= groupId @}</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>{@= version @}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>{@= groupId @}</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>{@= version @}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
{@ if (repository) { @}
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>{@= repository.id @}</id>
|
||||
<name>{@= repository.name @}</name>
|
||||
<url>{@= repository.url @}</url>
|
||||
<snapshots>
|
||||
<enabled>{@= repository.snapshotsEnabled @}</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>{@ } @}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="project--container">
|
||||
<a href="{{include.site_url}}">
|
||||
<div class="project--title">{{include.project_title}}</div>
|
||||
<p class="project--description">{{include.project_description}}</p>
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
{% capture content %}
|
||||
{% include billboard.html %}
|
||||
<div class="project-body--wrapper">
|
||||
<div class="project-body--container">
|
||||
<div class="projects--wrapper project-aggregator">
|
||||
{{ main_content | markdownify }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcapture %}
|
||||
{% include page.html %}
|
||||
@@ -0,0 +1,29 @@
|
||||
{% capture billboard_quickstart_button %}
|
||||
<a class="btn btn-black uppercase project-quickstart-btn" href="#quick-start">Quick Start</a>
|
||||
{% endcapture %}
|
||||
{% capture content %}
|
||||
{% include billboard.html %}
|
||||
<div class="github-fork-ribbon--container">
|
||||
<a href="{{ site.github_repo_url }}"><img style="position: absolute; top: 0; right: 0; border: 0;" src="{{site.baseurl}}/img/forkme.png" alt="Fork me on GitHub"></a>
|
||||
</div>
|
||||
<div class="project-body--wrapper">
|
||||
<div class="project-body--container">
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<div class="project-body--section">
|
||||
{{ main_content | markdownify }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="span4">
|
||||
{% include project_sidebar.html %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcapture %}
|
||||
{% capture end_content %}
|
||||
{% include widget_templates.html %}
|
||||
{% endcapture %}
|
||||
{% include page.html %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% include documentation.html %}
|
||||
<div class="right-pane-widget--container no-top-border">
|
||||
<div class="project-sub-link--wrapper">
|
||||
{% include badges.html %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-pane-widget--container no-top-border project-sidebar-resource--wrapper">
|
||||
{{ related_resources | markdownify }}
|
||||
</div>
|
||||
@@ -0,0 +1,136 @@
|
||||
<script type="text/html" id="project-documentation-widget-template">
|
||||
<div class="right-pane-widget--container no-top-border project-documentation--container">
|
||||
<div class="item-dropdown-widget">
|
||||
<div class="item-dropdown--title">{@= name @}</div>
|
||||
<div class="item--dropdown">
|
||||
<div class="item--body">
|
||||
<div class="item--body-title">
|
||||
<div class="item--left-column">Release</div>
|
||||
<div class="item--right-column">Documentation</div>
|
||||
</div>
|
||||
{@ _.each(releases, function(release) { @}
|
||||
<div class="item--body--version">
|
||||
<div class="item--left-column">
|
||||
<p>{@= release.versionDisplayName @}</p>
|
||||
{@ if(release.current) { @}
|
||||
<div class="spring-icon spring-icon-current-version"></div>
|
||||
{@ } @}
|
||||
<div class="spring-icon {@= release.statusIconClass() @}"></div>
|
||||
</div>
|
||||
<div class="item--right-column">
|
||||
{@ if (release.refDocUrl !== '') { @}
|
||||
<a href='{@= release.refDocUrl @}' class="docs-link reference-link">Reference</a>
|
||||
{@ }; @}
|
||||
{@ if (release.apiDocUrl !== '') { @}
|
||||
<a href='{@= release.apiDocUrl @}' class="docs-link api-link">API</a>
|
||||
{@ }; @}
|
||||
</div>
|
||||
</div>
|
||||
{@ }); @}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="project-download-widget-controls-template">
|
||||
<div class="js-download-widget-selector">
|
||||
<select class='selector selectpicker'>
|
||||
{@ _.each(releases, function(release, index) { @}
|
||||
<option value="{@= index @}"
|
||||
data-content="
|
||||
<span>{@= release.versionDisplayName @}</span>
|
||||
{@ if(release.current) { @}
|
||||
<div class='spring-icon spring-icon-current-version'></div>
|
||||
{@ } @}
|
||||
<div class='spring-icon {@= release.statusIconClass() @}'/>"
|
||||
data-current="{@= release.current @}">
|
||||
()
|
||||
</option>
|
||||
{@ }); @}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="item-slider-widget js-item-slider--wrapper">
|
||||
<div class="item-slider--container">
|
||||
<div class="item--slider js-item--slider"></div>
|
||||
<div class="item js-active js-item" data-snippet-type='maven'>
|
||||
Maven
|
||||
</div>
|
||||
<div class="item js-item" data-snippet-type='gradle'>
|
||||
Gradle
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
{% if site.custom_pom_template %}
|
||||
{% capture maven_pom_template %}
|
||||
{% include pom.xml %}
|
||||
{% endcapture %}
|
||||
{% else %}
|
||||
{% capture maven_pom_template %}
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>{@= groupId @}</groupId>
|
||||
<artifactId>{@= artifactId @}</artifactId>
|
||||
<version>{@= version @}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
{% endcapture %}
|
||||
{% endif %}
|
||||
|
||||
<script type="text/html" id="project-download-maven-widget-template">
|
||||
{% highlight xml %}
|
||||
{{ maven_pom_template }}
|
||||
{% endhighlight %}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="project-repository-maven-widget-template">
|
||||
{% highlight xml %}
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>{@= repository.id @}</id>
|
||||
<name>{@= repository.name @}</name>
|
||||
<url>{@= repository.url @}</url>
|
||||
<snapshots>
|
||||
<enabled>{@= repository.snapshotsEnabled @}</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
{% endhighlight %}
|
||||
</script>
|
||||
|
||||
{% if site.custom_gradle_template %}
|
||||
{% capture gradle_template %}
|
||||
{% include build.gradle %}
|
||||
{% endcapture %}
|
||||
{% else %}
|
||||
{% capture gradle_template %}
|
||||
dependencies {
|
||||
compile '{@= groupId @}:{@= artifactId @}:{@= version @}'
|
||||
}
|
||||
{% endcapture %}
|
||||
{% endif %}
|
||||
|
||||
<script type="text/html" id="project-download-gradle-widget-template">
|
||||
{% highlight groovy %}
|
||||
{{ gradle_template }}
|
||||
{% endhighlight %}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="project-repository-gradle-widget-template">
|
||||
{% highlight groovy %}
|
||||
repositories {
|
||||
maven {
|
||||
url '{@= repository.url @}'
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="project-download-zip-widget-template">
|
||||
This is a zip url
|
||||
</script>
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
---
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
|
||||
{% capture head_links %}
|
||||
<link rel="stylesheet" type="text/css" href="{{site.baseurl}}/css/documentation.css" />
|
||||
{% endcapture %}
|
||||
|
||||
{% capture content %}
|
||||
<div class="project-body--wrapper" id="quick-start">
|
||||
<div class="project-body--container">
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="project-body--section">
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
|
||||
{% include page.html %}
|
||||
</html>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: documentation_page
|
||||
---
|
||||
|
||||
# My Project ReadMe
|
||||
This would be taken from the project
|
||||
|
||||
|
||||
## Sub Heading
|
||||
Birth, a very small stage in a vast cosmic
|
||||
arena extraordinary claims require extraordinary evidence! Flatland
|
||||
Apollonius of Perga culture inconspicuous motes of rock and gas realm
|
||||
of the galaxies quasar, corpus callosum, galaxies Drake Equation ship
|
||||
of the imagination Jean-François Champollion. Galaxies Hypatia!
|
||||
Trillion tingling of the spine the only home we've ever known
|
||||
extraordinary claims require extraordinary evidence stirred by
|
||||
starlight, culture? Flatland Tunguska event finite but unbounded
|
||||
corpus callosum!
|
||||
|
||||
Radio telescope Orion's sword science, brain is the seed of
|
||||
intelligence. Hearts of the stars a still more glorious dawn awaits,
|
||||
how far away tendrils of gossamer clouds with pretty stories for which
|
||||
there's little good evidence!
|
||||
|
||||
Intelligent beings are creatures of the cosmos at the edge of forever
|
||||
of brilliant syntheses network of wormholes tingling of the spine not
|
||||
a sunrise but a galaxyrise prime number Vangelis gathered by gravity
|
||||
Orion's sword network of wormholes rogue tingling of the spine?
|
||||
|
||||
```java
|
||||
public static void main() {
|
||||
// long long long long long long long long long long long long long long long long long long long long long long long
|
||||
}
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
* Implementation of CRUD methods for JPA Entities
|
||||
* Dynamic query generation from query method names
|
||||
* Transparent triggering of JPA NamedQueries by query methods
|
||||
* Implementation domain base classes providing basic properties
|
||||
* Support for transparent auditing (created, last changed)
|
||||
* Possibility to integrate custom repository code
|
||||
* Easy Spring integration with custom namespace
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
# The name of your project
|
||||
title: Spring Data JPA
|
||||
|
||||
badges:
|
||||
|
||||
# Specify your project's twitter handle, if any. Delete if none.
|
||||
twitter: SpringData
|
||||
|
||||
# Customize your project's badges. Delete any entries that do not apply.
|
||||
custom:
|
||||
- name: Source (GitHub)
|
||||
url: https://github.com/spring-projects/spring-data-jpa
|
||||
icon: github
|
||||
|
||||
- name: Issues (JIRA)
|
||||
url: https://jira.springsource.org/browse/DATAJPA
|
||||
icon: tracking
|
||||
|
||||
- name: CI (Bamboo)
|
||||
url: https://build.springsource.org/browse/SPRINGDATAJPA
|
||||
icon: ci
|
||||
|
||||
- name: Forum
|
||||
url: https://forum.spring.io/forum/spring-projects/data
|
||||
icon: forum
|
||||
|
||||
- name: StackOverflow
|
||||
url: https://stackoverflow.com/questions/tagged/spring-data-jpa
|
||||
icon: stackoverflow
|
||||
|
||||
- name: Metrics (SonarQube)
|
||||
url: https://sonar.springsource.org/dashboard/index/org.springframework.data:spring-data-jpa
|
||||
icon: metrics
|
||||
|
||||
---
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
|
||||
<!-- Specify the parent of this project (or delete if none) to influence the rendering of the breadcrumb -->
|
||||
{% capture parent_link %}
|
||||
[Spring Parent]({{ site.projects_site_url }}/spring-parent)
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture billboard_description %}
|
||||
|
||||
**PROJECT DESCRIPTION** Corpus callosum,
|
||||
[the carbon](#) in our apple pies a mote of dust suspended in a
|
||||
sunbeam. Muse about! Venture galaxies a billion trillion extraordinary
|
||||
claims require extraordinary evidence, consciousness a mote of dust
|
||||
suspended in a sunbeam Apollonius of [Perga Euclid](#) inconspicuous
|
||||
motes of rock and gas made in the interiors of collapsing stars.
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture main_content %}
|
||||
|
||||
**INTRODUCTORY PARAGRAPHS** Birth, a very small stage in a vast cosmic
|
||||
arena extraordinary claims require extraordinary evidence! Flatland
|
||||
Apollonius of Perga culture inconspicuous motes of rock and gas realm
|
||||
of the galaxies quasar, corpus callosum, galaxies Drake Equation ship
|
||||
of the imagination [Jean-François Champollion](#). Galaxies Hypatia!
|
||||
Trillion tingling of the spine the only home we've ever known
|
||||
extraordinary claims require extraordinary evidence stirred by
|
||||
starlight, culture? Flatland Tunguska event finite but unbounded
|
||||
corpus callosum!
|
||||
|
||||
## Features
|
||||
|
||||
* Feature 1
|
||||
* [Feature 2](#)
|
||||
* Feature 3
|
||||
* Feature 4
|
||||
* ...
|
||||
|
||||
<span id="quick-start"></span>
|
||||
|
||||
## Quick Start
|
||||
|
||||
{% include download_widget.md %}
|
||||
|
||||
|
||||
```java
|
||||
package foo;
|
||||
|
||||
import foo;
|
||||
|
||||
public class SearchController {
|
||||
|
||||
@Foo
|
||||
public SearchController(SearchService searchService) {
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// This is just a test to see how a very long line works with our project css
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture related_resources %}
|
||||
|
||||
### Sample Projects
|
||||
|
||||
* [Project Name 1](#)
|
||||
* [Project name 2](#)
|
||||
* [Project name nth](#)
|
||||
|
||||
### Getting Started Guides
|
||||
|
||||
* [GSG 1]({{site.main_site_url}}/guides/gs/rest-service)
|
||||
* [GSG 2]({{site.main_site_url}}/guides/gs/other-guide-2)
|
||||
* [GSG n]({{site.main_site_url}}/guides/gs/other-guide-3)
|
||||
|
||||
### Tutorials
|
||||
|
||||
* [Tutorial 1]({{site.main_site_url}}/guides/tutorials/rest)
|
||||
* [Tutorial 2]({{site.main_site_url}}/guides/tutorials/other-2)
|
||||
* [Tutorial n]({{site.main_site_url}}/guides/tutorials/other-3)
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% include project_page.html %}
|
||||
</html>
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
---
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
{% capture billboard_description %}
|
||||
Spring Data makes it easier to build Spring-powered applications that use new data access
|
||||
technologies such as non-relational databases, map-reduce frameworks, and cloud based data services
|
||||
as well as provide improved support for relational database technologies.
|
||||
Spring Data is an umbrella open source project which contains many subprojects that are specific
|
||||
to a given database. The projects are developed by working together with many of the companies
|
||||
and developers that are behind these exciting technologies.
|
||||
{% endcapture %}
|
||||
|
||||
{% capture main_content %}
|
||||
|
||||
{% capture project_description %}
|
||||
Hearts of the stars brain is the seed of intelligence consciousness extraplanetary shores of the cosmic ocean! As a patch of light paroxysm of global death? Inconspicuous motes of rock and gas.
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/sprinframework" project_title="Spring Framework" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
This is Apache Hadoop Hadoop!
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/spring_hadoop" project_title="Apache Hadoop" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
Hearts of the stars brain is the seed of intelligence consciousness extraplanetary shores of the cosmic ocean! As a patch of light paroxysm of global death? Inconspicuous motes of rock and gas.
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/sprinframework" project_title="Spring Framework" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
This is Apache Hadoop Hadoop!
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/spring_hadoop" project_title="Apache Hadoop" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
Hearts of the stars brain is the seed of intelligence consciousness extraplanetary shores of the cosmic ocean! As a patch of light paroxysm of global death? Inconspicuous motes of rock and gas.
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/sprinframework" project_title="Spring Framework" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
This is Apache Hadoop Hadoop!
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/spring_hadoop" project_title="Apache Hadoop" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
Hearts of the stars brain is the seed of intelligence consciousness extraplanetary shores of the cosmic ocean! As a patch of light paroxysm of global death? Inconspicuous motes of rock and gas.
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/sprinframework" project_title="Spring Framework" project_description=project_description %}
|
||||
|
||||
{% capture project_description %}
|
||||
This is Apache Hadoop Hadoop!
|
||||
{% endcapture %}
|
||||
{% include project_block.md site_url="https://www.spring.io" repo_url="https://github.com/spring_hadoop" project_title="Apache Hadoop" project_description=project_description %}
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% include project_group_page.html %}
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
layout: default
|
||||
title: Page Title Here
|
||||
---
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
**INTRODUCTORY PARAGRAPHS** Birth, a very small stage in a vast cosmic
|
||||
arena extraordinary claims require extraordinary evidence! Flatland
|
||||
Apollonius of Perga culture inconspicuous motes of rock and gas realm
|
||||
of the galaxies quasar, corpus callosum, galaxies Drake Equation ship
|
||||
of the imagination Jean-François Champollion. Galaxies Hypatia!
|
||||
Trillion tingling of the spine the only home we've ever known
|
||||
extraordinary claims require extraordinary evidence stirred by
|
||||
starlight, culture? Flatland Tunguska event finite but unbounded
|
||||
corpus callosum!
|
||||
|
||||
Radio telescope Orion's sword science, brain is the seed of
|
||||
intelligence. Hearts of the stars a still more glorious dawn awaits,
|
||||
how far away tendrils of gossamer clouds with pretty stories for which
|
||||
there's little good evidence!
|
||||
|
||||
Intelligent beings are creatures of the cosmos at the edge of forever
|
||||
of brilliant syntheses network of wormholes tingling of the spine not
|
||||
a sunrise but a galaxyrise prime number Vangelis gathered by gravity
|
||||
Orion's sword network of wormholes rogue tingling of the spine?
|
||||
|
||||
## Features
|
||||
|
||||
* Implementation of CRUD methods for JPA Entities
|
||||
* Dynamic query generation from query method names
|
||||
* Transparent triggering of JPA NamedQueries by query methods
|
||||
* Implementation domain base classes providing basic properties
|
||||
* Support for transparent auditing (created, last changed)
|
||||
* Possibility to integrate custom repository code
|
||||
* Easy Spring integration with custom namespace
|
||||
</html>
|
||||
@@ -1,205 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2001-2004 The Apache Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
Checkstyle is very configurable. Be sure to read the documentation at
|
||||
http://checkstyle.sf.net (or in your downloaded distribution).
|
||||
|
||||
Most Checks are configurable, be sure to consult the documentation.
|
||||
|
||||
To completely disable a check, just comment it out or delete it from the file.
|
||||
|
||||
Finally, it is worth reading the documentation.
|
||||
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<!-- Checks that a package.html file exists for each package. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html#PackageHtml -->
|
||||
<!-- module name="PackageHtml"/ -->
|
||||
|
||||
<!-- Checks whether files end with a new line. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
|
||||
<!-- Checks that property files contain the same keys. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
|
||||
<module name="Translation"/>
|
||||
|
||||
|
||||
<module name="TreeWalker">
|
||||
|
||||
<property name="cacheFile" value="${checkstyle.cache.file}"/>
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<!--
|
||||
<module name="JavadocMethod"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="JavadocVariable"/>
|
||||
<module name="JavadocStyle"/>
|
||||
-->
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<module name="ConstantName">
|
||||
<!-- logger variables break normal constant syntax. We need to allow lower case too -->
|
||||
<property name="format" value="^[a-zA-Z][a-zA-Z0-9]*(_[A-Z0-9]+)*$"/>
|
||||
</module>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
<module name="MethodName"/>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName"/>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName"/>
|
||||
|
||||
|
||||
<!-- Checks for Headers -->
|
||||
<!-- See http://checkstyle.sf.net/config_header.html -->
|
||||
<!-- <module name="Header"> -->
|
||||
<!-- The follow property value demonstrates the ability -->
|
||||
<!-- to have access to ANT properties. In this case it uses -->
|
||||
<!-- the ${basedir} property to allow Checkstyle to be run -->
|
||||
<!-- from any directory within a project. See property -->
|
||||
<!-- expansion, -->
|
||||
<!-- http://checkstyle.sf.net/config.html#properties -->
|
||||
<!-- <property -->
|
||||
<!-- name="headerFile" -->
|
||||
<!-- value="${basedir}/java.header"/> -->
|
||||
<!-- </module> -->
|
||||
|
||||
<!-- Following interprets the header file as regular expressions. -->
|
||||
<!-- <module name="RegexpHeader"/> -->
|
||||
|
||||
|
||||
<!-- Checks for imports -->
|
||||
<!-- See http://checkstyle.sf.net/config_imports.html -->
|
||||
<module name="AvoidStarImport">
|
||||
<property name="excludes" value="javax.servlet,java.util"/>
|
||||
</module>
|
||||
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
|
||||
<module name="RedundantImport"/>
|
||||
<!--module name="UnusedImports"/ -->
|
||||
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<module name="FileLength"/>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="125"/>
|
||||
</module>
|
||||
<module name="MethodLength"/>
|
||||
<module name="ParameterNumber"/>
|
||||
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="TabCharacter"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<!--
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
|
||||
<!-- Modifier Checks -->
|
||||
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="RedundantModifier"/>
|
||||
|
||||
|
||||
<!-- Checks for blocks. You know, those {}'s -->
|
||||
<!-- See http://checkstyle.sf.net/config_blocks.html -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<!-- module name="EmptyBlock"/ -->
|
||||
<module name="LeftCurly"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="RightCurly"/>
|
||||
|
||||
|
||||
<!-- Checks for common coding problems -->
|
||||
<!-- See http://checkstyle.sf.net/config_coding.html -->
|
||||
<!-- module name="AvoidInlineConditionals"/ -->
|
||||
<module name="DoubleCheckedLocking"/> <!-- MY FAVOURITE -->
|
||||
<module name="EmptyStatement"/>
|
||||
<!-- module name="EqualsHashCode"/ -->
|
||||
<!--
|
||||
<module name="HiddenField">
|
||||
<property name="ignoreConstructorParameter" value="true"/>
|
||||
<property name="ignoreSetter" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<!-- module name="MagicNumber"/ -->
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<!--
|
||||
<module name="RedundantThrows">
|
||||
<property name="allowUnchecked" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
<!--
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
-->
|
||||
<!-- Checks for class design -->
|
||||
<!-- See http://checkstyle.sf.net/config_design.html -->
|
||||
<!-- module name="DesignForExtension"/ -->
|
||||
<module name="FinalClass"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
<module name="InterfaceIsType"/>
|
||||
<module name="VisibilityModifier">
|
||||
<!-- logger variables are often protected -->
|
||||
<property name="protectedAllowed" value="true"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<!-- module name="FinalParameters"/ -->
|
||||
<!--
|
||||
<module name="GenericIllegalRegexp">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
-->
|
||||
<!-- module name="TrailingComment"/ -->
|
||||
<!-- module name="TodoComment"/ -->
|
||||
<module name="UpperEll"/>
|
||||
|
||||
</module>
|
||||
|
||||
</module>
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
<?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>2.0.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<name>Spring Security - ACL module</name>
|
||||
<version>2.0.2</version>
|
||||
<packaging>bundle</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-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-mock</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>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.osgi.export>
|
||||
org.springframework.security.*;version=${pom.version.osgi}
|
||||
</spring.osgi.export>
|
||||
|
||||
<spring.osgi.import>
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
|
||||
org.springframework.context.*;version="${spring.version.osgi}",
|
||||
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="${spring.version.osgi}";resolution:=optional,
|
||||
org.springframework.util.*;version="${spring.version.osgi}",
|
||||
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
|
||||
javax.sql.*
|
||||
</spring.osgi.import>
|
||||
|
||||
<spring.osgi.private.pkg>
|
||||
!org.springframework.security.*
|
||||
</spring.osgi.private.pkg>
|
||||
|
||||
<spring.osgi.symbolic.name>org.springframework.security.acls</spring.osgi.symbolic.name>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -1,57 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an individual permission assignment within an {@link Acl}.
|
||||
*
|
||||
* <p>
|
||||
* Instances MUST be immutable, as they are returned by <code>Acl</code>
|
||||
* and should not allow client modification.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface AccessControlEntry extends Serializable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
Acl getAcl();
|
||||
|
||||
/**
|
||||
* Obtains an identifier that represents this ACE.
|
||||
*
|
||||
* @return the identifier, or <code>null</code> if unsaved
|
||||
*/
|
||||
Serializable getId();
|
||||
|
||||
Permission getPermission();
|
||||
|
||||
Sid getSid();
|
||||
|
||||
/**
|
||||
* Indicates the a Permission is being granted to the relevant Sid. If false, indicates the permission is
|
||||
* being revoked/blocked.
|
||||
*
|
||||
* @return true if being granted, false otherwise
|
||||
*/
|
||||
boolean isGranting();
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an access control list (ACL) for a domain object.
|
||||
*
|
||||
* <p>
|
||||
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In
|
||||
* order to avoid needing references to the domain object itself, this
|
||||
* interface handles indirection between a domain object and an ACL object
|
||||
* identity via the {@link
|
||||
* org.springframework.security.acls.objectidentity.ObjectIdentity} interface.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Implementing classes may elect to return instances that represent
|
||||
* {@link org.springframework.security.acls.Permission} information for either
|
||||
* some OR all {@link org.springframework.security.acls.sid.Sid}
|
||||
* instances. Therefore, an instance may NOT necessarily contain ALL <tt>Sid</tt>s
|
||||
* for a given domain object.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Acl extends Serializable {
|
||||
|
||||
/**
|
||||
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries associated with
|
||||
* the <tt>Acl</tt> parents are not returned.
|
||||
*
|
||||
* <p>This method is typically used for administrative purposes.</p>
|
||||
*
|
||||
* <p>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
|
||||
* part of advanced permission checking.</p>
|
||||
*
|
||||
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
|
||||
* #isGranted(Permission[], Sid[], boolean)}.</p>
|
||||
*
|
||||
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||
* <tt>Sid</tt>s is represented.</p>
|
||||
*
|
||||
* @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if there are
|
||||
* no entries presently associated with this <tt>Acl</tt>.
|
||||
*/
|
||||
AccessControlEntry[] getEntries();
|
||||
|
||||
/**
|
||||
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable once an
|
||||
* <tt>Acl</tt> is created.
|
||||
*
|
||||
* @return the object identity (never <tt>null</tt>)
|
||||
*/
|
||||
ObjectIdentity getObjectIdentity();
|
||||
|
||||
/**
|
||||
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by implementation and is
|
||||
* unspecified.
|
||||
*
|
||||
* @return the owner (may be <tt>null</tt> if the implementation does not use ownership concepts)
|
||||
*/
|
||||
Sid getOwner();
|
||||
|
||||
/**
|
||||
* A domain object may have a parent for the purpose of ACL inheritance. If there is a parent, its ACL can
|
||||
* be accessed via this method. In turn, the parent's parent (grandparent) can be accessed and so on.
|
||||
*
|
||||
* <p>This method solely represents the presence of a navigation hierarchy between the parent <tt>Acl</tt> and this
|
||||
* <tt>Acl</tt>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
|
||||
* <tt>true</tt>.</p>
|
||||
*
|
||||
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||
* <tt>Sid</tt>s is represented.</p>
|
||||
*
|
||||
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not have a parent)
|
||||
*/
|
||||
Acl getParentAcl();
|
||||
|
||||
/**
|
||||
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
|
||||
* <tt>Acl</tt>.<p>The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own
|
||||
* is insufficient to cause ACL entries to inherit down. This is because a domain object 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>
|
||||
*/
|
||||
boolean isEntriesInheriting();
|
||||
|
||||
/**
|
||||
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
|
||||
* required.
|
||||
*
|
||||
* <p>An array of <tt>Sid</tt>s are presented, representing security identifies of the current
|
||||
* principal. In addition, an array of <tt>Permission</tt>s is presented which will have one or more bits set
|
||||
* in order to indicate the permissions needed for an affirmative authorization decision. An array is presented
|
||||
* because holding <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
|
||||
* affirmative authorization.</p>
|
||||
*
|
||||
* <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>
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @throws NotFoundException MUST be thrown if an implementation cannot make an authoritative authorization
|
||||
* decision, usually because there is no ACL information for this particular permission and/or SID
|
||||
* @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for one or more of the
|
||||
* <tt>Sid</tt>s passed as arguments
|
||||
*/
|
||||
boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException;
|
||||
|
||||
/**
|
||||
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain entries for every
|
||||
* <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded and does not represent every
|
||||
* <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only be used within the limited scope of the
|
||||
* <tt>Sid</tt> instances it actually represents.
|
||||
* <p>
|
||||
* It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only authorization
|
||||
* decisions are being made. However, if user interface reporting or modification of <tt>Acl</tt>s are
|
||||
* desired, an <tt>Acl</tt> should be loaded with all <tt>Sid</tt>s. This method denotes whether or
|
||||
* not the specified <tt>Sid</tt>s have been loaded or not.
|
||||
* </p>
|
||||
*
|
||||
* @param sids one or more security identities the caller is interest in knowing whether this <tt>Sid</tt>
|
||||
* supports
|
||||
*
|
||||
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this <tt>Acl</tt> instance
|
||||
*/
|
||||
boolean isSidLoaded(Sid[] sids);
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Utility methods for displaying ACL information.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AclFormattingUtils {
|
||||
|
||||
public static String demergePatterns(String original, String removeBits) {
|
||||
Assert.notNull(original, "Original string required");
|
||||
Assert.notNull(removeBits, "Bits To Remove string required");
|
||||
Assert.isTrue(original.length() == removeBits.length(),
|
||||
"Original and Bits To Remove strings must be identical length");
|
||||
|
||||
char[] replacement = new char[original.length()];
|
||||
|
||||
for (int i = 0; i < original.length(); i++) {
|
||||
if (removeBits.charAt(i) == Permission.RESERVED_OFF) {
|
||||
replacement[i] = original.charAt(i);
|
||||
} else {
|
||||
replacement[i] = Permission.RESERVED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
return new String(replacement);
|
||||
}
|
||||
|
||||
public static String mergePatterns(String original, String extraBits) {
|
||||
Assert.notNull(original, "Original string required");
|
||||
Assert.notNull(extraBits, "Extra Bits string required");
|
||||
Assert.isTrue(original.length() == extraBits.length(),
|
||||
"Original and Extra Bits strings must be identical length");
|
||||
|
||||
char[] replacement = new char[extraBits.length()];
|
||||
|
||||
for (int i = 0; i < extraBits.length(); i++) {
|
||||
if (extraBits.charAt(i) == Permission.RESERVED_OFF) {
|
||||
replacement[i] = original.charAt(i);
|
||||
} else {
|
||||
replacement[i] = extraBits.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return new String(replacement);
|
||||
}
|
||||
|
||||
private static String printBinary(int i, char on, char off) {
|
||||
String s = Integer.toString(i, 2);
|
||||
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
|
||||
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
|
||||
|
||||
return temp2.replace('0', off).replace('1', on);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
|
||||
* character "".<p>Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.</p>
|
||||
*
|
||||
* @param i the integer bit mask to print the active bits for
|
||||
*
|
||||
* @return a 32-character representation of the bit mask
|
||||
*/
|
||||
public static String printBinary(int i) {
|
||||
return printBinary(i, '*', Permission.RESERVED_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
|
||||
* the passed character.
|
||||
* <p>
|
||||
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
||||
*
|
||||
* @param mask the integer bit mask to print the active bits for
|
||||
* @param code the character to print when an active bit is detected
|
||||
*
|
||||
* @return a 32-character representation of the bit mask
|
||||
*/
|
||||
public static String printBinary(int mask, char code) {
|
||||
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_ON),
|
||||
Permission.RESERVED_ON + " is a reserved character code");
|
||||
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_OFF),
|
||||
Permission.RESERVED_OFF + " is a reserved character code");
|
||||
|
||||
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, code);
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Provides retrieval of {@link Acl} instances.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface AclService {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Locates all object identities that use the specified parent. This is useful for administration tools.
|
||||
*
|
||||
* @param parentIdentity to locate children of
|
||||
*
|
||||
* @return the children (or <tt>null</tt> if none were found)
|
||||
*/
|
||||
ObjectIdentity[] findChildren(ObjectIdentity parentIdentity);
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(ObjectIdentity[])} except it returns only a single Acl.<p>This method
|
||||
* should not be called as it does not leverage the underlaying implementation's potential ability to filter
|
||||
* <tt>Acl</tt> entries based on a {@link Sid} parameter.</p>
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(ObjectIdentity[], Sid[])} except it returns only a single Acl.
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object, Sid[] sids)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.<p>The returned map is
|
||||
* keyed on the passed objects, with the values being the <tt>Acl</tt> instances. Any unknown objects will not
|
||||
* have a map key.</p>
|
||||
*
|
||||
* @param objects the objects to find {@link Acl} information for
|
||||
*
|
||||
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
|
||||
*/
|
||||
Map readAclsById(ObjectIdentity[] objects) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only for the
|
||||
* security identifies passed.<p>Implementations <em>MAY</em> provide a subset of the ACLs via this method
|
||||
* although this is NOT a requirement. This is intended to allow performance optimisations within implementations.
|
||||
* Callers should therefore use this method in preference to the alternative overloaded version which does not
|
||||
* have performance optimisation opportunities.</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 sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
*
|
||||
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
|
||||
*/
|
||||
Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
|
||||
throws NotFoundException;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if an <code>Acl</code> entry already exists for the object.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AlreadyExistsException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>AlreadyExistsException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AlreadyExistsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>AlreadyExistsException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public AlreadyExistsException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* Represents an ACE that provides auditing information.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface AuditableAccessControlEntry extends AccessControlEntry {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
boolean isAuditFailure();
|
||||
|
||||
boolean isAuditSuccess();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mutable ACL that provides audit capabilities.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface AuditableAcl extends MutableAcl {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if an {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ChildrenExistException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>ChildrenExistException</code> with the specified
|
||||
* message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public ChildrenExistException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>ChildrenExistException</code> with the specified
|
||||
* message and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public ChildrenExistException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if an ACL identity could not be extracted from an object.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class IdentityUnavailableException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public IdentityUnavailableException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public IdentityUnavailableException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
|
||||
/**
|
||||
* A mutable <tt>Acl</tt>.
|
||||
*
|
||||
* <p>
|
||||
* A mutable ACL must ensure that appropriate security checks are performed
|
||||
* before allowing access to its methods.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface MutableAcl extends Acl {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void deleteAce(int aceIndex) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
|
||||
*
|
||||
* @return the identifier, or <tt>null</tt> if unsaved
|
||||
*/
|
||||
Serializable getId();
|
||||
|
||||
void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Changes the present owner to a different owner.
|
||||
*
|
||||
* @param newOwner the new owner (mandatory; cannot be null)
|
||||
*/
|
||||
void setOwner(Sid newOwner);
|
||||
|
||||
/**
|
||||
* Change the value returned by {@link Acl#isEntriesInheriting()}.
|
||||
*
|
||||
* @param entriesInheriting the new value
|
||||
*/
|
||||
void setEntriesInheriting(boolean entriesInheriting);
|
||||
|
||||
/**
|
||||
* Changes the parent of this ACL.
|
||||
*
|
||||
* @param newParent the new parent
|
||||
*/
|
||||
void setParent(Acl newParent);
|
||||
|
||||
void updateAce(int aceIndex, Permission permission)
|
||||
throws NotFoundException;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
|
||||
|
||||
/**
|
||||
* Provides support for creating and storing <code>Acl</code> instances.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface MutableAclService extends AclService {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Creates an empty <code>Acl</code> object in the database. It will have no entries. The returned object
|
||||
* will then be used to add entries.
|
||||
*
|
||||
* @param objectIdentity the object identity to create
|
||||
*
|
||||
* @return an ACL object with its ID set
|
||||
*
|
||||
* @throws AlreadyExistsException if the passed object identity already has a record
|
||||
*/
|
||||
MutableAcl createAcl(ObjectIdentity objectIdentity)
|
||||
throws AlreadyExistsException;
|
||||
|
||||
/**
|
||||
* Removes the specified entry from the database.
|
||||
*
|
||||
* @param objectIdentity the object identity to remove
|
||||
* @param deleteChildren whether to cascade the delete to children
|
||||
*
|
||||
* @throws ChildrenExistException if the deleteChildren argument was <code>false</code> but children exist
|
||||
*/
|
||||
void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
|
||||
throws ChildrenExistException;
|
||||
|
||||
/**
|
||||
* Changes an existing <code>Acl</code> in the database.
|
||||
*
|
||||
* @param acl to modify
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException if the relevant record could not be found (did you remember to use {@link
|
||||
* #createAcl(ObjectIdentity)} to create the object, rather than creating it with the <code>new</code>
|
||||
* keyword?)
|
||||
*/
|
||||
MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if an ACL-related object cannot be found.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class NotFoundException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public NotFoundException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public NotFoundException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
|
||||
/**
|
||||
* A mutable ACL that provides ownership capabilities.
|
||||
*
|
||||
* <p>
|
||||
* Generally the owner of an ACL is able to call any ACL mutator method, as
|
||||
* well as assign a new owner.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface OwnershipAcl extends MutableAcl {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void setOwner(Sid newOwner);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a permission granted to a {@link org.springframework.security.acls.sid.Sid Sid} for a given domain object.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Permission extends Serializable {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
char RESERVED_ON = '~';
|
||||
char RESERVED_OFF = '.';
|
||||
String THIRTY_TWO_RESERVED_OFF = "................................";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Returns the bits that represents the permission.
|
||||
*
|
||||
* @return the bits that represent the permission
|
||||
*/
|
||||
int getMask();
|
||||
|
||||
/**
|
||||
* Returns a 32-character long bit pattern <code>String</code> representing this permission.
|
||||
* <p>
|
||||
* Implementations are free to format the pattern as they see fit, although under no circumstances may
|
||||
* {@link #RESERVED_OFF} or {@link #RESERVED_ON} be used within the pattern. An exemption is in the case of
|
||||
* {@link #RESERVED_OFF} which is used to denote a bit that is off (clear).
|
||||
* Implementations may also elect to use {@link #RESERVED_ON} internally for computation purposes,
|
||||
* although this method may not return any <code>String</code> containing {@link #RESERVED_ON}.
|
||||
* </p>
|
||||
* <p>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 any permission
|
||||
* calculations. Therefore, duplication of characters within the output is permitted.</p>
|
||||
*
|
||||
* @return a 32-character bit pattern
|
||||
*/
|
||||
String getPattern();
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/* 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;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if an {@link Acl} cannot perform an operation because it only loaded a subset of <code>Sid</code>s and
|
||||
* the caller has requested details for an unloaded <code>Sid</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UnloadedSidException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public UnloadedSidException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public UnloadedSidException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
}
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
/* 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 org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* An immutable default implementation of <code>AccessControlEntry</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Acl acl;
|
||||
private Permission permission;
|
||||
private Serializable id;
|
||||
private Sid sid;
|
||||
private boolean auditFailure = false;
|
||||
private boolean auditSuccess = false;
|
||||
private boolean granting;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
|
||||
boolean auditSuccess, boolean auditFailure) {
|
||||
Assert.notNull(acl, "Acl required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
Assert.notNull(permission, "Permission required");
|
||||
this.id = id;
|
||||
this.acl = acl; // can be null
|
||||
this.sid = sid;
|
||||
this.permission = permission;
|
||||
this.granting = granting;
|
||||
this.auditSuccess = auditSuccess;
|
||||
this.auditFailure = auditFailure;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (!(arg0 instanceof AccessControlEntryImpl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
|
||||
|
||||
if (this.acl == null) {
|
||||
if (rhs.getAcl() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// this.acl is non-null
|
||||
if (rhs.getAcl() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.acl and rhs.acl are non-null, so do a comparison
|
||||
if (this.acl.getObjectIdentity() == null) {
|
||||
if (rhs.acl.getObjectIdentity() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
|
||||
if (!this.acl.getObjectIdentity().equals(rhs.getAcl().getObjectIdentity())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.id == null) {
|
||||
if (rhs.id != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.id and rhs.id are null and thus equal
|
||||
} else {
|
||||
// this.id is non-null
|
||||
if (rhs.id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.id and rhs.id are non-null
|
||||
if (!this.id.equals(rhs.id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.auditFailure != rhs.isAuditFailure()) || (this.auditSuccess != rhs.isAuditSuccess())
|
||||
|| (this.granting != rhs.isGranting())
|
||||
|| !this.permission.equals(rhs.getPermission()) || !this.sid.equals(rhs.getSid())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Acl getAcl() {
|
||||
return acl;
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Permission getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public Sid getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public boolean isAuditFailure() {
|
||||
return auditFailure;
|
||||
}
|
||||
|
||||
public boolean isAuditSuccess() {
|
||||
return auditSuccess;
|
||||
}
|
||||
|
||||
public boolean isGranting() {
|
||||
return granting;
|
||||
}
|
||||
|
||||
void setAuditFailure(boolean auditFailure) {
|
||||
this.auditFailure = auditFailure;
|
||||
}
|
||||
|
||||
void setAuditSuccess(boolean auditSuccess) {
|
||||
this.auditSuccess = auditSuccess;
|
||||
}
|
||||
|
||||
void setPermission(Permission permission) {
|
||||
Assert.notNull(permission, "Permission required");
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("AccessControlEntryImpl[");
|
||||
sb.append("id: ").append(this.id).append("; ");
|
||||
sb.append("granting: ").append(this.granting).append("; ");
|
||||
sb.append("sid: ").append(this.sid).append("; ");
|
||||
sb.append("permission: ").append(this.permission).append("; ");
|
||||
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
|
||||
sb.append("auditFailure: ").append(this.auditFailure);
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/* 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 org.springframework.security.acls.Acl;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
|
||||
* adminstrative methods on the <code>AclImpl</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface AclAuthorizationStrategy {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
int CHANGE_OWNERSHIP = 0;
|
||||
int CHANGE_AUDITING = 1;
|
||||
int CHANGE_GENERAL = 2;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void securityCheck(Acl acl, int changeType);
|
||||
}
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
/* 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 org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.acls.sid.SidRetrievalStrategy;
|
||||
import org.springframework.security.acls.sid.SidRetrievalStrategyImpl;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@link AclAuthorizationStrategy}.<p>Permission will be granted provided the current
|
||||
* principal is either the owner (as defined by the ACL), has {@link BasePermission#ADMINISTRATION} (as defined by the
|
||||
* ACL and via a {@link Sid} retrieved for the current principal via {@link #sidRetrievalStrategy}), or if the current
|
||||
* principal holds the relevant system-wide {@link GrantedAuthority} and injected into the constructor.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private GrantedAuthority gaGeneralChanges;
|
||||
private GrantedAuthority gaModifyAuditing;
|
||||
private GrantedAuthority gaTakeOwnership;
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
|
||||
* can be held to always permit ACL changes.
|
||||
*
|
||||
* @param auths an array of <code>GrantedAuthority</code>s that have
|
||||
* special permissions (index 0 is the authority needed to change
|
||||
* ownership, index 1 is the authority needed to modify auditing details,
|
||||
* index 2 is the authority needed to change other ACL and ACE details) (required)
|
||||
*/
|
||||
public AclAuthorizationStrategyImpl(GrantedAuthority[] auths) {
|
||||
Assert.notEmpty(auths, "GrantedAuthority[] with three elements required");
|
||||
Assert.isTrue(auths.length == 3, "GrantedAuthority[] with three elements required");
|
||||
this.gaTakeOwnership = auths[0];
|
||||
this.gaModifyAuditing = auths[1];
|
||||
this.gaGeneralChanges = auths[2];
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void securityCheck(Acl acl, int changeType) {
|
||||
if ((SecurityContextHolder.getContext() == null)
|
||||
|| (SecurityContextHolder.getContext().getAuthentication() == null)
|
||||
|| !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
|
||||
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
|
||||
}
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
// Check if authorized by virtue of ACL ownership
|
||||
Sid currentUser = new PrincipalSid(authentication);
|
||||
|
||||
if (currentUser.equals(acl.getOwner())
|
||||
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not authorized by ACL ownership; try via adminstrative permissions
|
||||
GrantedAuthority requiredAuthority = null;
|
||||
|
||||
if (changeType == CHANGE_AUDITING) {
|
||||
requiredAuthority = this.gaModifyAuditing;
|
||||
} else if (changeType == CHANGE_GENERAL) {
|
||||
requiredAuthority = this.gaGeneralChanges;
|
||||
} else if (changeType == CHANGE_OWNERSHIP) {
|
||||
requiredAuthority = this.gaTakeOwnership;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown change type");
|
||||
}
|
||||
|
||||
// Iterate this principal's authorities to determine right
|
||||
GrantedAuthority[] auths = authentication.getAuthorities();
|
||||
|
||||
for (int i = 0; i < auths.length; i++) {
|
||||
if (requiredAuthority.equals(auths[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get permission via ACEs within the ACL
|
||||
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
if (acl.isGranted(new Permission[] {BasePermission.ADMINISTRATION}, sids, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new AccessDeniedException(
|
||||
"Principal does not have required ACL permissions to perform requested operation");
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
}
|
||||
@@ -1,411 +0,0 @@
|
||||
/* 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 java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAcl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.OwnershipAcl;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Base implementation of <code>Acl</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id
|
||||
*/
|
||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Acl parentAcl;
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private transient AuditLogger auditLogger;
|
||||
private List aces = new Vector();
|
||||
private ObjectIdentity objectIdentity;
|
||||
private Serializable id;
|
||||
private Sid owner; // OwnershipAcl
|
||||
private Sid[] loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||
private boolean entriesInheriting = true;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Minimal constructor, which should be used {@link
|
||||
* org.springframework.security.acls.MutableAclService#createAcl(ObjectIdentity)}.
|
||||
*
|
||||
* @param objectIdentity the object identity this ACL relates to (required)
|
||||
* @param id the primary key assigned to this ACL (required)
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
* @param auditLogger audit logger (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
AuditLogger auditLogger) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(auditLogger, "AuditLogger required");
|
||||
this.objectIdentity = objectIdentity;
|
||||
this.id = id;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.auditLogger = auditLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor, which should be used by persistence tools that do not
|
||||
* provide field-level access features.
|
||||
*
|
||||
* @param objectIdentity the object identity this ACL relates to (required)
|
||||
* @param id the primary key assigned to this ACL (required)
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
* @param auditLogger audit logger (required)
|
||||
* @param parentAcl the parent (may be <code>null</code>)
|
||||
* @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 owner the owner (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
AuditLogger auditLogger, Acl parentAcl, Sid[] loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(owner, "Owner required");
|
||||
Assert.notNull(auditLogger, "AuditLogger required");
|
||||
this.objectIdentity = objectIdentity;
|
||||
this.id = id;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.auditLogger = auditLogger;
|
||||
this.parentAcl = parentAcl; // may be null
|
||||
this.loadedSids = loadedSids; // may be null
|
||||
this.entriesInheriting = entriesInheriting;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private no-argument constructor for use by reflection-based persistence
|
||||
* tools along with field-level access.
|
||||
*/
|
||||
private AclImpl() {}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private void verifyAceIndexExists(int aceIndex) {
|
||||
if (aceIndex < 0) {
|
||||
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
||||
}
|
||||
if (aceIndex > this.aces.size()) {
|
||||
throw new NotFoundException("aceIndex must correctly refer to an index of the AccessControlEntry collection");
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAce(int aceIndex) throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.remove(aceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public AccessControlEntry[] getEntries() {
|
||||
// Can safely return AccessControlEntry directly, as they're immutable outside the ACL package
|
||||
return (AccessControlEntry[]) aces.toArray(new AccessControlEntry[] {});
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public ObjectIdentity getObjectIdentity() {
|
||||
return objectIdentity;
|
||||
}
|
||||
|
||||
public Sid getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public Acl getParentAcl() {
|
||||
return parentAcl;
|
||||
}
|
||||
|
||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.notNull(permission, "Permission required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (atIndexLocation < 0) {
|
||||
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
|
||||
}
|
||||
if (atIndexLocation > this.aces.size()) {
|
||||
throw new NotFoundException("atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
|
||||
}
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.add(atIndexLocation, ace);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEntriesInheriting() {
|
||||
return entriesInheriting;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 #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
|
||||
*/
|
||||
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
Assert.notEmpty(permission, "Permissions required");
|
||||
Assert.notEmpty(sids, "SIDs required");
|
||||
|
||||
if (!this.isSidLoaded(sids)) {
|
||||
throw new UnloadedSidException("ACL was not loaded for one or more SID");
|
||||
}
|
||||
|
||||
AccessControlEntry firstRejection = null;
|
||||
|
||||
for (int i = 0; i < permission.length; i++) {
|
||||
for (int x = 0; x < sids.length; x++) {
|
||||
// Attempt to find exact match for this permission mask and SID
|
||||
Iterator acesIterator = aces.iterator();
|
||||
boolean scanNextSid = true;
|
||||
|
||||
while (acesIterator.hasNext()) {
|
||||
AccessControlEntry ace = (AccessControlEntry) acesIterator.next();
|
||||
|
||||
if ((ace.getPermission().getMask() == permission[i].getMask()) && ace.getSid().equals(sids[x])) {
|
||||
// Found a matching ACE, so its authorization decision will prevail
|
||||
if (ace.isGranting()) {
|
||||
// Success
|
||||
if (!administrativeMode) {
|
||||
auditLogger.logIfNeeded(true, ace);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// 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 "aceIterator" while 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");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(Sid[] sids) {
|
||||
// If loadedSides is null, this indicates all SIDs were loaded
|
||||
// Also return true if the caller didn't specify a SID to find
|
||||
if ((this.loadedSids == null) || (sids == null) || (sids.length == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This ACL applies to a SID subset only. Iterate to check it applies.
|
||||
for (int i = 0; i < sids.length; i++) {
|
||||
boolean found = false;
|
||||
|
||||
for (int y = 0; y < this.loadedSids.length; y++) {
|
||||
if (sids[i].equals(this.loadedSids[y])) {
|
||||
// this SID is OK
|
||||
found = true;
|
||||
|
||||
break; // out of loadedSids for loop
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setEntriesInheriting(boolean entriesInheriting) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
this.entriesInheriting = entriesInheriting;
|
||||
}
|
||||
|
||||
public void setOwner(Sid newOwner) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.notNull(newOwner, "Owner required");
|
||||
this.owner = newOwner;
|
||||
}
|
||||
|
||||
public void setParent(Acl newParent) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
||||
this.parentAcl = newParent;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("AclImpl[");
|
||||
sb.append("id: ").append(this.id).append("; ");
|
||||
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
||||
sb.append("owner: ").append(this.owner).append("; ");
|
||||
|
||||
Iterator iterator = this.aces.iterator();
|
||||
int count = 0;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
count++;
|
||||
|
||||
if (count == 1) {
|
||||
sb.append("\r\n");
|
||||
}
|
||||
|
||||
sb.append(iterator.next().toString()).append("\r\n");
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
sb.append("no ACEs; ");
|
||||
}
|
||||
|
||||
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
|
||||
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
|
||||
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
|
||||
sb.append("auditLogger: ").append(this.auditLogger);
|
||||
sb.append("]");
|
||||
|
||||
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.length == rhs.loadedSids.length) {
|
||||
for (int i = 0; i < this.loadedSids.length; i++) {
|
||||
if (!this.loadedSids[i].equals(rhs.loadedSids[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* 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 org.springframework.security.acls.AccessControlEntry;
|
||||
|
||||
|
||||
/**
|
||||
* Used by <code>AclImpl</code> to log audit events.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface AuditLogger {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void logIfNeeded(boolean granted, AccessControlEntry ace);
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/* 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 org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* A set of standard permissions.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class BasePermission implements Permission {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
|
||||
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
|
||||
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
|
||||
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
|
||||
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
||||
private static Map locallyDeclaredPermissionsByInteger = new HashMap();
|
||||
private static Map locallyDeclaredPermissionsByName = new HashMap();
|
||||
|
||||
static {
|
||||
Field[] fields = BasePermission.class.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
Object fieldValue = fields[i].get(null);
|
||||
|
||||
if (BasePermission.class.isAssignableFrom(fieldValue.getClass())) {
|
||||
// Found a BasePermission static field
|
||||
BasePermission perm = (BasePermission) fieldValue;
|
||||
locallyDeclaredPermissionsByInteger.put(new Integer(perm.getMask()), perm);
|
||||
locallyDeclaredPermissionsByName.put(fields[i].getName(), perm);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private char code;
|
||||
private int mask;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
private BasePermission(int mask, char code) {
|
||||
this.mask = mask;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
|
||||
* active bits in the passed mask.
|
||||
*
|
||||
* @param mask to build
|
||||
*
|
||||
* @return a Permission representing the requested object
|
||||
*/
|
||||
public static Permission buildFromMask(int mask) {
|
||||
if (locallyDeclaredPermissionsByInteger.containsKey(new Integer(mask))) {
|
||||
// The requested mask has an exactly match against a statically-defined BasePermission, so return it
|
||||
return (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(mask));
|
||||
}
|
||||
|
||||
// To get this far, we have to use a CumulativePermission
|
||||
CumulativePermission permission = new CumulativePermission();
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int permissionToCheck = 1 << i;
|
||||
|
||||
if ((mask & permissionToCheck) == permissionToCheck) {
|
||||
Permission p = (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(permissionToCheck));
|
||||
Assert.state(p != null,
|
||||
"Mask " + permissionToCheck + " does not have a corresponding static BasePermission");
|
||||
permission.set(p);
|
||||
}
|
||||
}
|
||||
|
||||
return permission;
|
||||
}
|
||||
|
||||
public static Permission[] buildFromMask(int[] masks) {
|
||||
if ((masks == null) || (masks.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[masks.length];
|
||||
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
permissions[i] = buildFromMask(masks[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public static Permission buildFromName(String name) {
|
||||
Assert.isTrue(locallyDeclaredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
|
||||
|
||||
return (Permission) locallyDeclaredPermissionsByName.get(name);
|
||||
}
|
||||
|
||||
public static Permission[] buildFromName(String[] names) {
|
||||
if ((names == null) || (names.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[names.length];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
permissions[i] = buildFromName(names[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public int getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return AclFormattingUtils.printBinary(mask, code);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "BasePermission[" + getPattern() + "=" + mask + "]";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/* 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 org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* A bsaic implementation of {@link AuditLogger}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ConsoleAuditLogger implements AuditLogger {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
|
||||
Assert.notNull(ace, "AccessControlEntry required");
|
||||
|
||||
if (ace instanceof AuditableAccessControlEntry) {
|
||||
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
|
||||
|
||||
if (granted && auditableAce.isAuditSuccess()) {
|
||||
System.out.println("GRANTED due to ACE: " + ace);
|
||||
} else if (!granted && auditableAce.isAuditFailure()) {
|
||||
System.out.println("DENIED due to ACE: " + ace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/* 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 org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.<p>Methods return
|
||||
* <code>this</code>, in order to facilitate method chaining.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class CumulativePermission implements Permission {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private String pattern = THIRTY_TWO_RESERVED_OFF;
|
||||
private int mask = 0;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public CumulativePermission clear(Permission permission) {
|
||||
this.mask &= ~permission.getMask();
|
||||
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CumulativePermission clear() {
|
||||
this.mask = 0;
|
||||
this.pattern = THIRTY_TWO_RESERVED_OFF;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof Permission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permission rhs = (Permission) arg0;
|
||||
|
||||
return (this.mask == rhs.getMask());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
public int getMask() {
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public CumulativePermission set(Permission permission) {
|
||||
this.mask |= permission.getMask();
|
||||
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "CumulativePermission[" + pattern + "=" + this.mask + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Basic implementation of access control lists (ACLs) interfaces.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,42 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* A caching layer for {@link JdbcAclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface AclCache {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
void evictFromCache(Serializable pk);
|
||||
|
||||
void evictFromCache(ObjectIdentity objectIdentity);
|
||||
|
||||
MutableAcl getFromCache(ObjectIdentity objectIdentity);
|
||||
|
||||
MutableAcl getFromCache(Serializable pk);
|
||||
|
||||
void putInCache(MutableAcl acl);
|
||||
}
|
||||
@@ -1,542 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Performs lookups in a manner that is compatible with ANSI SQL.<p>NB: This implementation does attempt to provide
|
||||
* reasonably optimised lookups - within the constraints of a normalised database and standard ANSI SQL features. If
|
||||
* you are willing to sacrifice either of these constraints (eg use a particular database feature such as hierarchical
|
||||
* queries or materalized views, or reduce normalisation) you are likely to achieve better performance. In such
|
||||
* situations you will need to provide your own custom <code>LookupStrategy</code>. This class does not support
|
||||
* subclassing, as it is likely to change in future releases and therefore subclassing is unsupported.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class BasicLookupStrategy implements LookupStrategy {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private AclCache aclCache;
|
||||
private AuditLogger auditLogger;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
private int batchSize = 50;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructor accepting mandatory arguments
|
||||
*
|
||||
* @param dataSource to access the database
|
||||
* @param aclCache the cache where fully-loaded elements can be stored
|
||||
* @param aclAuthorizationStrategy authorization strategy (required)
|
||||
*/
|
||||
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
Assert.notNull(aclCache, "AclCache required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(auditLogger, "AuditLogger required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.aclCache = aclCache;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.auditLogger = auditLogger;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
Assert.isTrue(requiredRepetitions >= 1, "Must be => 1");
|
||||
|
||||
String startSql = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
+ "acl_object_identity.id as acl_id, "
|
||||
+ "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, "
|
||||
+ "acl_entry.id as ace_id, "
|
||||
+ "acl_entry.mask, "
|
||||
+ "acl_entry.granting, "
|
||||
+ "acl_entry.audit_success, "
|
||||
+ "acl_entry.audit_failure, "
|
||||
+ "acl_sid.principal as ace_principal, "
|
||||
+ "acl_sid.sid as ace_sid, "
|
||||
+ "acli_sid.principal as acl_principal, "
|
||||
+ "acli_sid.sid as acl_sid, "
|
||||
+ "acl_class.class "
|
||||
+ "from acl_object_identity "
|
||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
||||
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id "
|
||||
+ "where ( ";
|
||||
|
||||
String endSql = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
|
||||
StringBuffer sqlStringBuffer = new StringBuffer();
|
||||
sqlStringBuffer.append(startSql);
|
||||
|
||||
for (int i = 1; i <= requiredRepetitions; i++) {
|
||||
sqlStringBuffer.append(repeatingSql);
|
||||
|
||||
if (i != requiredRepetitions) {
|
||||
sqlStringBuffer.append(" or ");
|
||||
}
|
||||
}
|
||||
|
||||
sqlStringBuffer.append(endSql);
|
||||
|
||||
return sqlStringBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The final phase of converting the <code>Map</code> of <code>AclImpl</code> instances which contain
|
||||
* <code>StubAclParent</code>s into proper, valid <code>AclImpl</code>s with correct ACL parents.
|
||||
*
|
||||
* @param inputMap the unconverted <code>AclImpl</code>s
|
||||
* @param currentIdentity the current<code>Acl</code> that we wish to convert (this may be
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IllegalStateException DOCUMENT ME!
|
||||
*/
|
||||
private AclImpl convert(Map inputMap, Long currentIdentity) {
|
||||
Assert.notEmpty(inputMap, "InputMap required");
|
||||
Assert.notNull(currentIdentity, "CurrentIdentity required");
|
||||
|
||||
// Retrieve this Acl from the InputMap
|
||||
Acl uncastAcl = (Acl) inputMap.get(currentIdentity);
|
||||
Assert.isInstanceOf(AclImpl.class, uncastAcl, "The inputMap contained a non-AclImpl");
|
||||
|
||||
AclImpl inputAcl = (AclImpl) uncastAcl;
|
||||
|
||||
Acl parent = inputAcl.getParentAcl();
|
||||
|
||||
if ((parent != null) && parent instanceof StubAclParent) {
|
||||
// Lookup the parent
|
||||
StubAclParent stubAclParent = (StubAclParent) parent;
|
||||
parent = convert(inputMap, stubAclParent.getId());
|
||||
}
|
||||
|
||||
// Now we have the parent (if there is one), create the true AclImpl
|
||||
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long) inputAcl.getId(), aclAuthorizationStrategy,
|
||||
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
Field field = FieldUtils.getField(AclImpl.class, "aces");
|
||||
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
field.set(result, field.get(inputAcl));
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain or set AclImpl.ace field");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the current <code>ResultSet</code> row, and converts it into an <code>AclImpl</code> that
|
||||
* contains a <code>StubAclParent</code>
|
||||
*
|
||||
* @param acls the Map we should add the converted Acl to
|
||||
* @param rs the ResultSet focused on a current row
|
||||
*
|
||||
* @throws SQLException if something goes wrong converting values
|
||||
* @throws IllegalStateException DOCUMENT ME!
|
||||
*/
|
||||
private void convertCurrentResultIntoObject(Map acls, ResultSet rs)
|
||||
throws SQLException {
|
||||
Long id = new Long(rs.getLong("acl_id"));
|
||||
|
||||
// If we already have an ACL for this ID, just create the ACE
|
||||
AclImpl acl = (AclImpl) acls.get(id);
|
||||
|
||||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||
new Long(rs.getLong("object_id_identity")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(new Long(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
Sid owner;
|
||||
|
||||
if (rs.getBoolean("acl_principal")) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
||||
// It is permissable to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
Sid recipient;
|
||||
|
||||
if (rs.getBoolean("ace_principal")) {
|
||||
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||
} else {
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||
}
|
||||
|
||||
Permission permission = BasePermission.buildFromMask(rs.getInt("mask"));
|
||||
boolean granting = rs.getBoolean("granting");
|
||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, recipient, permission, granting,
|
||||
auditSuccess, auditFailure);
|
||||
|
||||
Field acesField = FieldUtils.getField(AclImpl.class, "aces");
|
||||
List aces;
|
||||
|
||||
try {
|
||||
acesField.setAccessible(true);
|
||||
aces = (List) acesField.get(acl);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain AclImpl.ace field: cause[" + ex.getMessage() + "]");
|
||||
}
|
||||
|
||||
// Add the ACE if it doesn't already exist in the ACL.aces field
|
||||
if (!aces.contains(ace)) {
|
||||
aces.add(ace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.<p>The caller is responsible
|
||||
* for optimization issues, such as selecting the identities to lookup, ensuring the cache doesn't contain them
|
||||
* already, and adding the returned elements to the cache etc.</p>
|
||||
* <p>This subclass is required to return fully valid <code>Acl</code>s, including properly-configured
|
||||
* parent ACLs.</p>
|
||||
*
|
||||
* @param objectIdentities DOCUMENT ME!
|
||||
* @param sids DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
private Map lookupObjectIdentities(final ObjectIdentity[] objectIdentities, Sid[] sids) {
|
||||
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
||||
|
||||
final Map acls = new HashMap(); // contains Acls with StubAclParents
|
||||
|
||||
// Make the "acls" map contain all requested objectIdentities
|
||||
// (including markers to each parent in the hierarchy)
|
||||
String sql = computeRepeatingSql("(acl_object_identity.object_id_identity = ? and acl_class.class = ?)",
|
||||
objectIdentities.length);
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
for (int i = 0; i < objectIdentities.length; i++) {
|
||||
// Determine prepared statement values for this iteration
|
||||
String javaType = objectIdentities[i].getJavaType().getName();
|
||||
Assert.isInstanceOf(Long.class, objectIdentities[i].getIdentifier(),
|
||||
"This class requires ObjectIdentity.getIdentifier() to be a Long");
|
||||
|
||||
long id = ((Long) objectIdentities[i].getIdentifier()).longValue();
|
||||
|
||||
// Inject values
|
||||
ps.setLong((2 * i) + 1, id);
|
||||
ps.setString((2 * i) + 2, javaType);
|
||||
}
|
||||
}
|
||||
}, 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);
|
||||
}
|
||||
|
||||
// Finally, convert our "acls" containing StubAclParents into true Acls
|
||||
Map resultMap = new HashMap();
|
||||
Iterator iter = acls.values().iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Acl inputAcl = (Acl) iter.next();
|
||||
Assert.isInstanceOf(AclImpl.class, inputAcl, "Map should have contained an AclImpl");
|
||||
Assert.isInstanceOf(Long.class, ((AclImpl) inputAcl).getId(), "Acl.getId() must be Long");
|
||||
|
||||
Acl result = convert(acls, (Long) ((AclImpl) inputAcl).getId());
|
||||
resultMap.put(result.getObjectIdentity(), result);
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the primary key IDs specified in "findNow", adding AclImpl instances with StubAclParents to the
|
||||
* "acls" Map.
|
||||
*
|
||||
* @param acls the AclImpls (with StubAclParents)
|
||||
* @param findNow Long-based primary keys to retrieve
|
||||
* @param sids DOCUMENT ME!
|
||||
*/
|
||||
private void lookupPrimaryKeys(final Map acls, final Set findNow, final Sid[] sids) {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
|
||||
String sql = computeRepeatingSql("(acl_object_identity.id = ?)", findNow.size());
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
Iterator iter = findNow.iterator();
|
||||
int i = 0;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
i++;
|
||||
ps.setLong(i, ((Long) iter.next()).longValue());
|
||||
}
|
||||
}
|
||||
}, 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.<p>WARNING: This implementation completely disregards the "sids" argument! Every item
|
||||
* in the cache is expected to contain all SIDs. If you have serious performance needs (eg a very large number of
|
||||
* SIDs per object identity), you'll probably want to develop a custom {@link LookupStrategy} implementation
|
||||
* instead.</p>
|
||||
* <p>The implementation works in batch sizes specfied by {@link #batchSize}.</p>
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (ignored by this implementation)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
*/
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) {
|
||||
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
|
||||
// Map<ObjectIdentity,Acl>
|
||||
Map result = new HashMap(); // contains FULLY loaded Acl objects
|
||||
|
||||
Set currentBatchToLoad = new HashSet(); // contains ObjectIdentitys
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
boolean aclFound = false;
|
||||
|
||||
// Check we don't already have this ACL in the results
|
||||
if (result.containsKey(objects[i])) {
|
||||
aclFound = true;
|
||||
}
|
||||
|
||||
// Check cache for the present ACL entry
|
||||
if (!aclFound) {
|
||||
Acl acl = aclCache.getFromCache(objects[i]);
|
||||
|
||||
// Ensure any cached element supports all the requested SIDs
|
||||
// (they should always, as our base impl doesn't filter on SID)
|
||||
if (acl != null) {
|
||||
if (acl.isSidLoaded(sids)) {
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
aclFound = true;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the ACL from the database
|
||||
if (!aclFound) {
|
||||
currentBatchToLoad.add(objects[i]);
|
||||
}
|
||||
|
||||
// Is it time to load from JDBC the currentBatchToLoad?
|
||||
if ((currentBatchToLoad.size() == this.batchSize) || ((i + 1) == objects.length)) {
|
||||
if (currentBatchToLoad.size() > 0) {
|
||||
Map loadedBatch = lookupObjectIdentities((ObjectIdentity[]) currentBatchToLoad.toArray(new ObjectIdentity[] {}), sids);
|
||||
|
||||
// Add loaded batch (all elements 100% initialized) to results
|
||||
result.putAll(loadedBatch);
|
||||
|
||||
// Add the loaded batch to the cache
|
||||
Iterator loadedAclIterator = loadedBatch.values().iterator();
|
||||
|
||||
while (loadedAclIterator.hasNext()) {
|
||||
aclCache.putInCache((AclImpl) loadedAclIterator.next());
|
||||
}
|
||||
|
||||
currentBatchToLoad.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class ProcessResultSet implements ResultSetExtractor {
|
||||
private Map acls;
|
||||
private Sid[] sids;
|
||||
|
||||
public ProcessResultSet(Map acls, Sid[] sids) {
|
||||
Assert.notNull(acls, "ACLs cannot be null");
|
||||
this.acls = acls;
|
||||
this.sids = sids; // can be null
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link ResultSetExtractor#extractData(ResultSet)}.
|
||||
* Creates an {@link Acl} for each row in the {@link ResultSet} and
|
||||
* ensures it is in member field <tt>acls</tt>. Any {@link Acl} with
|
||||
* 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
|
||||
* @return a list of parent IDs remaining to be looked up (may be empty, but never <tt>null</tt>)
|
||||
* @throws SQLException
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
Set parentIdsToLookup = new HashSet(); // Set of parent_id Longs
|
||||
|
||||
while (rs.next()) {
|
||||
// Convert current row into an Acl (albeit with a StubAclParent)
|
||||
convertCurrentResultIntoObject(acls, rs);
|
||||
|
||||
// Figure out if this row means we need to lookup another parent
|
||||
long parentId = rs.getLong("parent_object");
|
||||
|
||||
if (parentId != 0) {
|
||||
// See if it's already in the "acls"
|
||||
if (acls.containsKey(new Long(parentId))) {
|
||||
continue; // skip this while iteration
|
||||
}
|
||||
|
||||
// Now try to find it in the cache
|
||||
MutableAcl cached = aclCache.getFromCache(new Long(parentId));
|
||||
|
||||
if ((cached == null) || !cached.isSidLoaded(sids)) {
|
||||
parentIdsToLookup.add(new Long(parentId));
|
||||
} else {
|
||||
// Pop into the acls map, so our convert method doesn't
|
||||
// need to deal with an unsynchronized AclCache
|
||||
acls.put(cached.getId(), cached);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the parents left to lookup to the calller
|
||||
return parentIdsToLookup;
|
||||
}
|
||||
}
|
||||
|
||||
private class StubAclParent implements Acl {
|
||||
private Long id;
|
||||
|
||||
public StubAclParent(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AccessControlEntry[] getEntries() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ObjectIdentity getObjectIdentity() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public Sid getOwner() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public Acl getParentAcl() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public boolean isEntriesInheriting() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(Sid[] sids) {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.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
|
||||
* @version $Id$
|
||||
*/
|
||||
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);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Simple JDBC-based implementation of <code>AclService</code>.
|
||||
* <p>
|
||||
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl} and
|
||||
* {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set, so that the implementation can
|
||||
* detect changed parameters easily.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class JdbcAclService implements AclService {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
||||
private static final String selectAclObjectWithParent = "select obj.object_id_identity obj_id, class.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 "
|
||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||
+ "select id FROM acl_class where acl_class.class = ?)";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected JdbcTemplate jdbcTemplate;
|
||||
private LookupStrategy lookupStrategy;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
Assert.notNull(lookupStrategy, "LookupStrategy required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.lookupStrategy = lookupStrategy;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity) {
|
||||
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getJavaType().getName()};
|
||||
List objects = jdbcTemplate.query(selectAclObjectWithParent, args,
|
||||
new RowMapper() {
|
||||
public Object mapRow(ResultSet rs, int rowNum)
|
||||
throws SQLException {
|
||||
String javaType = rs.getString("class");
|
||||
Long identifier = new Long(rs.getLong("obj_id"));
|
||||
|
||||
return new ObjectIdentityImpl(javaType, identifier);
|
||||
}
|
||||
});
|
||||
|
||||
if (objects.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (ObjectIdentityImpl[]) objects.toArray(new ObjectIdentityImpl[objects.size()]);
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object, Sid[] sids) throws NotFoundException {
|
||||
Map map = readAclsById(new ObjectIdentity[] {object}, sids);
|
||||
Assert.isTrue(map.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object);
|
||||
|
||||
return (Acl) map.get(object);
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
|
||||
return readAclById(object, null);
|
||||
}
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException {
|
||||
return readAclsById(objects, null);
|
||||
}
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException {
|
||||
Map result = lookupStrategy.readAclsById(objects, sids);
|
||||
|
||||
// Check every requested object identity was found (throw NotFoundException if needed)
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (!result.containsKey(objects[i])) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '"
|
||||
+ objects[i].toString() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.MutableAclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a base implementation of {@link MutableAclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Johannes Zlattinger
|
||||
* @version $Id$
|
||||
*/
|
||||
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
private AclCache aclCache;
|
||||
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||
private String identityQuery = "call identity()";
|
||||
private String insertClass = "insert into acl_class (class) values (?)";
|
||||
private String insertEntry = "insert into acl_entry "
|
||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
||||
private String insertObjectIdentity = "insert into acl_object_identity "
|
||||
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
|
||||
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
|
||||
private String selectClassPrimaryKey = "select id from acl_class where class=?";
|
||||
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_class "
|
||||
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
|
||||
+ "and acl_object_identity.object_id_identity = ?";
|
||||
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
|
||||
private String updateObjectIdentity = "update acl_object_identity set "
|
||||
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
|
||||
super(dataSource, lookupStrategy);
|
||||
Assert.notNull(aclCache, "AclCache required");
|
||||
this.aclCache = aclCache;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity)
|
||||
throws AlreadyExistsException {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
|
||||
// Check this object identity hasn't already been persisted
|
||||
if (retrieveObjectIdentityPrimaryKey(objectIdentity) != null) {
|
||||
throw new AlreadyExistsException("Object identity '" + objectIdentity + "' already exists");
|
||||
}
|
||||
|
||||
// Need to retrieve the current principal, in order to know who "owns" this ACL (can be changed later on)
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
PrincipalSid sid = new PrincipalSid(auth);
|
||||
|
||||
// Create the acl_object_identity row
|
||||
createObjectIdentity(objectIdentity, sid);
|
||||
|
||||
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
|
||||
Acl acl = readAclById(objectIdentity);
|
||||
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
|
||||
|
||||
return (MutableAcl) acl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl object.
|
||||
*
|
||||
* @param acl containing the ACEs to insert
|
||||
*/
|
||||
protected void createEntries(final MutableAcl acl) {
|
||||
jdbcTemplate.batchUpdate(insertEntry,
|
||||
new BatchPreparedStatementSetter() {
|
||||
public int getBatchSize() {
|
||||
return acl.getEntries().length;
|
||||
}
|
||||
|
||||
public void setValues(PreparedStatement stmt, int i)
|
||||
throws SQLException {
|
||||
AccessControlEntry entry_ = (AccessControlEntry) Array.get(acl.getEntries(), i);
|
||||
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
|
||||
|
||||
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
|
||||
|
||||
stmt.setLong(1, ((Long) acl.getId()).longValue());
|
||||
stmt.setInt(2, i);
|
||||
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true).longValue());
|
||||
stmt.setInt(4, entry.getPermission().getMask());
|
||||
stmt.setBoolean(5, entry.isGranting());
|
||||
stmt.setBoolean(6, entry.isAuditSuccess());
|
||||
stmt.setBoolean(7, entry.isAuditFailure());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity. The Sid is also
|
||||
* necessary, as acl_object_identity has defined the sid column as non-null.
|
||||
*
|
||||
* @param object to represent an acl_object_identity for
|
||||
* @param owner for the SID column (will be created if there is no acl_sid entry for this particular Sid already)
|
||||
*/
|
||||
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
||||
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
||||
Long classId = createOrRetrieveClassPrimaryKey(object.getJavaType(), true);
|
||||
jdbcTemplate.update(insertObjectIdentity,
|
||||
new Object[] {classId, object.getIdentifier().toString(), sidId, new Boolean(true)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from acl_class, creating a new row if needed and the allowCreate property is
|
||||
* true.
|
||||
*
|
||||
* @param clazz to find or create an entry for (this implementation uses the fully-qualified class name String)
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
*
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveClassPrimaryKey(Class clazz, boolean allowCreate) {
|
||||
List classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {clazz.getName()}, Long.class);
|
||||
Long classId = null;
|
||||
|
||||
if (classIds.isEmpty()) {
|
||||
if (allowCreate) {
|
||||
classId = null;
|
||||
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
classId = new Long(jdbcTemplate.queryForLong(identityQuery));
|
||||
}
|
||||
} else {
|
||||
classId = (Long) classIds.iterator().next();
|
||||
}
|
||||
|
||||
return classId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
|
||||
* true.
|
||||
*
|
||||
* @param sid to find or create
|
||||
* @param allowCreate true if creation is permitted if not found
|
||||
*
|
||||
* @return the primary key or null if not found
|
||||
*
|
||||
* @throws IllegalArgumentException DOCUMENT ME!
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
Assert.notNull(sid, "Sid required");
|
||||
|
||||
String sidName = null;
|
||||
boolean principal = true;
|
||||
|
||||
if (sid instanceof PrincipalSid) {
|
||||
sidName = ((PrincipalSid) sid).getPrincipal();
|
||||
} else if (sid instanceof GrantedAuthoritySid) {
|
||||
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
|
||||
principal = false;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
||||
}
|
||||
|
||||
List sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey, new Object[] {new Boolean(principal), sidName},
|
||||
Long.class);
|
||||
Long sidId = null;
|
||||
|
||||
if (sidIds.isEmpty()) {
|
||||
if (allowCreate) {
|
||||
sidId = null;
|
||||
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
sidId = new Long(jdbcTemplate.queryForLong(identityQuery));
|
||||
}
|
||||
} else {
|
||||
sidId = (Long) sidIds.iterator().next();
|
||||
}
|
||||
|
||||
return sidId;
|
||||
}
|
||||
|
||||
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
|
||||
throws ChildrenExistException {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
|
||||
|
||||
if (deleteChildren) {
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
deleteAcl(children[i], true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!foreignKeysInDatabase) {
|
||||
// We need to perform a manual verification for what a FK would normally do
|
||||
// We generally don't do this, in the interests of deadlock management
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.length
|
||||
+ " children)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(oidPrimaryKey);
|
||||
|
||||
// Delete this ACL's acl_object_identity row
|
||||
deleteObjectIdentity(oidPrimaryKey);
|
||||
|
||||
// Clear the cache
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity primary key.
|
||||
*
|
||||
* @param oidPrimaryKey the rows in acl_entry to delete
|
||||
*/
|
||||
protected void deleteEntries(Long oidPrimaryKey) {
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
|
||||
new Object[] {oidPrimaryKey});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a single row from acl_object_identity that is associated with the presented ObjectIdentity primary key.
|
||||
*
|
||||
* <p>
|
||||
* We do not delete any entries from acl_class, even if no classes are using that class any longer. This is a
|
||||
* deadlock avoidance approach.
|
||||
* </p>
|
||||
*
|
||||
* @param oidPrimaryKey to delete the acl_object_identity
|
||||
*/
|
||||
protected void deleteObjectIdentity(Long oidPrimaryKey) {
|
||||
// Delete the acl_object_identity row
|
||||
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the primary key from the acl_object_identity table for the passed ObjectIdentity. Unlike some
|
||||
* other methods in this implementation, this method will NOT create a row (use {@link
|
||||
* #createObjectIdentity(ObjectIdentity, Sid)} instead).
|
||||
*
|
||||
* @param oid to find
|
||||
*
|
||||
* @return the object identity or null if not found
|
||||
*/
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
||||
new Object[] {oid.getJavaType().getName(), oid.getIdentifier()}));
|
||||
} catch (DataAccessException notFound) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation will simply delete all ACEs in the database and recreate them on each invocation of
|
||||
* this method. A more comprehensive implementation might use dirty state checking, or more likely use ORM
|
||||
* capabilities for create, update and delete operations of {@link MutableAcl}.
|
||||
*
|
||||
* @param acl DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
||||
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
|
||||
|
||||
// Create this ACL's ACEs in the acl_entry table
|
||||
createEntries(acl);
|
||||
|
||||
// Change the mutable columns in acl_object_identity
|
||||
updateObjectIdentity(acl);
|
||||
|
||||
// Clear the cache, including children
|
||||
clearCacheIncludingChildren(acl.getObjectIdentity());
|
||||
|
||||
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
|
||||
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
|
||||
}
|
||||
|
||||
private void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
clearCacheIncludingChildren(children[i]);
|
||||
}
|
||||
}
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing acl_object_identity row, with new information presented in the passed MutableAcl
|
||||
* object. Also will create an acl_sid entry if needed for the Sid that owns the MutableAcl.
|
||||
*
|
||||
* @param acl to modify (a row must already exist in acl_object_identity)
|
||||
*
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
protected void updateObjectIdentity(MutableAcl acl) {
|
||||
Long parentId = null;
|
||||
|
||||
if (acl.getParentAcl() != null) {
|
||||
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
|
||||
"Implementation only supports ObjectIdentityImpl");
|
||||
|
||||
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
|
||||
parentId = retrieveObjectIdentityPrimaryKey(oii);
|
||||
}
|
||||
|
||||
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
|
||||
|
||||
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
|
||||
int count = jdbcTemplate.update(updateObjectIdentity,
|
||||
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
|
||||
|
||||
if (count != 1) {
|
||||
throw new NotFoundException("Unable to locate ACL to update");
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.identityQuery = identityQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
|
||||
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||
*/
|
||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Performs lookups for {@link org.springframework.security.acls.AclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface LookupStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Perform database-specific optimized lookup.
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (may be <tt>null</tt> - implementations may elect not
|
||||
* to provide SID optimisations)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
*/
|
||||
Map readAclsById(ObjectIdentity[] objects, Sid[] sids);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
JDBC-based persistence of ACL information.
|
||||
</body>
|
||||
</html>
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
/* 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.objectidentity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the identity of an individual domain object instance.
|
||||
*
|
||||
* <p>
|
||||
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
||||
* domain objects in the ACL subsystem, it is essential that implementations provide
|
||||
* methods so that object-equality rather than reference-equality can be relied upon
|
||||
* reliably. In other words, the ACL subsystem can consider two
|
||||
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
||||
* reference-equality of <tt>identity1==identity2</tt>.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface ObjectIdentity extends Serializable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* @param obj to be compared
|
||||
*
|
||||
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
|
||||
* 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>
|
||||
*
|
||||
* @return the identifier (unique within this <tt>javaType</tt>; never <tt>null</tt>)
|
||||
*/
|
||||
Serializable getIdentifier();
|
||||
|
||||
/**
|
||||
* Obtains the Java type represented by the domain object. The Java type can be an interface or a class, but is
|
||||
* most often the domain object implementation class.
|
||||
*
|
||||
* @return the Java type of the domain object (never <tt>null</tt>)
|
||||
*/
|
||||
Class getJavaType();
|
||||
|
||||
/**
|
||||
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
||||
* @see Object#hashCode()
|
||||
*/
|
||||
int hashCode();
|
||||
}
|
||||
-152
@@ -1,152 +0,0 @@
|
||||
/* 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.objectidentity;
|
||||
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link ObjectIdentity}.
|
||||
* <p>
|
||||
* Uses <code>String</code>s to store the identity of the domain object instance. Also offers a constructor that uses
|
||||
* reflection to build the identity information.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private Class javaType;
|
||||
private Serializable identifier;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public ObjectIdentityImpl(String javaType, Serializable identifier) {
|
||||
Assert.hasText(javaType, "Java Type required");
|
||||
Assert.notNull(identifier, "identifier required");
|
||||
|
||||
try {
|
||||
this.javaType = Class.forName(javaType);
|
||||
} catch (Exception ex) {
|
||||
ReflectionUtils.handleReflectionException(ex);
|
||||
}
|
||||
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public ObjectIdentityImpl(Class javaType, Serializable identifier) {
|
||||
Assert.notNull(javaType, "Java Type required");
|
||||
Assert.notNull(identifier, "identifier required");
|
||||
this.javaType = javaType;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the <code>ObjectIdentityImpl</code> based on the passed
|
||||
* object instance. The passed object must provide a <code>getId()</code>
|
||||
* method, otherwise an exception will be thrown. The object passed will
|
||||
* be considered the {@link #javaType}, so if more control is required,
|
||||
* an alternate constructor should be used instead.
|
||||
*
|
||||
* @param object the domain object instance to create an identity for
|
||||
*
|
||||
* @throws IdentityUnavailableException if identity could not be extracted
|
||||
*/
|
||||
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
||||
Assert.notNull(object, "object cannot be null");
|
||||
|
||||
this.javaType = ClassUtils.getUserClass(object.getClass());
|
||||
|
||||
Object result;
|
||||
|
||||
try {
|
||||
Method method = this.javaType.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.isInstanceOf(Serializable.class, result, "Getter must provide a return value of type Serializable");
|
||||
this.identifier = (Serializable) result;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Important so caching operates properly.<P>Considers an object of the same class equal if it has the same
|
||||
* <code>classname</code> and <code>id</code> properties.</p>
|
||||
*
|
||||
* @param arg0 object to compare
|
||||
*
|
||||
* @return <code>true</code> if the presented object matches this object
|
||||
*/
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof ObjectIdentityImpl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
|
||||
|
||||
if (this.getIdentifier().equals(other.getIdentifier()) && this.getJavaType().equals(other.getJavaType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Serializable getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public Class getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Important so caching operates properly.
|
||||
*
|
||||
* @return the hash
|
||||
*/
|
||||
public int hashCode() {
|
||||
int code = 31;
|
||||
code ^= this.javaType.hashCode();
|
||||
code ^= this.identifier.hashCode();
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(this.getClass().getName()).append("[");
|
||||
sb.append("Java Type: ").append(this.javaType.getName());
|
||||
sb.append("; Identifier: ").append(this.identifier).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/* 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.objectidentity;
|
||||
|
||||
/**
|
||||
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
|
||||
* will be returned for a particular domain object
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*
|
||||
*/
|
||||
public interface ObjectIdentityRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
ObjectIdentity getObjectIdentity(Object domainObject);
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/* 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.objectidentity;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} that uses the constructor of {@link
|
||||
* ObjectIdentityImpl} to create the {@link ObjectIdentity}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public ObjectIdentity getObjectIdentity(Object domainObject) {
|
||||
return new ObjectIdentityImpl(domainObject);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides indirection between ACL packages and domain objects.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Interfaces and shared classes to manage access control lists (ACLs) for domain object instances.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,71 +0,0 @@
|
||||
/* 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.sid;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a <code>GrantedAuthority</code> as a <code>Sid</code>.<p>This is a basic implementation that simply
|
||||
* uses the <code>String</code>-based principal 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
|
||||
* @version $Id$
|
||||
*/
|
||||
public class GrantedAuthoritySid implements Sid {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private String grantedAuthority;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public GrantedAuthoritySid(String grantedAuthority) {
|
||||
Assert.hasText(grantedAuthority, "GrantedAuthority required");
|
||||
this.grantedAuthority = grantedAuthority;
|
||||
}
|
||||
|
||||
public GrantedAuthoritySid(GrantedAuthority grantedAuthority) {
|
||||
Assert.notNull(grantedAuthority, "GrantedAuthority required");
|
||||
Assert.notNull(grantedAuthority.getAuthority(),
|
||||
"This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()");
|
||||
this.grantedAuthority = grantedAuthority.getAuthority();
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof GrantedAuthoritySid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delegate to getGrantedAuthority() to perform actual comparison (both should be identical)
|
||||
return ((GrantedAuthoritySid) object).getGrantedAuthority().equals(this.getGrantedAuthority());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.getGrantedAuthority().hashCode();
|
||||
}
|
||||
|
||||
public String getGrantedAuthority() {
|
||||
return grantedAuthority;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/* 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.sid;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an <code>Authentication.getPrincipal()</code> as a <code>Sid</code>.<p>This is a basic implementation
|
||||
* that simply uses the <code>String</code>-based principal 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
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PrincipalSid implements Sid {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private String principal;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public PrincipalSid(String principal) {
|
||||
Assert.hasText(principal, "Principal required");
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public PrincipalSid(Authentication authentication) {
|
||||
Assert.notNull(authentication, "Authentication required");
|
||||
Assert.notNull(authentication.getPrincipal(), "Principal required");
|
||||
|
||||
if (authentication.getPrincipal() instanceof UserDetails) {
|
||||
this.principal = ((UserDetails) authentication.getPrincipal()).getUsername();
|
||||
} else {
|
||||
this.principal = authentication.getPrincipal().toString();
|
||||
}
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if ((object == null) || !(object instanceof PrincipalSid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delegate to getPrincipal() to perform actual comparison (both should be identical)
|
||||
return ((PrincipalSid) object).getPrincipal().equals(this.getPrincipal());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.getPrincipal().hashCode();
|
||||
}
|
||||
|
||||
public String getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "PrincipalSid[" + this.principal + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/* 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.sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A security identity recognised by the ACL system.
|
||||
*
|
||||
* <p>
|
||||
* This interface provides indirection between actual security objects (eg
|
||||
* principals, roles, groups etc) and what is stored inside an
|
||||
* <code>Acl</code>. This is because an <code>Acl</code> will not store an
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface Sid extends Serializable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
|
||||
*
|
||||
* @param obj to be compared
|
||||
*
|
||||
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
|
||||
*/
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
|
||||
*
|
||||
* @return a hash code representation of this object
|
||||
*/
|
||||
int hashCode();
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/* 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.sid;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface that provides an ability to determine the {@link Sid} instances applicable
|
||||
* for an {@link Authentication}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface SidRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
Sid[] getSids(Authentication authentication);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/* 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.sid;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
|
||||
* every granted authority the principal holds.
|
||||
* <p>
|
||||
* The returned array will always contain the {@link PrincipalSid} before any {@link GrantedAuthoritySid} elements.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Sid[] getSids(Authentication authentication) {
|
||||
GrantedAuthority[] authorities = authentication.getAuthorities();
|
||||
Sid[] sids = new Sid[authorities.length + 1];
|
||||
|
||||
sids[0] = new PrincipalSid(authentication);
|
||||
|
||||
for (int i = 1; i <= authorities.length; i++) {
|
||||
sids[i] = new GrantedAuthoritySid(authorities[i - 1]);
|
||||
}
|
||||
|
||||
return sids;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides indirection between ACL packages and security identities, such as principals and GrantedAuthority[]s.
|
||||
</body>
|
||||
</html>
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
/* 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.afterinvocation;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategy;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.acls.sid.SidRetrievalStrategy;
|
||||
import org.springframework.security.acls.sid.SidRetrievalStrategyImpl;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @author $author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AclService aclService;
|
||||
private Class processDomainObjectClass = Object.class;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
private String processConfigAttribute;
|
||||
private Permission[] requirePermission = {BasePermission.READ};
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AbstractAclProvider(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
|
||||
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||
Assert.notNull(aclService, "An AclService is mandatory");
|
||||
|
||||
if ((requirePermission == null) || (requirePermission.length == 0)) {
|
||||
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
|
||||
}
|
||||
|
||||
this.aclService = aclService;
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
this.requirePermission = requirePermission;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected Class getProcessDomainObjectClass() {
|
||||
return processDomainObjectClass;
|
||||
}
|
||||
|
||||
protected boolean hasPermission(Authentication authentication, Object domainObject) {
|
||||
// Obtain the OID applicable to the domain object
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
|
||||
// Obtain the SIDs applicable to the principal
|
||||
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
Acl acl = null;
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
acl = aclService.readAclById(objectIdentity, sids);
|
||||
|
||||
return acl.isGranted(requirePermission, sids, false);
|
||||
} catch (NotFoundException ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
|
||||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
protected void setProcessConfigAttribute(String processConfigAttribute) {
|
||||
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
}
|
||||
|
||||
public void setProcessDomainObjectClass(Class processDomainObjectClass) {
|
||||
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
|
||||
this.processDomainObjectClass = processDomainObjectClass;
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return processConfigAttribute.equals(attribute.getAttribute());
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports any type of class, because it does not query the presented secure object.
|
||||
*
|
||||
* @param clazz the secure object
|
||||
*
|
||||
* @return always <code>true</code>
|
||||
*/
|
||||
public boolean supports(Class clazz) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
/* 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.afterinvocation;
|
||||
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthorizationServiceException;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Given a <code>Collection</code> of domain object instances returned from a secure object invocation, remove
|
||||
* any <code>Collection</code> elements the principal does not have appropriate permission to access as defined by the
|
||||
* {@link AclService}.
|
||||
* <p>
|
||||
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with
|
||||
* each <code>Collection</code> domain object instance element for the current <code>Authentication</code> object.
|
||||
* <p>
|
||||
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
|
||||
* #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
|
||||
* principal is {@link org.springframework.security.acls.Acl#isGranted(org.springframework.security.acls.Permission[],
|
||||
* org.springframework.security.acls.sid.Sid[], boolean) Acl.isGranted(Permission[], Sid[], boolean)}
|
||||
* when presenting the {@link #requirePermission} array to that method.
|
||||
* <p>
|
||||
* If the principal does not have permission, that element will not be included in the returned
|
||||
* <code>Collection</code>.
|
||||
* <p>
|
||||
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a {@link
|
||||
* #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a {@link #requirePermission} of
|
||||
* <code>BasePermission.READ</code>. These are also the defaults.
|
||||
* <p>
|
||||
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code><code>Collection</code>
|
||||
* will be returned. If the provided <code>returnObject</code> is not a <code>Collection</code>, an {@link
|
||||
* AuthorizationServiceException} will be thrown.
|
||||
* <p>
|
||||
* All comparisons and prefixes are case sensitive.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Paulo Neves
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, Permission[] requirePermission) {
|
||||
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
if (returnedObject == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is null, skipping");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attr = (ConfigAttribute) iter.next();
|
||||
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Need to process the Collection for this invocation
|
||||
Filterer filterer;
|
||||
|
||||
if (returnedObject instanceof Collection) {
|
||||
filterer = new CollectionFilterer((Collection) returnedObject);
|
||||
} else if (returnedObject.getClass().isArray()) {
|
||||
filterer = new ArrayFilterer((Object[]) returnedObject);
|
||||
} else {
|
||||
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
|
||||
+ "returnedObject, but the returnedObject was: " + returnedObject);
|
||||
}
|
||||
|
||||
// Locate unauthorised Collection elements
|
||||
Iterator collectionIter = filterer.iterator();
|
||||
|
||||
while (collectionIter.hasNext()) {
|
||||
Object domainObject = collectionIter.next();
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
-125
@@ -1,125 +0,0 @@
|
||||
/* 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.afterinvocation;
|
||||
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* Given a domain object instance returned from a secure object invocation, ensures the principal has
|
||||
* appropriate permission as defined by the {@link AclService}.
|
||||
* <p>
|
||||
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
|
||||
* domain object instance for the current <code>Authentication</code> object.
|
||||
* <p>
|
||||
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
|
||||
* #processConfigAttribute}. The provider will then lookup the ACLs from the <tt>AclService</tt> and ensure the
|
||||
* principal is {@link org.springframework.security.acls.Acl#isGranted(org.springframework.security.acls.Permission[],
|
||||
org.springframework.security.acls.sid.Sid[], boolean) Acl.isGranted(Permission[], Sid[], boolean)}
|
||||
* when presenting the {@link #requirePermission} array to that method.
|
||||
* <p>
|
||||
* Often users will setup an <code>AclEntryAfterInvocationProvider</code> with a {@link
|
||||
* #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a {@link #requirePermission} of
|
||||
* <code>BasePermission.READ</code>. These are also the defaults.
|
||||
* <p>
|
||||
* If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.
|
||||
* <p>
|
||||
* If the provided <tt>returnedObject</tt> is <code>null</code>, permission will always be granted and
|
||||
* <code>null</code> will be returned.
|
||||
* <p>
|
||||
* All comparisons and prefixes are case sensitive.
|
||||
*/
|
||||
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, Permission[] requirePermission) {
|
||||
super(aclService, "AFTER_ACL_READ", requirePermission);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
|
||||
if (returnedObject == null) {
|
||||
// AclManager interface contract prohibits nulls
|
||||
// As they have permission to null/nothing, grant access
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is null, skipping");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is not applicable for this provider, skipping");
|
||||
}
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attr = (ConfigAttribute) iter.next();
|
||||
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
// Need to make an access decision on this invocation
|
||||
|
||||
if (hasPermission(authentication, returnedObject)) {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
logger.debug("Denying access");
|
||||
|
||||
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
|
||||
new Object[] {authentication.getName(), returnedObject},
|
||||
"Authentication {0} has NO permissions to the domain object {1}"));
|
||||
}
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/* 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.vote;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthorizationServiceException;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategy;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.acls.sid.SidRetrievalStrategy;
|
||||
import org.springframework.security.acls.sid.SidRetrievalStrategyImpl;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Given a domain object instance passed as a method argument, ensures the principal has appropriate permission
|
||||
* as indicated by the {@link AclService}.
|
||||
* <p>
|
||||
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions associated with a
|
||||
* domain object instance for the current <tt>Authentication</tt> object.
|
||||
* <p>
|
||||
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the {@link #processConfigAttribute}.
|
||||
* The provider will then locate the first method argument of type {@link #processDomainObjectClass}. Assuming that
|
||||
* method argument is non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and ensure the
|
||||
* principal is {@link Acl#isGranted(org.springframework.security.acls.Permission[],
|
||||
* org.springframework.security.acls.sid.Sid[], boolean)} when presenting the {@link #requirePermission} array to that
|
||||
* method.
|
||||
* <p>
|
||||
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the method argument
|
||||
* could not be found, an {@link org.springframework.security.AuthorizationServiceException} will be thrown.
|
||||
* <p>
|
||||
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each will have a
|
||||
* different {@link #processDomainObjectClass}, {@link #processConfigAttribute} and {@link #requirePermission}
|
||||
* combination. For example, a small application might employ the following instances of <tt>AclEntryVoter</tt>:
|
||||
* <ul>
|
||||
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
||||
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission <code>BasePermission.READ</code></li>
|
||||
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
||||
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
|
||||
* <code>BasePermission.CREATE</code> (allowing the principal to have <b>either</b> of these two permissions)</li>
|
||||
* <li>Process domain object class <code>Customer</code>, configuration attribute
|
||||
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission <code>BasePermission.READ</code></li>
|
||||
* <li>Process domain object class <code>Customer</code>, configuration attribute
|
||||
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
|
||||
* <code>BasePermission.CREATE</code></li>
|
||||
* </ul>
|
||||
* Alternatively, you could have used a common superclass or interface for the {@link #processDomainObjectClass}
|
||||
* if both <code>BankAccount</code> and <code>Customer</code> had common parents.</p>
|
||||
* <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>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AclEntryVoter extends AbstractAclVoter {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AclService aclService;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
private String internalMethod;
|
||||
private String processConfigAttribute;
|
||||
private Permission[] requirePermission;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
|
||||
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||
Assert.notNull(aclService, "An AclService is mandatory");
|
||||
|
||||
if ((requirePermission == null) || (requirePermission.length == 0)) {
|
||||
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
|
||||
}
|
||||
|
||||
this.aclService = aclService;
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
this.requirePermission = requirePermission;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Optionally specifies a method of the domain object that will be used to obtain a contained domain
|
||||
* object. That contained domain object will be used for the ACL evaluation. This is useful if a domain object
|
||||
* contains a parent that an ACL evaluation should be targeted for, instead of the child domain object (which
|
||||
* perhaps is being created and as such does not yet have any ACL permissions)
|
||||
*
|
||||
* @return <code>null</code> to use the domain object, or the name of a method (that requires no arguments) that
|
||||
* should be invoked to obtain an <code>Object</code> which will be the domain object used for ACL
|
||||
* evaluation
|
||||
*/
|
||||
protected String getInternalMethod() {
|
||||
return internalMethod;
|
||||
}
|
||||
|
||||
public void setInternalMethod(String internalMethod) {
|
||||
this.internalMethod = internalMethod;
|
||||
}
|
||||
|
||||
protected String getProcessConfigAttribute() {
|
||||
return processConfigAttribute;
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
|
||||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attr = (ConfigAttribute) iter.next();
|
||||
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
// Need to make an access decision on this invocation
|
||||
// Attempt to locate the domain object instance to process
|
||||
Object domainObject = getDomainObjectInstance(object);
|
||||
|
||||
// If domain object is null, vote to abstain
|
||||
if (domainObject == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to abstain - domainObject is null");
|
||||
}
|
||||
|
||||
return AccessDecisionVoter.ACCESS_ABSTAIN;
|
||||
}
|
||||
|
||||
// Evaluate if we are required to use an inner domain object
|
||||
if (StringUtils.hasText(internalMethod)) {
|
||||
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
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
|
||||
// Obtain the SIDs applicable to the principal
|
||||
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
Acl acl;
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
acl = aclService.readAclById(objectIdentity, sids);
|
||||
} catch (NotFoundException nfe) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
}
|
||||
|
||||
return AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
|
||||
try {
|
||||
if (acl.isGranted(requirePermission, sids, false)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to grant access");
|
||||
}
|
||||
|
||||
return AccessDecisionVoter.ACCESS_GRANTED;
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Voting to deny access - ACLs returned, but insufficient permissions for this principal");
|
||||
}
|
||||
|
||||
return AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
} catch (NotFoundException nfe) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
}
|
||||
|
||||
return AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
// No configuration attribute matched, so abstain
|
||||
return AccessDecisionVoter.ACCESS_ABSTAIN;
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
|
||||
<!--
|
||||
- Application context containing business beans.
|
||||
-
|
||||
- Used by all artifacts.
|
||||
-
|
||||
- $Id:applicationContext-test.xml 1754 2006-11-17 02:01:21Z benalex $
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="databaseSeeder" class="org.springframework.security.acls.jdbc.DatabaseSeeder">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg value="classpath:org/springframework/security/acls/jdbc/testData.sql"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="aclCache" class="org.springframework.security.acls.jdbc.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
||||
<property name="cacheManager">
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
|
||||
</property>
|
||||
<property name="cacheName" value="aclCache"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
<constructor-arg ref="aclAuthorizationStrategy"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="lookupStrategy"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" class="org.springframework.security.TestDataSource">
|
||||
<constructor-arg value="acltest" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -1,27 +0,0 @@
|
||||
-- Not required. Just shows the sort of queries being sent to DB.
|
||||
|
||||
|
||||
select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER,
|
||||
ACL_OBJECT_IDENTITY.ID as ACL_ID,
|
||||
ACL_OBJECT_IDENTITY.PARENT_OBJECT,
|
||||
ACL_OBJECT_IDENTITY,ENTRIES_INHERITING,
|
||||
ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE,
|
||||
ACL_SID.PRINCIPAL as ACE_PRINCIPAL, ACL_SID.SID as ACE_SID,
|
||||
ACLI_SID.PRINCIPAL as ACL_PRINCIPAL, ACLI_SID.SID as ACL_SID,
|
||||
ACL_CLASS.CLASS
|
||||
|
||||
from ACL_OBJECT_IDENTITY, ACL_SID ACLI_SID, ACL_CLASS
|
||||
LEFT JOIN ACL_ENTRY ON ACL_OBJECT_IDENTITY.ID = ACL_ENTRY.ACL_OBJECT_IDENTITY
|
||||
LEFT JOIN ACL_SID ON ACL_ENTRY.SID = ACL_SID.ID
|
||||
|
||||
where
|
||||
|
||||
ACLI_SID.ID = ACL_OBJECT_IDENTITY.OWNER_SID
|
||||
and ACL_CLASS.ID = ACL_OBJECT_IDENTITY.OBJECT_ID_CLASS
|
||||
and (
|
||||
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 1
|
||||
and ACL_CLASS.CLASS = 'sample.contact.Contact')
|
||||
or
|
||||
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 2000
|
||||
and ACL_CLASS.CLASS = 'sample.contact.Contact')
|
||||
) order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc
|
||||
@@ -1,45 +0,0 @@
|
||||
-- Injected into DatabaseSeeder via applicationContext-test.xml (see test case JdbcAclServiceTests)
|
||||
|
||||
-- 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,
|
||||
CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));
|
||||
|
||||
INSERT INTO ACL_CLASS VALUES (1, 'sample.contact.Contact');
|
||||
|
||||
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 BIGINT 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,124 +0,0 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link AclFormattingUtils}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AclFormattingUtilsTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public final void testDemergePatternsParametersConstraints() throws Exception {
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns(null, "SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
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 removeBits = "...............................R";
|
||||
Assert.assertEquals("...........................A....", AclFormattingUtils
|
||||
.demergePatterns(original, removeBits));
|
||||
|
||||
Assert.assertEquals("ABCDEF", AclFormattingUtils.demergePatterns("ABCDEF", "......"));
|
||||
Assert.assertEquals("......", AclFormattingUtils.demergePatterns("ABCDEF", "GHIJKL"));
|
||||
}
|
||||
|
||||
public final void testMergePatternsParametersConstraints() throws Exception {
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns(null, "SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
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 extraBits = "...........................A....";
|
||||
Assert.assertEquals("...........................A...R", AclFormattingUtils
|
||||
.mergePatterns(original, extraBits));
|
||||
|
||||
Assert.assertEquals("ABCDEF", AclFormattingUtils.mergePatterns("ABCDEF", "......"));
|
||||
Assert.assertEquals("GHIJKL", AclFormattingUtils.mergePatterns("ABCDEF", "GHIJKL"));
|
||||
}
|
||||
|
||||
public final void testBinaryPrints() throws Exception {
|
||||
Assert.assertEquals("............................****", AclFormattingUtils.printBinary(15));
|
||||
|
||||
try {
|
||||
AclFormattingUtils.printBinary(15, Permission.RESERVED_ON);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
Assert.assertEquals("............................xxxx", AclFormattingUtils.printBinary(15, 'x'));
|
||||
}
|
||||
}
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
/**
|
||||
* Test class for {@link AccessControlEntryImpl}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AccessControlEntryTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testConstructorRequiredFields() throws Exception {
|
||||
// Check Acl field is present
|
||||
try {
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(null, null, new PrincipalSid("johndoe"),
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check Sid field is present
|
||||
try {
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(null, new MockAcl(), null,
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check Permission field is present
|
||||
try {
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(null, new MockAcl(), new PrincipalSid("johndoe"), null,
|
||||
true, true, true);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAccessControlEntryImplGetters() throws Exception {
|
||||
Acl mockAcl = new MockAcl();
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
// Create a sample entry
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
// and check every get() method
|
||||
Assert.assertEquals(new Long(1), ace.getId());
|
||||
Assert.assertEquals(mockAcl, ace.getAcl());
|
||||
Assert.assertEquals(sid, ace.getSid());
|
||||
Assert.assertTrue(ace.isGranting());
|
||||
Assert.assertEquals(BasePermission.ADMINISTRATION, ace.getPermission());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) ace).isAuditFailure());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) ace).isAuditSuccess());
|
||||
}
|
||||
|
||||
public void testEquals() throws Exception {
|
||||
Acl mockAcl = new MockAcl();
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
Assert.assertFalse(ace.equals(null));
|
||||
Assert.assertFalse(ace.equals(new Long(100)));
|
||||
Assert.assertTrue(ace.equals(ace));
|
||||
Assert.assertTrue(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
|
||||
true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, false, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, false, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, false)));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAcl implements Acl {
|
||||
|
||||
public AccessControlEntry[] getEntries() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectIdentity getObjectIdentity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sid getOwner() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Acl getParentAcl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEntriesInheriting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(Sid[] sids) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,638 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.AuditableAcl;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.MutableAclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.OwnershipAcl;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link AclImpl}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AclImplTests extends TestCase {
|
||||
// ~ Methods ========================================================================================================
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testConstructorsRejectNullParameters() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
try {
|
||||
Acl acl = new AclImpl(null, new Long(1), strategy, auditLogger);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, null, strategy, auditLogger);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), null, auditLogger);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), strategy, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(null, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, null, strategy, auditLogger, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), null, auditLogger, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), strategy, null, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertAceRejectsNullParameters() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
try {
|
||||
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
acl.insertAce(0, BasePermission.READ, null, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInsertAceAddsElementAtCorrectIndex() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
service.updateAcl(acl);
|
||||
// Check it was successfully added
|
||||
assertEquals(1, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getAcl(), acl);
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
|
||||
// Add a second permission
|
||||
acl.insertAce(1, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
service.updateAcl(acl);
|
||||
// Check it was added on the last position
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[1].getAcl(), acl);
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
|
||||
// Add a third permission, after the first one
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_TEST3"), false);
|
||||
service.updateAcl(acl);
|
||||
assertEquals(3, acl.getEntries().length);
|
||||
// Check the third entry was added between the two existent ones
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.WRITE);
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[2].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
}
|
||||
|
||||
public void testInsertAceFailsForInexistentElement() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
try {
|
||||
acl.insertAce(55, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAceKeepsInitialOrdering() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Add several permissions
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
acl.insertAce(1, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST3"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
// Delete first permission and check the order of the remaining permissions is kept
|
||||
acl.deleteAce(0);
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
|
||||
// Add one more permission and remove the permission in the middle
|
||||
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST4"), true);
|
||||
service.updateAcl(acl);
|
||||
acl.deleteAce(1);
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST4"));
|
||||
|
||||
// Remove remaining permissions
|
||||
acl.deleteAce(1);
|
||||
acl.deleteAce(0);
|
||||
assertEquals(0, acl.getEntries().length);
|
||||
}
|
||||
|
||||
public void testDeleteAceFailsForInexistentElement() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
try {
|
||||
acl.deleteAce(99);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testIsGrantingRejectsEmptyParameters() throws Exception {
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
||||
try {
|
||||
acl.isGranted(new Permission[] {}, new Sid[] { new PrincipalSid("ben") }, false);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
acl.isGranted(new Permission[] { BasePermission.READ }, new Sid[] {}, false);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testIsGrantingGrantsAccessForAclWithNoParent() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GUEST") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity rootOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
// Create an ACL which owner is not the authenticated principal
|
||||
MutableAcl rootAcl = new AclImpl(rootOid, new Long(1), strategy, auditLogger, null, null, false, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
||||
// Grant some permissions
|
||||
rootAcl.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), false);
|
||||
rootAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid("scott"), true);
|
||||
rootAcl.insertAce(2, BasePermission.WRITE, new PrincipalSid("rod"), false);
|
||||
rootAcl.insertAce(3, BasePermission.WRITE, new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), true);
|
||||
|
||||
// Check permissions granting
|
||||
Permission[] permissions = new Permission[] { BasePermission.READ, BasePermission.CREATE };
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_GUEST") };
|
||||
assertFalse(rootAcl.isGranted(permissions, sids, false));
|
||||
try {
|
||||
rootAcl.isGranted(permissions, new Sid[] { new PrincipalSid("scott") }, false);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
assertTrue(rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("scott") },
|
||||
false));
|
||||
assertFalse(rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("rod"),
|
||||
new GrantedAuthoritySid("WRITE_ACCESS_ROLE") }, false));
|
||||
assertTrue(rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] {
|
||||
new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), new PrincipalSid("rod") }, false));
|
||||
try {
|
||||
// Change the type of the Sid and check the granting process
|
||||
rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new GrantedAuthoritySid("rod"),
|
||||
new PrincipalSid("WRITE_ACCESS_ROLE") }, false);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testIsGrantingGrantsAccessForInheritableAcls() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity parentOid1 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity parentOid2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity childOid1 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
|
||||
ObjectIdentity childOid2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
|
||||
// Create ACLs
|
||||
MutableAcl grandParentAcl = new AclImpl(grandParentOid, new Long(1), strategy, auditLogger, null, null, false,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl parentAcl1 = new AclImpl(parentOid1, new Long(2), strategy, auditLogger, null, null, true,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl parentAcl2 = new AclImpl(parentOid2, new Long(3), strategy, auditLogger, null, null, true,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl childAcl1 = new AclImpl(childOid1, new Long(4), strategy, auditLogger, null, null, true,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl childAcl2 = new AclImpl(childOid2, new Long(4), strategy, auditLogger, null, null, false,
|
||||
new PrincipalSid("johndoe"));
|
||||
|
||||
// Create hierarchies
|
||||
childAcl2.setParent(childAcl1);
|
||||
childAcl1.setParent(parentAcl1);
|
||||
parentAcl2.setParent(grandParentAcl);
|
||||
parentAcl1.setParent(grandParentAcl);
|
||||
|
||||
// Add some permissions
|
||||
grandParentAcl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
grandParentAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid("ben"), true);
|
||||
grandParentAcl.insertAce(2, BasePermission.DELETE, new PrincipalSid("ben"), false);
|
||||
grandParentAcl.insertAce(3, BasePermission.DELETE, new PrincipalSid("scott"), true);
|
||||
parentAcl1.insertAce(0, BasePermission.READ, new PrincipalSid("scott"), true);
|
||||
parentAcl1.insertAce(1, BasePermission.DELETE, new PrincipalSid("scott"), false);
|
||||
parentAcl2.insertAce(0, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
childAcl1.insertAce(0, BasePermission.CREATE, new PrincipalSid("scott"), true);
|
||||
|
||||
// Check granting process for parent1
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new PrincipalSid("scott") },
|
||||
false));
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new GrantedAuthoritySid(
|
||||
"ROLE_USER_READ") }, false));
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertFalse(parentAcl1.isGranted(new Permission[] { BasePermission.DELETE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertFalse(parentAcl1.isGranted(new Permission[] { BasePermission.DELETE },
|
||||
new Sid[] { new PrincipalSid("scott") }, false));
|
||||
|
||||
// Check granting process for parent2
|
||||
assertTrue(parentAcl2.isGranted(new Permission[] { BasePermission.CREATE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertTrue(parentAcl2.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertFalse(parentAcl2.isGranted(new Permission[] { BasePermission.DELETE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
|
||||
// Check granting process for child1
|
||||
assertTrue(childAcl1.isGranted(new Permission[] { BasePermission.CREATE }, new Sid[] { new PrincipalSid("scott") },
|
||||
false));
|
||||
assertTrue(childAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new GrantedAuthoritySid(
|
||||
"ROLE_USER_READ") }, false));
|
||||
assertFalse(childAcl1.isGranted(new Permission[] { BasePermission.DELETE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
|
||||
// Check granting process for child2 (doesn't inherit the permissions from its parent)
|
||||
try {
|
||||
assertTrue(childAcl2.isGranted(new Permission[] { BasePermission.CREATE },
|
||||
new Sid[] { new PrincipalSid("scott") }, false));
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
assertTrue(childAcl2.isGranted(new Permission[] { BasePermission.CREATE }, new Sid[] { new PrincipalSid(
|
||||
"johndoe") }, false));
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testUpdateAce() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, false, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(2, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.WRITE);
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.CREATE);
|
||||
|
||||
// Change each permission
|
||||
acl.updateAce(0, BasePermission.CREATE);
|
||||
acl.updateAce(1, BasePermission.DELETE);
|
||||
acl.updateAce(2, BasePermission.READ);
|
||||
|
||||
// Check the change was successfuly made
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.CREATE);
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.DELETE);
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.READ);
|
||||
}
|
||||
|
||||
public void testUpdateAuditing() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_AUDITING"), new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, false, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditFailure());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditFailure());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditSuccess());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditSuccess());
|
||||
|
||||
// Change each permission
|
||||
((AuditableAcl) acl).updateAuditing(0, true, true);
|
||||
((AuditableAcl) acl).updateAuditing(1, true, true);
|
||||
|
||||
// Check the change was successfuly made
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditSuccess());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditSuccess());
|
||||
}
|
||||
|
||||
public void testGettersSetters() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GENERAL"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MutableAcl parentAcl = new AclImpl(identity2, new Long(2), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertEquals(acl.getId(), new Long(1));
|
||||
assertEquals(acl.getObjectIdentity(), identity);
|
||||
assertEquals(acl.getOwner(), new PrincipalSid("johndoe"));
|
||||
assertNull(acl.getParentAcl());
|
||||
assertTrue(acl.isEntriesInheriting());
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
assertEquals(acl.getParentAcl(), parentAcl);
|
||||
|
||||
acl.setEntriesInheriting(false);
|
||||
assertFalse(acl.isEntriesInheriting());
|
||||
|
||||
((OwnershipAcl) acl).setOwner(new PrincipalSid("ben"));
|
||||
assertEquals(acl.getOwner(), new PrincipalSid("ben"));
|
||||
}
|
||||
|
||||
public void testIsSidLoaded() throws Exception {
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GENERAL"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
Sid[] loadedSids = new Sid[] { new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_IGNORED") };
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, loadedSids, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
||||
assertTrue(acl.isSidLoaded(loadedSids));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED"), new PrincipalSid("ben") }));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED")}));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new PrincipalSid("ben") }));
|
||||
assertTrue(acl.isSidLoaded(null));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { }));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_IGNORED") }));
|
||||
assertFalse(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_GENERAL"), new GrantedAuthoritySid("ROLE_IGNORED") }));
|
||||
assertFalse(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_GENERAL") }));
|
||||
}
|
||||
|
||||
// ~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAclService implements MutableAclService {
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
|
||||
}
|
||||
|
||||
/*
|
||||
* Mock implementation that populates the aces list with fully initialized AccessControlEntries
|
||||
* @see org.springframework.security.acls.MutableAclService#updateAcl(org.springframework.security.acls.MutableAcl)
|
||||
*/
|
||||
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
||||
AccessControlEntry[] oldAces = acl.getEntries();
|
||||
Field acesField = FieldUtils.getField(AclImpl.class, "aces");
|
||||
acesField.setAccessible(true);
|
||||
List newAces;
|
||||
try {
|
||||
newAces = (List) acesField.get(acl);
|
||||
newAces.clear();
|
||||
|
||||
for (int i = 0; i < oldAces.length; i++) {
|
||||
AccessControlEntry ac = oldAces[i];
|
||||
// Just give an ID to all this acl's aces, rest of the fields are just copied
|
||||
newAces.add(new AccessControlEntryImpl(new Long(i + 1), ac.getAcl(), ac.getSid(), ac.getPermission(), ac
|
||||
.isGranting(), ((AuditableAccessControlEntry) ac).isAuditSuccess(),
|
||||
((AuditableAccessControlEntry) ac).isAuditFailure()));
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object, Sid[] sids) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
-296
@@ -1,296 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
|
||||
/**
|
||||
* Test class for {@link AclAuthorizationStrategyImpl} and {@link AclImpl}
|
||||
* security checks.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void testSecurityCheckNoACEs() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
// Create another authorization strategy
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_THREE") });
|
||||
Acl acl2 = new AclImpl(identity, new Long(1), aclAuthorizationStrategy2, new ConsoleAuditLogger());
|
||||
// Check access in case the principal has no authorization rights
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecurityCheckWithMultipleACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
// Let's give the principal the ADMINISTRATION permission, without
|
||||
// granting access
|
||||
MutableAcl aclFirstDeny = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
aclFirstDeny.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
|
||||
// The CHANGE_GENERAL test should pass as the principal has ROLE_GENERAL
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
// The CHANGE_AUDITING and CHANGE_OWNERSHIP should fail since the
|
||||
// principal doesn't have these authorities,
|
||||
// nor granting access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Add granting access to this principal
|
||||
aclFirstDeny.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
// and try again for CHANGE_AUDITING - the first ACE's granting flag
|
||||
// (false) will deny this access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Create another ACL and give the principal the ADMINISTRATION
|
||||
// permission, with granting access
|
||||
MutableAcl aclFirstAllow = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
aclFirstAllow.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
|
||||
// The CHANGE_AUDITING test should pass as there is one ACE with
|
||||
// granting access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
// Add a deny ACE and test again for CHANGE_AUDITING
|
||||
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
// Create an ACL with no ACE
|
||||
MutableAcl aclNoACE = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
// and still grant access for CHANGE_GENERAL
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecurityCheckWithInheritableACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
// Let's give the principal an ADMINISTRATION permission, with granting
|
||||
// access
|
||||
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
MutableAcl childAcl = new AclImpl(identity, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Check against the 'child' acl, which doesn't offer any authorization
|
||||
// rights on CHANGE_OWNERSHIP
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Link the child with its parent and test again against the
|
||||
// CHANGE_OWNERSHIP right
|
||||
childAcl.setParent(parentAcl);
|
||||
childAcl.setEntriesInheriting(true);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
|
||||
// Create a root parent and link it to the middle parent
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
rootParentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
parentAcl.setEntriesInheriting(true);
|
||||
parentAcl.setParent(rootParentAcl);
|
||||
childAcl.setParent(parentAcl);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecurityCheckPrincipalOwner() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_ONE"),
|
||||
new GrantedAuthorityImpl("ROLE_ONE") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
|
||||
false, new PrincipalSid(auth));
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
/**
|
||||
* Test class for {@link ConsoleAuditLogger}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AuditLoggerTests extends TestCase {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private PrintStream console;
|
||||
|
||||
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void setUp() throws Exception {
|
||||
console = System.out;
|
||||
System.setOut(new PrintStream(bytes));
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
System.setOut(console);
|
||||
}
|
||||
|
||||
public void testLoggingTests() throws Exception {
|
||||
ConsoleAuditLogger logger = new ConsoleAuditLogger();
|
||||
MockAccessControlEntryImpl auditableAccessControlEntry = new MockAccessControlEntryImpl();
|
||||
|
||||
logger.logIfNeeded(true, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.size() == 0);
|
||||
|
||||
bytes.reset();
|
||||
logger.logIfNeeded(false, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.size() == 0);
|
||||
|
||||
auditableAccessControlEntry.setAuditSuccess(true);
|
||||
bytes.reset();
|
||||
|
||||
logger.logIfNeeded(true, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.toString().length() > 0);
|
||||
Assert.assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
|
||||
|
||||
auditableAccessControlEntry.setAuditFailure(true);
|
||||
bytes.reset();
|
||||
|
||||
logger.logIfNeeded(false, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.toString().length() > 0);
|
||||
Assert.assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
|
||||
|
||||
MockAccessControlEntry accessControlEntry = new MockAccessControlEntry();
|
||||
bytes.reset();
|
||||
logger.logIfNeeded(true, accessControlEntry);
|
||||
Assert.assertTrue(bytes.size() == 0);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAccessControlEntryImpl implements AuditableAccessControlEntry {
|
||||
private boolean auditFailure = false;
|
||||
|
||||
private boolean auditSuccess = false;
|
||||
|
||||
public boolean isAuditFailure() {
|
||||
return auditFailure;
|
||||
}
|
||||
|
||||
public boolean isAuditSuccess() {
|
||||
return auditSuccess;
|
||||
}
|
||||
|
||||
public Acl getAcl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Permission getPermission() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sid getSid() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isGranting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setAuditFailure(boolean auditFailure) {
|
||||
this.auditFailure = auditFailure;
|
||||
}
|
||||
|
||||
public void setAuditSuccess(boolean auditSuccess) {
|
||||
this.auditSuccess = auditSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockAccessControlEntry implements AccessControlEntry {
|
||||
|
||||
public Acl getAcl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Permission getPermission() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sid getSid() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isGranting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/* 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 org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* Tests BasePermission and CumulativePermission.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id${date}
|
||||
*/
|
||||
public class PermissionTests {
|
||||
private static final Log LOGGER = LogFactory.getLog(PermissionTests.class);
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void expectedIntegerValues() {
|
||||
assertEquals(1, BasePermission.READ.getMask());
|
||||
assertEquals(16, BasePermission.ADMINISTRATION.getMask());
|
||||
assertEquals(7,
|
||||
new CumulativePermission().set(BasePermission.READ).set(BasePermission.WRITE).set(BasePermission.CREATE)
|
||||
.getMask());
|
||||
assertEquals(17,
|
||||
new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION).getMask());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromInteger() {
|
||||
Permission permission = BasePermission.buildFromMask(7);
|
||||
System.out.println("7 = " + permission.toString());
|
||||
permission = BasePermission.buildFromMask(4);
|
||||
System.out.println("4 = " + permission.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringConversion() {
|
||||
System.out.println("R = " + BasePermission.READ.toString());
|
||||
assertEquals("BasePermission[...............................R=1]", BasePermission.READ.toString());
|
||||
|
||||
System.out.println("A = " + BasePermission.ADMINISTRATION.toString());
|
||||
assertEquals("BasePermission[...........................A....=16]", BasePermission.ADMINISTRATION.toString());
|
||||
|
||||
System.out.println("R = " + new CumulativePermission().set(BasePermission.READ).toString());
|
||||
assertEquals("CumulativePermission[...............................R=1]",
|
||||
new CumulativePermission().set(BasePermission.READ).toString());
|
||||
|
||||
System.out.println("A = " + new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
|
||||
assertEquals("CumulativePermission[...........................A....=16]",
|
||||
new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
|
||||
|
||||
System.out.println("RA = "
|
||||
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
|
||||
assertEquals("CumulativePermission[...........................A...R=17]",
|
||||
new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
|
||||
|
||||
System.out.println("R = "
|
||||
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
|
||||
.clear(BasePermission.ADMINISTRATION).toString());
|
||||
assertEquals("CumulativePermission[...............................R=1]",
|
||||
new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
|
||||
.clear(BasePermission.ADMINISTRATION).toString());
|
||||
|
||||
System.out.println("0 = "
|
||||
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
|
||||
.clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString());
|
||||
assertEquals("CumulativePermission[................................=0]",
|
||||
new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
|
||||
.clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString());
|
||||
}
|
||||
}
|
||||
-209
@@ -1,209 +0,0 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
import org.springframework.cache.ehcache.EhCacheFactoryBean;
|
||||
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
|
||||
public class AclPermissionInheritanceTests extends TestCase {
|
||||
|
||||
private JdbcMutableAclService aclService;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
private DriverManagerDataSource dataSource;
|
||||
private DataSourceTransactionManager txManager;
|
||||
private TransactionStatus txStatus;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
|
||||
dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:permissiontest");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
|
||||
txManager = new DataSourceTransactionManager();
|
||||
txManager.setDataSource(dataSource);
|
||||
|
||||
txStatus = txManager.getTransaction(new DefaultTransactionDefinition());
|
||||
|
||||
aclService = createAclService(dataSource);
|
||||
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(
|
||||
"system", "secret", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_IGNORED")});
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
txManager.rollback(txStatus);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void test1() throws Exception {
|
||||
|
||||
createAclSchema(jdbcTemplate);
|
||||
|
||||
ObjectIdentityImpl rootObject =
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
|
||||
|
||||
MutableAcl parent = aclService.createAcl(rootObject);
|
||||
MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
child.setParent(parent);
|
||||
aclService.updateAcl(child);
|
||||
|
||||
parent = (AclImpl) aclService.readAclById(rootObject);
|
||||
parent.insertAce(0, BasePermission.READ,
|
||||
new PrincipalSid("john"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
parent = (AclImpl) aclService.readAclById(rootObject);
|
||||
parent.insertAce(1, BasePermission.READ,
|
||||
new PrincipalSid("joe"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) aclService.readAclById(
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals("Fails because child has a stale reference to its parent",
|
||||
2, parent.getEntries().length);
|
||||
assertEquals(1, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("john"), parent.getEntries()[0].getSid());
|
||||
assertEquals(1, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("joe"), parent.getEntries()[1].getSid());
|
||||
|
||||
}
|
||||
public void test2() throws Exception {
|
||||
|
||||
createAclSchema(jdbcTemplate);
|
||||
|
||||
ObjectIdentityImpl rootObject =
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
|
||||
|
||||
MutableAcl parent = aclService.createAcl(rootObject);
|
||||
MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
child.setParent(parent);
|
||||
aclService.updateAcl(child);
|
||||
|
||||
parent.insertAce(0, BasePermission.ADMINISTRATION,
|
||||
new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
parent.insertAce(1, BasePermission.DELETE, new PrincipalSid("terry"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) aclService.readAclById(
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals(2, parent.getEntries().length);
|
||||
assertEquals(16, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries()[0].getSid());
|
||||
assertEquals(8, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("terry"), parent.getEntries()[1].getSid());
|
||||
|
||||
}
|
||||
|
||||
private JdbcMutableAclService createAclService(DriverManagerDataSource ds)
|
||||
throws IOException {
|
||||
|
||||
GrantedAuthorityImpl adminAuthority = new GrantedAuthorityImpl("ROLE_ADMINISTRATOR");
|
||||
AclAuthorizationStrategyImpl authStrategy = new AclAuthorizationStrategyImpl(
|
||||
new GrantedAuthorityImpl[]{adminAuthority,adminAuthority,adminAuthority});
|
||||
|
||||
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
|
||||
ehCacheManagerFactoryBean.afterPropertiesSet();
|
||||
CacheManager cacheManager = (CacheManager) ehCacheManagerFactoryBean.getObject();
|
||||
|
||||
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
|
||||
ehCacheFactoryBean.setCacheName("aclAche");
|
||||
ehCacheFactoryBean.setCacheManager(cacheManager);
|
||||
ehCacheFactoryBean.afterPropertiesSet();
|
||||
Ehcache ehCache = (Ehcache) ehCacheFactoryBean.getObject();
|
||||
|
||||
AclCache aclAche = new EhCacheBasedAclCache(ehCache);
|
||||
|
||||
BasicLookupStrategy lookupStrategy =
|
||||
new BasicLookupStrategy(ds, aclAche, authStrategy, new ConsoleAuditLogger());
|
||||
|
||||
return new JdbcMutableAclService(ds,lookupStrategy, aclAche);
|
||||
}
|
||||
|
||||
private void createAclSchema(JdbcTemplate jdbcTemplate) {
|
||||
|
||||
jdbcTemplate.execute("DROP TABLE ACL_ENTRY IF EXISTS;");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_OBJECT_IDENTITY IF EXISTS;");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_CLASS IF EXISTS");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_SID IF EXISTS");
|
||||
|
||||
jdbcTemplate.execute(
|
||||
"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));");
|
||||
jdbcTemplate.execute(
|
||||
"CREATE TABLE ACL_CLASS(" +
|
||||
"ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
|
||||
"CLASS VARCHAR_IGNORECASE(100) NOT NULL," +
|
||||
"CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
||||
jdbcTemplate.execute(
|
||||
"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 BIGINT 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));");
|
||||
jdbcTemplate.execute(
|
||||
"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));");
|
||||
}
|
||||
|
||||
public static class TestDomainObject {
|
||||
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
-310
@@ -1,310 +0,0 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.TestDataSource;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link BasicLookupStrategy}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class BasicLookupStrategyTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private static JdbcTemplate jdbcTemplate;
|
||||
|
||||
private LookupStrategy strategy;
|
||||
|
||||
private static TestDataSource dataSource;
|
||||
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new CacheManager();
|
||||
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void createDatabase() throws Exception {
|
||||
dataSource = new TestDataSource("lookupstrategytest");
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
|
||||
Resource resource = new ClassPathResource("org/springframework/security/acls/jdbc/testData.sql");
|
||||
String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
|
||||
jdbcTemplate.execute(sql);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void dropDatabase() throws Exception {
|
||||
dataSource.destroy();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownCacheManager() {
|
||||
cacheManager.removalAll();
|
||||
cacheManager.shutdown();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void populateDatabase() {
|
||||
String query = "INSERT INTO acl_sid(ID,PRINCIPAL,SID) VALUES (1,1,'ben');"
|
||||
+ "INSERT INTO acl_class(ID,CLASS) VALUES (2,'org.springframework.security.TargetObject');"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (1,2,100,null,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (2,2,101,1,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (3,2,102,2,1,1);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (1,1,0,1,1,1,0,0);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (2,1,1,1,2,0,0,0);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (3,2,0,1,8,1,0,0);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (4,3,0,1,8,0,0,0);";
|
||||
jdbcTemplate.execute(query);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initializeBeans() {
|
||||
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
|
||||
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"), new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"),
|
||||
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy, new ConsoleAuditLogger());
|
||||
}
|
||||
|
||||
@After
|
||||
public void emptyDatabase() {
|
||||
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 7;"
|
||||
+ "DELETE FROM acl_object_identity WHERE ID = 6;" + "DELETE FROM acl_object_identity WHERE ID = 5;"
|
||||
+ "DELETE FROM acl_object_identity WHERE ID = 4;" + "DELETE FROM acl_object_identity WHERE ID = 3;"
|
||||
+ "DELETE FROM acl_object_identity WHERE ID = 2;" + "DELETE FROM acl_object_identity WHERE ID = 1;"
|
||||
+ "DELETE FROM acl_class;" + "DELETE FROM acl_sid;";
|
||||
jdbcTemplate.execute(query);
|
||||
}
|
||||
|
||||
private Ehcache getCache() {
|
||||
Ehcache cache = cacheManager.getCache("basiclookuptestcache");
|
||||
cache.removeAll();
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Objects were put in cache
|
||||
strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
|
||||
// Let's empty the database to force acls retrieval from cache
|
||||
emptyDatabase();
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Set a batch size to allow multiple database queries in order to retrieve all acls
|
||||
((BasicLookupStrategy) this.strategy).setBatchSize(1);
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
|
||||
private void checkEntries(ObjectIdentity topParentOid, ObjectIdentity middleParentOid, ObjectIdentity childOid, Map map)
|
||||
throws Exception {
|
||||
Assert.assertEquals(3, map.size());
|
||||
|
||||
MutableAcl topParent = (MutableAcl) map.get(topParentOid);
|
||||
MutableAcl middleParent = (MutableAcl) map.get(middleParentOid);
|
||||
MutableAcl child = (MutableAcl) map.get(childOid);
|
||||
|
||||
// Check the retrieved versions has IDs
|
||||
Assert.assertNotNull(topParent.getId());
|
||||
Assert.assertNotNull(middleParent.getId());
|
||||
Assert.assertNotNull(child.getId());
|
||||
|
||||
// Check their parents were correctly retrieved
|
||||
Assert.assertNull(topParent.getParentAcl());
|
||||
Assert.assertEquals(topParentOid, middleParent.getParentAcl().getObjectIdentity());
|
||||
Assert.assertEquals(middleParentOid, child.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Check their ACEs were correctly retrieved
|
||||
Assert.assertEquals(2, topParent.getEntries().length);
|
||||
Assert.assertEquals(1, middleParent.getEntries().length);
|
||||
Assert.assertEquals(1, child.getEntries().length);
|
||||
|
||||
// Check object identities were correctly retrieved
|
||||
Assert.assertEquals(topParentOid, topParent.getObjectIdentity());
|
||||
Assert.assertEquals(middleParentOid, middleParent.getObjectIdentity());
|
||||
Assert.assertEquals(childOid, child.getObjectIdentity());
|
||||
|
||||
// Check each entry
|
||||
Assert.assertTrue(topParent.isEntriesInheriting());
|
||||
Assert.assertEquals(topParent.getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(topParent.getEntries()[0].getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
Assert.assertEquals(topParent.getEntries()[0].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[0]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[0]).isAuditSuccess());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) topParent.getEntries()[0]).isGranting());
|
||||
|
||||
Assert.assertEquals(topParent.getEntries()[1].getId(), new Long(2));
|
||||
Assert.assertEquals(topParent.getEntries()[1].getPermission(), BasePermission.WRITE);
|
||||
Assert.assertEquals(topParent.getEntries()[1].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[1]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[1]).isAuditSuccess());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[1]).isGranting());
|
||||
|
||||
Assert.assertTrue(middleParent.isEntriesInheriting());
|
||||
Assert.assertEquals(middleParent.getId(), new Long(2));
|
||||
Assert.assertEquals(middleParent.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(middleParent.getEntries()[0].getId(), new Long(3));
|
||||
Assert.assertEquals(middleParent.getEntries()[0].getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(middleParent.getEntries()[0].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries()[0]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries()[0]).isAuditSuccess());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) middleParent.getEntries()[0]).isGranting());
|
||||
|
||||
Assert.assertTrue(child.isEntriesInheriting());
|
||||
Assert.assertEquals(child.getId(), new Long(3));
|
||||
Assert.assertEquals(child.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(child.getEntries()[0].getId(), new Long(4));
|
||||
Assert.assertEquals(child.getEntries()[0].getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(child.getEntries()[0].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries()[0]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries()[0]).isAuditSuccess());
|
||||
Assert.assertFalse((child.getEntries()[0]).isGranting());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllParentsAreRetrievedWhenChildIsLoaded() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,103,1,1,1);";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
|
||||
|
||||
// Retrieve the child
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { childOid }, null);
|
||||
|
||||
// Check that the child and all its parents were retrieved
|
||||
Assert.assertNotNull(map.get(childOid));
|
||||
Assert.assertEquals(childOid, ((Acl) map.get(childOid)).getObjectIdentity());
|
||||
Assert.assertNotNull(map.get(middleParentOid));
|
||||
Assert.assertEquals(middleParentOid, ((Acl) map.get(middleParentOid)).getObjectIdentity());
|
||||
Assert.assertNotNull(map.get(topParentOid));
|
||||
Assert.assertEquals(topParentOid, ((Acl) map.get(topParentOid)).getObjectIdentity());
|
||||
|
||||
// The second parent shouldn't have been retrieved
|
||||
Assert.assertNull(map.get(middleParent2Oid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test created from SEC-590.
|
||||
*/
|
||||
@Test
|
||||
public void testReadAllObjectIdentitiesWhenLastElementIsAlreadyCached() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (5,2,105,4,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (6,2,106,4,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (7,2,107,5,1,1);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(107));
|
||||
|
||||
// First lookup only child, thus populating the cache with grandParent, parent1 and child
|
||||
Permission[] checkPermission = new Permission[] { BasePermission.READ };
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben") };
|
||||
ObjectIdentity[] childOids = new ObjectIdentity[] { childOid };
|
||||
|
||||
((BasicLookupStrategy) this.strategy).setBatchSize(6);
|
||||
Map foundAcls = strategy.readAclsById(childOids, sids);
|
||||
|
||||
Acl foundChildAcl = (Acl) foundAcls.get(childOid);
|
||||
Assert.assertNotNull(foundChildAcl);
|
||||
Assert.assertTrue(foundChildAcl.isGranted(checkPermission, sids, false));
|
||||
|
||||
// Search for object identities has to be done in the following order: last element have to be one which
|
||||
// is already in cache and the element before it must not be stored in cache
|
||||
ObjectIdentity[] allOids = new ObjectIdentity[] { grandParentOid, parent1Oid, parent2Oid, childOid };
|
||||
try {
|
||||
foundAcls = strategy.readAclsById(allOids, sids);
|
||||
Assert.assertTrue(true);
|
||||
} catch (NotFoundException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
|
||||
Acl foundParent2Acl = (Acl) foundAcls.get(parent2Oid);
|
||||
Assert.assertNotNull(foundParent2Acl);
|
||||
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsWithDifferentSerializableTypesAsObjectIdentities() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(104));
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben") };
|
||||
ObjectIdentity[] childOids = new ObjectIdentity[] { oid };
|
||||
|
||||
try {
|
||||
Map foundAcls = strategy.readAclsById(childOids, sids);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
} catch(IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Seeds the database for {@link JdbcAclServiceTests}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DatabaseSeeder {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public DatabaseSeeder(DataSource dataSource, Resource resource) throws IOException {
|
||||
Assert.notNull(dataSource, "dataSource required");
|
||||
Assert.notNull(resource, "resource required");
|
||||
|
||||
JdbcTemplate template = new JdbcTemplate(dataSource);
|
||||
String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
|
||||
template.execute(sql);
|
||||
}
|
||||
}
|
||||
-248
@@ -1,248 +0,0 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedAclCache}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class EhCacheBasedAclCacheTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new CacheManager();
|
||||
// Use disk caching immediately (to test for serialization issue reported in SEC-527)
|
||||
cacheManager.addCache(new Cache("ehcachebasedacltests", 0, true, false, 30, 30));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownCacheManager() {
|
||||
cacheManager.removalAll();
|
||||
cacheManager.shutdown();
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private Ehcache getCache() {
|
||||
Ehcache cache = cacheManager.getCache("ehcachebasedacltests");
|
||||
cache.removeAll();
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorRejectsNullParameters() throws Exception {
|
||||
AclCache aclCache = new EhCacheBasedAclCache(null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodsRejectNullParameters() throws Exception {
|
||||
Ehcache cache = new MockEhcache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
try {
|
||||
Serializable id = null;
|
||||
myCache.evictFromCache(id);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
ObjectIdentity obj = null;
|
||||
myCache.evictFromCache(obj);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Serializable id = null;
|
||||
myCache.getFromCache(id);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
ObjectIdentity obj = null;
|
||||
myCache.getFromCache(obj);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
MutableAcl acl = null;
|
||||
myCache.putInCache(acl);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-527
|
||||
@Test
|
||||
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Serialization test
|
||||
File file = File.createTempFile("SEC_TEST", ".object");
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
||||
oos.writeObject(acl);
|
||||
oos.close();
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ObjectInputStream ois = new ObjectInputStream(fis);
|
||||
MutableAcl retrieved = (MutableAcl) ois.readObject();
|
||||
ois.close();
|
||||
|
||||
assertEquals(acl, retrieved);
|
||||
|
||||
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
|
||||
assertEquals(null, retrieved1);
|
||||
|
||||
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
|
||||
assertEquals(null, retrieved2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheOperationsAclWithoutParent() throws Exception {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
|
||||
// Put another object in cache
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
MutableAcl acl2 = new AclImpl(identity2, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
myCache.putInCache(acl2);
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
// Try to evict an entry that doesn't exist
|
||||
myCache.evictFromCache(new Long(3));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102)));
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
myCache.evictFromCache(new Long(1));
|
||||
assertEquals(cache.getSize(), 2);
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
|
||||
// Check the second object inserted
|
||||
assertEquals(myCache.getFromCache(new Long(2)), acl2);
|
||||
assertEquals(myCache.getFromCache(identity2), acl2);
|
||||
|
||||
myCache.evictFromCache(identity2);
|
||||
assertEquals(cache.getSize(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheOperationsAclWithParent() throws Exception {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity identityParent = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
MutableAcl parentAcl = new AclImpl(identityParent, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
myCache.putInCache(acl);
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
assertEquals(myCache.getFromCache(new Long(2)), parentAcl);
|
||||
assertEquals(myCache.getFromCache(identityParent), parentAcl);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockEhcache extends Cache {
|
||||
public MockEhcache() {
|
||||
super("cache", 0, true, true, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
/* 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.jdbc;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
|
||||
|
||||
|
||||
/**
|
||||
* Integration tests the ACL system using an in-memory database.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Andrei Stefan
|
||||
* @version $Id:JdbcAclServiceTests.java 1754 2006-11-17 02:01:21Z benalex $
|
||||
*/
|
||||
public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringContextTests {
|
||||
//~ Constant fields ================================================================================================
|
||||
|
||||
public static final String SELECT_ALL_CLASSES = "SELECT * FROM acl_class WHERE class = ?";
|
||||
|
||||
public static final String SELECT_ALL_OBJECT_IDENTITIES = "SELECT * FROM acl_object_identity";
|
||||
|
||||
public static final String SELECT_OBJECT_IDENTITY = "SELECT * FROM acl_object_identity WHERE object_id_identity = ?";
|
||||
|
||||
public static final String SELECT_ACL_ENTRY = "SELECT * FROM acl_entry, acl_object_identity WHERE " +
|
||||
"acl_object_identity.id = acl_entry.acl_object_identity " +
|
||||
"AND acl_object_identity.object_id_identity <= ?";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private JdbcMutableAclService jdbcMutableAclService;
|
||||
|
||||
private AclCache aclCache;
|
||||
|
||||
private LookupStrategy lookupStrategy;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
return new String[] {"classpath:org/springframework/security/acls/jdbc/applicationContext-test.xml"};
|
||||
}
|
||||
|
||||
public void setJdbcMutableAclService(JdbcMutableAclService jdbcAclService) {
|
||||
this.jdbcMutableAclService = jdbcAclService;
|
||||
}
|
||||
|
||||
public void setAclCache(AclCache aclCache) {
|
||||
this.aclCache = aclCache;
|
||||
}
|
||||
|
||||
public void setLookupStrategy(LookupStrategy lookupStrategy) {
|
||||
this.lookupStrategy = lookupStrategy;
|
||||
}
|
||||
|
||||
protected void onTearDown() throws Exception {
|
||||
super.onTearDown();
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void testLifecycle() {
|
||||
setComplete();
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
|
||||
// Specify the inheritence hierarchy
|
||||
middleParent.setParent(topParent);
|
||||
child.setParent(middleParent);
|
||||
|
||||
// Now let's add a couple of permissions
|
||||
topParent.insertAce(0, BasePermission.READ, new PrincipalSid(auth), true);
|
||||
topParent.insertAce(1, BasePermission.WRITE, new PrincipalSid(auth), false);
|
||||
middleParent.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
||||
|
||||
// Explictly save the changed ACL
|
||||
jdbcMutableAclService.updateAcl(topParent);
|
||||
jdbcMutableAclService.updateAcl(middleParent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
// Let's check if we can read them back correctly
|
||||
Map map = jdbcMutableAclService.readAclsById(new ObjectIdentity[] {topParentOid, middleParentOid, childOid});
|
||||
assertEquals(3, map.size());
|
||||
|
||||
// Replace our current objects with their retrieved versions
|
||||
topParent = (MutableAcl) map.get(topParentOid);
|
||||
middleParent = (MutableAcl) map.get(middleParentOid);
|
||||
child = (MutableAcl) map.get(childOid);
|
||||
|
||||
// Check the retrieved versions has IDs
|
||||
assertNotNull(topParent.getId());
|
||||
assertNotNull(middleParent.getId());
|
||||
assertNotNull(child.getId());
|
||||
|
||||
// Check their parents were correctly persisted
|
||||
assertNull(topParent.getParentAcl());
|
||||
assertEquals(topParentOid, middleParent.getParentAcl().getObjectIdentity());
|
||||
assertEquals(middleParentOid, child.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Check their ACEs were correctly persisted
|
||||
assertEquals(2, topParent.getEntries().length);
|
||||
assertEquals(1, middleParent.getEntries().length);
|
||||
assertEquals(1, child.getEntries().length);
|
||||
|
||||
// Check the retrieved rights are correct
|
||||
assertTrue(topParent.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(topParent.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertTrue(middleParent.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
|
||||
try {
|
||||
child.isGranted(new Permission[] {BasePermission.ADMINISTRATION}, new Sid[] {new PrincipalSid(auth)}, false);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
// Now check the inherited rights (when not explicitly overridden) also look OK
|
||||
assertTrue(child.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
|
||||
// Next change the child so it doesn't inherit permissions from above
|
||||
child.setEntriesInheriting(false);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
assertFalse(child.isEntriesInheriting());
|
||||
|
||||
// Check the child permissions no longer inherit
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, true));
|
||||
|
||||
try {
|
||||
child.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, true);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
child.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, true);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
// Let's add an identical permission to the child, but it'll appear AFTER the current permission, so has no impact
|
||||
child.insertAce(1, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
|
||||
// Let's also add another permission to the child
|
||||
child.insertAce(2, BasePermission.CREATE, new PrincipalSid(auth), true);
|
||||
|
||||
// Save the changed child
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
assertEquals(3, child.getEntries().length);
|
||||
|
||||
// Output permissions
|
||||
for (int i = 0; i < child.getEntries().length; i++) {
|
||||
System.out.println(child.getEntries()[i]);
|
||||
}
|
||||
|
||||
// Check the permissions are as they should be
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, true)); // as earlier permission overrode
|
||||
assertTrue(child.isGranted(new Permission[] {BasePermission.CREATE}, new Sid[] {new PrincipalSid(auth)}, true));
|
||||
|
||||
// Now check the first ACE (index 0) really is DELETE for our Sid and is non-granting
|
||||
AccessControlEntry entry = child.getEntries()[0];
|
||||
assertEquals(BasePermission.DELETE.getMask(), entry.getPermission().getMask());
|
||||
assertEquals(new PrincipalSid(auth), entry.getSid());
|
||||
assertFalse(entry.isGranting());
|
||||
assertNotNull(entry.getId());
|
||||
|
||||
// Now delete that first ACE
|
||||
child.deleteAce(0);
|
||||
|
||||
// Save and check it worked
|
||||
child = jdbcMutableAclService.updateAcl(child);
|
||||
assertEquals(2, child.getEntries().length);
|
||||
assertTrue(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method that demonstrates eviction failure from cache - SEC-676
|
||||
*/
|
||||
public void testDeleteAclAlsoDeletesChildren() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Check the childOid really is a child of middleParentOid
|
||||
Acl childAcl = jdbcMutableAclService.readAclById(childOid);
|
||||
assertEquals(middleParentOid, childAcl.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Delete the mid-parent and test if the child was deleted, as well
|
||||
jdbcMutableAclService.deleteAcl(middleParentOid, true);
|
||||
|
||||
try {
|
||||
Acl acl = jdbcMutableAclService.readAclById(middleParentOid);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = jdbcMutableAclService.readAclById(childOid);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
Acl acl = jdbcMutableAclService.readAclById(topParentOid);
|
||||
assertNotNull(acl);
|
||||
assertEquals(((MutableAcl) acl).getObjectIdentity(), topParentOid);
|
||||
}
|
||||
|
||||
public void testConstructorRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
JdbcAclService service = new JdbcMutableAclService(null, lookupStrategy, aclCache);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
JdbcAclService service = new JdbcMutableAclService(this.getJdbcTemplate().getDataSource(), null, aclCache);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
JdbcAclService service = new JdbcMutableAclService(this.getJdbcTemplate().getDataSource(), lookupStrategy, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateAclRejectsNullParameter() throws Exception {
|
||||
try {
|
||||
jdbcMutableAclService.createAcl(null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateAclForADuplicateDomainObject() throws Exception {
|
||||
ObjectIdentity duplicateOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
// Try to add the same object second time
|
||||
try {
|
||||
jdbcMutableAclService.createAcl(duplicateOid);
|
||||
fail("It should have thrown AlreadyExistsException");
|
||||
}
|
||||
catch (AlreadyExistsException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAclRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
jdbcMutableAclService.deleteAcl(null, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAclWithChildrenThrowsException() throws Exception {
|
||||
try {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(false); // switch on FK checking in the class, not database
|
||||
jdbcMutableAclService.deleteAcl(topParentOid, false);
|
||||
fail("It should have thrown ChildrenExistException");
|
||||
}
|
||||
catch (ChildrenExistException expected) {
|
||||
assertTrue(true);
|
||||
} finally {
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(true); // restore to the default
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAclRemovesRowsFromDatabase() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Remove the child and check all related database rows were removed accordingly
|
||||
jdbcMutableAclService.deleteAcl(childOid, false);
|
||||
assertEquals(1, getJdbcTemplate().queryForList(SELECT_ALL_CLASSES, new Object[] {"org.springframework.security.TargetObject"} ).size());
|
||||
assertEquals(0, getJdbcTemplate().queryForList(SELECT_OBJECT_IDENTITY, new Object[] {new Long(102)}).size());
|
||||
assertEquals(2, getJdbcTemplate().queryForList(SELECT_ALL_OBJECT_IDENTITIES).size());
|
||||
assertEquals(3, getJdbcTemplate().queryForList(SELECT_ACL_ENTRY, new Object[] {new Long(103)} ).size());
|
||||
|
||||
// Check the cache
|
||||
assertNull(aclCache.getFromCache(childOid));
|
||||
assertNull(aclCache.getFromCache(new Long(102)));
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-655
|
||||
*/
|
||||
/* public void testClearChildrenFromCacheWhenParentIsUpdated() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity parentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
|
||||
|
||||
MutableAcl parent = jdbcMutableAclService.createAcl(parentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
|
||||
child.setParent(parent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
|
||||
parent.insertAce(null, BasePermission.READ, new PrincipalSid("ben"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
|
||||
parent.insertAce(null, BasePermission.READ, new PrincipalSid("scott"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals("Fails because child has a stale reference to its parent", 2, parent.getEntries().length);
|
||||
assertEquals(1, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("ben"), parent.getEntries()[0].getSid());
|
||||
assertEquals(1, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("scott"), parent.getEntries()[1].getSid());
|
||||
}*/
|
||||
|
||||
/* public void testCumulativePermissions() {
|
||||
setComplete();
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(110));
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
|
||||
// Add an ACE permission entry
|
||||
CumulativePermission cm = new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION);
|
||||
assertEquals(17, cm.getMask());
|
||||
topParent.insertAce(null, cm, new PrincipalSid(auth), true);
|
||||
assertEquals(1, topParent.getEntries().length);
|
||||
|
||||
// Explictly save the changed ACL
|
||||
topParent = jdbcMutableAclService.updateAcl(topParent);
|
||||
|
||||
// Check the mask was retrieved correctly
|
||||
assertEquals(17, topParent.getEntries()[0].getPermission().getMask());
|
||||
assertTrue(topParent.isGranted(new Permission[] {cm}, new Sid[] {new PrincipalSid(auth)}, true));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
*/
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link ObjectIdentityRetrievalStrategyImpl}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class ObjectIdentityRetrievalStrategyImplTests extends TestCase {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testObjectIdentityCreation() throws Exception {
|
||||
MockIdDomainObject domain = new MockIdDomainObject();
|
||||
domain.setId(new Integer(1));
|
||||
|
||||
ObjectIdentityRetrievalStrategy retStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
ObjectIdentity identity = retStrategy.getObjectIdentity(domain);
|
||||
|
||||
assertNotNull(identity);
|
||||
assertEquals(identity, new ObjectIdentityImpl(domain));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
-204
@@ -1,204 +0,0 @@
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ObjectIdentityImpl}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class ObjectIdentityTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testConstructorsRequiredFields() throws Exception {
|
||||
// Check one-argument constructor required field
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check String-Serializable constructor required field
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl("", new Long(1));
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check Serializable parameter is not null
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// The correct way of using String-Serializable constructor
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Long(1));
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
// Check the Class-Serializable constructor
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(MockIdDomainObject.class, null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetIdMethodConstraints() throws Exception {
|
||||
// Check the getId() method is present
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl("A_STRING_OBJECT");
|
||||
Assert.fail("It should have thrown IdentityUnavailableException");
|
||||
}
|
||||
catch (IdentityUnavailableException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// getId() should return a non-null value
|
||||
MockIdDomainObject mockId = new MockIdDomainObject();
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(mockId);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// getId() should return a Serializable object
|
||||
mockId.setId(new MockIdDomainObject());
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(mockId);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// getId() should return a Serializable object
|
||||
mockId.setId(new Long(100));
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(mockId);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructorInvalidClassParameter() throws Exception {
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl("not.a.Class", new Long(1));
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
return;
|
||||
}
|
||||
Assert.fail("It should have thrown IllegalStateException");
|
||||
}
|
||||
|
||||
public void testEquals() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
MockIdDomainObject mockObj = new MockIdDomainObject();
|
||||
mockObj.setId(new Long(1));
|
||||
|
||||
String string = "SOME_STRING";
|
||||
Assert.assertNotSame(obj, string);
|
||||
Assert.assertTrue(!obj.equals(null));
|
||||
Assert.assertTrue(!obj.equals("DIFFERENT_OBJECT_TYPE"));
|
||||
Assert.assertTrue(!obj
|
||||
.equals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Long(2))));
|
||||
Assert.assertTrue(!obj.equals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockOtherIdDomainObject",
|
||||
new Long(1))));
|
||||
Assert.assertEquals(
|
||||
new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Long(1)), obj);
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1))
|
||||
.equals(obj));
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1))
|
||||
.equals(new ObjectIdentityImpl(mockObj)));
|
||||
}
|
||||
|
||||
public void testHashCode() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
Assert.assertEquals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1))
|
||||
.hashCode(), obj.hashCode());
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockOtherIdDomainObject",
|
||||
new Long(1)).hashCode() != obj.hashCode());
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(2))
|
||||
.hashCode() != obj.hashCode());
|
||||
}
|
||||
|
||||
/* public void testHashCodeDifferentSerializableTypes() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
Assert.assertEquals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", "1")
|
||||
.hashCode(), obj.hashCode());
|
||||
Assert.assertEquals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Integer(1)).hashCode(), obj.hashCode());
|
||||
}*/
|
||||
|
||||
public void testGetters() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
Assert.assertEquals(new Long(1), obj.getIdentifier());
|
||||
Assert.assertEquals(MockIdDomainObject.class, obj.getJavaType());
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockOtherIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
|
||||
/**
|
||||
* Tests for {@link SidRetrievalStrategyImpl}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class SidRetrievalStrategyTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testSidsRetrieval() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("scott", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl("ROLE_2"), new GrantedAuthorityImpl("ROLE_3") });
|
||||
SidRetrievalStrategy retrStrategy = new SidRetrievalStrategyImpl();
|
||||
Sid[] sids = retrStrategy.getSids(authentication);
|
||||
|
||||
assertNotNull(sids);
|
||||
assertEquals(4, sids.length);
|
||||
assertNotNull(sids[0]);
|
||||
assertTrue(sids[0] instanceof PrincipalSid);
|
||||
|
||||
for (int i = 1; i < sids.length; i++) {
|
||||
assertTrue(sids[i] instanceof GrantedAuthoritySid);
|
||||
}
|
||||
|
||||
Assert.assertEquals("scott", ((PrincipalSid) sids[0]).getPrincipal());
|
||||
Assert.assertEquals("ROLE_1", ((GrantedAuthoritySid) sids[1]).getGrantedAuthority());
|
||||
Assert.assertEquals("ROLE_2", ((GrantedAuthoritySid) sids[2]).getGrantedAuthority());
|
||||
Assert.assertEquals("ROLE_3", ((GrantedAuthoritySid) sids[3]).getGrantedAuthority());
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
|
||||
public class SidTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testPrincipalSidConstructorsRequiredFields() throws Exception {
|
||||
// Check one String-argument constructor
|
||||
try {
|
||||
String string = null;
|
||||
Sid principalSid = new PrincipalSid(string);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Sid principalSid = new PrincipalSid("");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Sid principalSid = new PrincipalSid("johndoe");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
// Check one Authentication-argument constructor
|
||||
try {
|
||||
Authentication authentication = null;
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken(null, "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidConstructorsRequiredFields() throws Exception {
|
||||
// Check one String-argument constructor
|
||||
try {
|
||||
String string = null;
|
||||
Sid gaSid = new GrantedAuthoritySid(string);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Sid gaSid = new GrantedAuthoritySid("");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
Sid gaSid = new GrantedAuthoritySid("ROLE_TEST");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
// Check one GrantedAuthority-argument constructor
|
||||
try {
|
||||
GrantedAuthority ga = null;
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl(null);
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testPrincipalSidEquals() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertFalse(principalSid.equals(null));
|
||||
Assert.assertFalse(principalSid.equals("DIFFERENT_TYPE_OBJECT"));
|
||||
Assert.assertTrue(principalSid.equals(principalSid));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(authentication)));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null, null))));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null, null))));
|
||||
Assert.assertTrue(principalSid.equals(new PrincipalSid("johndoe")));
|
||||
Assert.assertFalse(principalSid.equals(new PrincipalSid("scott")));
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidEquals() throws Exception {
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
Assert.assertFalse(gaSid.equals(null));
|
||||
Assert.assertFalse(gaSid.equals("DIFFERENT_TYPE_OBJECT"));
|
||||
Assert.assertTrue(gaSid.equals(gaSid));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(ga)));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST"))));
|
||||
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_NOT_EQUAL"))));
|
||||
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid("ROLE_TEST")));
|
||||
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid("ROLE_NOT_EQUAL")));
|
||||
}
|
||||
|
||||
public void testPrincipalSidHashCode() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
|
||||
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
|
||||
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password",
|
||||
null)).hashCode());
|
||||
}
|
||||
|
||||
public void testGrantedAuthoritySidHashCode() throws Exception {
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
Assert.assertTrue(gaSid.hashCode() == new String("ROLE_TEST").hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() == new GrantedAuthoritySid("ROLE_TEST").hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid("ROLE_TEST_2").hashCode());
|
||||
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST_2")).hashCode());
|
||||
}
|
||||
|
||||
public void testGetters() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
|
||||
PrincipalSid principalSid = new PrincipalSid(authentication);
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
|
||||
|
||||
Assert.assertTrue("johndoe".equals(principalSid.getPrincipal()));
|
||||
Assert.assertFalse("scott".equals(principalSid.getPrincipal()));
|
||||
|
||||
Assert.assertTrue("ROLE_TEST".equals(gaSid.getGrantedAuthority()));
|
||||
Assert.assertFalse("ROLE_TEST2".equals(gaSid.getGrantedAuthority()));
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
target
|
||||
@@ -1,5 +0,0 @@
|
||||
target
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.wtpmodules
|
||||
@@ -1,22 +0,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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.2</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-catalina</artifactId>
|
||||
<name>Spring Security - Catalina adapter</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>tomcat</groupId>
|
||||
<artifactId>catalina</artifactId>
|
||||
<version>4.1.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
-236
@@ -1,236 +0,0 @@
|
||||
/* 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.adapters.catalina;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.realm.RealmBase;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.support.FileSystemXmlApplicationContext;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Adapter to enable Catalina (Tomcat) to authenticate via the Spring Security.<p>Returns a {@link
|
||||
* PrincipalSpringSecurityUserToken} to Catalina's authentication system, which is subsequently available via
|
||||
* <code>HttpServletRequest.getUserPrincipal()</code>.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:CatalinaSpringSecurityUserRealm.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class CatalinaSpringSecurityUserRealm extends RealmBase {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CatalinaSpringSecurityUserRealm.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
private Container container;
|
||||
private String appContextLocation;
|
||||
private String key;
|
||||
protected final String name = "CatalinaSpringUserRealm / $Id:CatalinaSpringSecurityUserRealm.java 2151 2007-09-22 11:54:13Z luke_t $";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
if (username == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (credentials == null) {
|
||||
credentials = "";
|
||||
}
|
||||
|
||||
Authentication request = new UsernamePasswordAuthenticationToken(username, credentials);
|
||||
Authentication response = null;
|
||||
|
||||
try {
|
||||
response = authenticationManager.authenticate(request);
|
||||
} catch (AuthenticationException failed) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user: " + username + " failed: " + failed.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PrincipalSpringSecurityUserToken(this.key, response.getPrincipal().toString(),
|
||||
response.getCredentials().toString(), response.getAuthorities(), response.getPrincipal());
|
||||
}
|
||||
|
||||
public Principal authenticate(String username, byte[] credentials) {
|
||||
return authenticate(username, new String(credentials));
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported, returns null
|
||||
*
|
||||
* @param username DOCUMENT ME!
|
||||
* @param digest DOCUMENT ME!
|
||||
* @param nonce DOCUMENT ME!
|
||||
* @param nc DOCUMENT ME!
|
||||
* @param cnonce DOCUMENT ME!
|
||||
* @param qop DOCUMENT ME!
|
||||
* @param realm DOCUMENT ME!
|
||||
* @param md5a2 DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
public java.security.Principal authenticate(java.lang.String username, java.lang.String digest,
|
||||
java.lang.String nonce, java.lang.String nc, java.lang.String cnonce, java.lang.String qop,
|
||||
java.lang.String realm, java.lang.String md5a2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported, returns null
|
||||
*
|
||||
* @param x509Certificates DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
public Principal authenticate(X509Certificate[] x509Certificates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAppContextLocation() {
|
||||
return appContextLocation;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns null (we override authenticate methods)
|
||||
*
|
||||
* @param arg0 DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
protected String getPassword(String arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns null (we override authenticate methods)
|
||||
*
|
||||
* @param arg0 DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
protected Principal getPrincipal(String arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasRole(Principal principal, String role) {
|
||||
if ((principal == null) || (role == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(principal instanceof PrincipalSpringSecurityUserToken)) {
|
||||
logger.warn("Expected passed principal to be of type PrincipalSpringSecurityUserToken but was "
|
||||
+ principal.getClass().getName());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken test = (PrincipalSpringSecurityUserToken) principal;
|
||||
|
||||
return test.isUserInRole(role);
|
||||
}
|
||||
|
||||
public void setAppContextLocation(String appContextLocation) {
|
||||
this.appContextLocation = appContextLocation;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the method that Catalina will use to start the container.
|
||||
*
|
||||
* @throws LifecycleException if a problem is detected
|
||||
*/
|
||||
public void start() throws LifecycleException {
|
||||
this.start(true);
|
||||
}
|
||||
|
||||
private void start(boolean startParent) throws LifecycleException {
|
||||
if (startParent) {
|
||||
super.start();
|
||||
}
|
||||
|
||||
if ((appContextLocation == null) || "".equals(appContextLocation)) {
|
||||
throw new LifecycleException("appContextLocation must be defined");
|
||||
}
|
||||
|
||||
if ((key == null) || "".equals(key)) {
|
||||
throw new LifecycleException("key must be defined");
|
||||
}
|
||||
|
||||
File xml = new File(System.getProperty("catalina.base"), appContextLocation);
|
||||
|
||||
if (!xml.exists()) {
|
||||
throw new LifecycleException("appContextLocation does not seem to exist in " + xml.toString());
|
||||
}
|
||||
|
||||
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("file:" + xml.getAbsolutePath());
|
||||
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Bean context must contain at least one bean of type AuthenticationManager");
|
||||
}
|
||||
|
||||
String beanName = (String) beans.keySet().iterator().next();
|
||||
authenticationManager = (AuthenticationManager) beans.get(beanName);
|
||||
logger.info("CatalinaSpringSecurityUserRealm Started");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a method to load the container adapter without delegating to the superclass, which cannot
|
||||
* operate outside the Catalina container.
|
||||
*
|
||||
* @throws LifecycleException if a problem is detected
|
||||
*/
|
||||
protected void startForTest() throws LifecycleException {
|
||||
this.start(false);
|
||||
}
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Adapter to Catalina web container (Tomcat).
|
||||
<p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Data access object which stores authentication information -->
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLE_TELLER,ROLE_SUPERVISOR
|
||||
dianne=emu,ROLE_TELLER
|
||||
scott=wombat,ROLE_TELLER
|
||||
peter=opal,disabled,ROLE_TELLER
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The authentication manager is deliberately missing in order to test error detection -->
|
||||
|
||||
</beans>
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Data access object which stores authentication information -->
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLE_TELLER,ROLE_SUPERVISOR
|
||||
dianne=emu,ROLE_TELLER
|
||||
scott=wombat,ROLE_TELLER
|
||||
peter=opal,disabled,ROLE_TELLER
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Authentication provider that queries our data access object -->
|
||||
<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="forcePrincipalAsString"><value>true</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- The authentication manager that iterates through our only authentication provider -->
|
||||
<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
-275
@@ -1,275 +0,0 @@
|
||||
/* 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.adapters.catalina;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link CatalinaSpringSecurityUserRealm}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:CatalinaSpringSecurityUserRealmTests.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class CatalinaSpringSecurityUserRealmTests extends TestCase {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String ADAPTER_KEY = "my_key";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CatalinaSpringSecurityUserRealmTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CatalinaSpringSecurityUserRealmTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(CatalinaSpringSecurityUserRealmTests.class);
|
||||
}
|
||||
|
||||
private CatalinaSpringSecurityUserRealm makeAdapter(String fileName)
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
|
||||
URL url = Thread.currentThread().getContextClassLoader().getResource("org/springframework/security/adapters/" + fileName);
|
||||
|
||||
if (url == null) {
|
||||
throw new Exception("Could not find " + fileName + " - cannot continue");
|
||||
}
|
||||
|
||||
File file = new File(url.getFile());
|
||||
|
||||
System.setProperty("catalina.base", file.getParentFile().getAbsolutePath());
|
||||
System.out.println("catalina.base set to: " + System.getProperty("catalina.base"));
|
||||
adapter.setAppContextLocation(fileName);
|
||||
adapter.setKey(ADAPTER_KEY);
|
||||
adapter.startForTest();
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
|
||||
throws Exception {
|
||||
try {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-invalid.xml");
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfNoAppContextSpecified()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
|
||||
adapter.setKey("KEY");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("appContextLocation must be defined", expected.getMessage());
|
||||
}
|
||||
|
||||
adapter.setAppContextLocation("");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("appContextLocation must be defined", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfNoKeySpecified() throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
|
||||
adapter.setAppContextLocation("SOMETHING");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("key must be defined", expected.getMessage());
|
||||
}
|
||||
|
||||
adapter.setKey("");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("key must be defined", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsWithIncorrectApplicationContextLocation()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
adapter.setAppContextLocation("SOME_INVALID_PATH");
|
||||
adapter.setKey("KEY");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertTrue(expected.getMessage().startsWith("appContextLocation does not seem to exist in"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterIdentifiesItself() throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(adapter.getName().lastIndexOf("CatalinaSpringUserRealm") != -1);
|
||||
}
|
||||
|
||||
public void testAdapterStartsUpSuccess() throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
public void testAuthenticateManyParamsReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.authenticate(null, null, null, null, null, null, null, null));
|
||||
}
|
||||
|
||||
public void testAuthenticateX509ReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.authenticate(null));
|
||||
}
|
||||
|
||||
public void testAuthenticationFailsForIncorrectPassword()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate("rod", "kangaroo"));
|
||||
}
|
||||
|
||||
public void testAuthenticationFailsForIncorrectUserName()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate("melissa", "koala"));
|
||||
}
|
||||
|
||||
public void testAuthenticationUsingByteArrayForCredentials()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
byte[] credentials = {'k', 'o', 'a', 'l', 'a'};
|
||||
Principal result = adapter.authenticate("rod", credentials);
|
||||
|
||||
if (!(result instanceof PrincipalSpringSecurityUserToken)) {
|
||||
fail("Should have returned PrincipalSpringSecurityUserToken");
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testAuthenticationUsingStringForCredentials()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
Principal result = adapter.authenticate("rod", "koala");
|
||||
|
||||
if (!(result instanceof PrincipalSpringSecurityUserToken)) {
|
||||
fail("Should have returned PrincipalSpringSecurityUserToken");
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullPasswordHandledGracefully()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate("rod", (String) null));
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullUserNameHandledGracefully()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate(null, "koala"));
|
||||
}
|
||||
|
||||
public void testGetPasswordReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.getPassword(null));
|
||||
}
|
||||
|
||||
public void testGetPrincipalReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.getPrincipal(null));
|
||||
}
|
||||
|
||||
public void testGetters() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
adapter.setKey("KEY");
|
||||
assertEquals("KEY", adapter.getKey());
|
||||
adapter.setAppContextLocation("SOME_LOCATION");
|
||||
assertEquals("SOME_LOCATION", adapter.getAppContextLocation());
|
||||
}
|
||||
|
||||
public void testHasRoleWithANullPrincipalFails() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(!adapter.hasRole(null, "ROLE_ONE"));
|
||||
}
|
||||
|
||||
public void testHasRoleWithAPrincipalTheAdapterDidNotCreateFails() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(!adapter.hasRole(new Principal() {
|
||||
public String getName() {
|
||||
return "MockPrincipal";
|
||||
}
|
||||
}, "ROLE_ONE"));
|
||||
}
|
||||
|
||||
public void testHasRoleWithPrincipalAcegiUserToken() {
|
||||
PrincipalSpringSecurityUserToken token = new PrincipalSpringSecurityUserToken("KEY", "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")},
|
||||
null);
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(adapter.hasRole(token, "ROLE_ONE"));
|
||||
assertTrue(adapter.hasRole(token, "ROLE_TWO"));
|
||||
assertTrue(!adapter.hasRole(token, "ROLE_WE_DO_NOT_HAVE"));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user