diff --git a/.asf.yaml b/.asf.yaml
index 36306ad458..7ad465ec65 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -25,12 +25,12 @@ github:
issues: true
projects: true
enabled_merge_buttons:
- squash: false
- merge: true
- rebase: false
+ squash: false
+ merge: true
+ rebase: false
notifications:
pullrequests: commits@shiro.apache.org
commits: commits@shiro.apache.org
- issues: issues@shiro.apache.org
+ issues: issues@shiro.apache.org
jira_options: link label worklog
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 793327e005..dca17b94af 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -25,37 +25,37 @@ updates:
open-pull-requests-limit: 50
ignore:
- dependency-name: "jakarta.platform:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.activation:jakarta.activation-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.annotation:jakarta.annotation-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.enterprise:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.xml.bind:jakarta.xml.bind-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.servlet.*:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.ws.rs:jakarta.ws.rs-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.validation:jakarta.validation-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.glassfish.web:jakarta.servlet.jsp.jstl"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.glassfish.jaxb:jaxb-runtime"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.omnifaces:omnifaces"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.springframework*:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "com.flowlogix:flowlogix-jee"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.eclipse.jetty:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
# Dependencies for Maven - on 1.12.x
- package-ecosystem: 'maven'
@@ -66,34 +66,34 @@ updates:
open-pull-requests-limit: 50
ignore:
- dependency-name: "jakarta.servlet.*:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "javax.servlet:javax.servlet-api"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.glassfish.web:jakarta.servlet.jsp.jstl"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.glassfish.jersey.*:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.jasig.cas.client:*"
- update-types: ["version-update:semver-minor"]
+ update-types: [ "version-update:semver-minor" ]
- dependency-name: "org.slf4j:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.codehaus.groovy:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "ch.qos.logback:logback-classic"
- update-types: ["version-update:semver-minor"]
+ update-types: [ "version-update:semver-minor" ]
- dependency-name: "com.hazelcast:hazelcast"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.aspectj:*"
- update-types: ["version-update:semver-patch"]
+ update-types: [ "version-update:semver-patch" ]
- dependency-name: "org.springframework*:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "org.eclipse.jetty:*"
- update-types: ["version-update:semver-major"]
+ update-types: [ "version-update:semver-major" ]
- dependency-name: "com.github.mjeanroy:junit-servers-jetty"
- update-types: ["version-update:semver-minor"]
+ update-types: [ "version-update:semver-minor" ]
# Dependencies for GitHub Actions
- package-ecosystem: 'github-actions'
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index d3180e0408..64280a08db 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -5,29 +5,36 @@ For more details on how to report a vulnerablity see: https://www.apache.org/sec
Following this checklist to help us incorporate your contribution quickly and easily:
- - [ ] Make sure there is a [GitHub issue](https://github.com/apache/shiro/issues) filed
- for the change (usually before you start working on it). Trivial changes like typos do not
- require a GitHub issue. Your pull request should address just this issue, without pulling in other changes.
- - [ ] Each commit in the pull request should have a meaningful subject line and body.
- - [ ] Format the pull request title like `[#XXX] - Fixes bug in SessionManager`,
- where you replace `#XXX` with the appropriate GitHub issue. Best practice
- is to use the GitHub issue title in the pull request title and in the first line of the commit message.
- - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
- - [ ] add `fixes #XXX` if merging the PR should close a related issue.
- - [ ] Run `mvn verify` to make sure basic checks pass. A more thorough check will be performed on your pull request automatically.
- - [ ] If you have a group of commits related to the same change, please squash your commits into one and force push your branch using `git rebase -i`.
- - [ ] Committers: Make sure a milestone is set on the PR
-
-Trivial changes like typos do not require a GitHub issue (javadoc, comments...).
+- [ ] Make sure there is a [GitHub issue](https://github.com/apache/shiro/issues) filed
+ for the change (usually before you start working on it). Trivial changes like typos do not
+ require a GitHub issue. Your pull request should address just this issue, without pulling in other changes.
+- [ ] Each commit in the pull request should have a meaningful subject line and body.
+- [ ] Format the pull request title like `[#XXX] - Fixes bug in SessionManager`,
+ where you replace `#XXX` with the appropriate GitHub issue. Best practice
+ is to use the GitHub issue title in the pull request title and in the first line of the commit message.
+- [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
+- [ ] add `fixes #XXX` if merging the PR should close a related issue.
+- [ ] Run `mvn verify` to make sure basic checks pass. A more thorough check will be performed on your pull request
+ automatically.
+- [ ] If you have a group of commits related to the same change, please squash your commits into one and force push your
+ branch using `git rebase -i`.
+- [ ] Committers: Make sure a milestone is set on the PR
+
+Trivial changes like typos do not require a GitHub issue (javadoc, comments...).
In this case, just format the pull request title like `[DOC] - Add javadoc in SessionManager`.
-
-If this is your first contribution, you have to read the [Contribution Guidelines](https://github.com/apache/shiro/blob/master/CONTRIBUTING.md)
-If your pull request is about ~20 lines of code you don't need to sign an [Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf)
+If this is your first contribution, you have to read
+the [Contribution Guidelines](https://github.com/apache/shiro/blob/master/CONTRIBUTING.md)
+
+If your pull request is about ~20 lines of code you don't need to sign
+an [Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf)
if you are unsure please ask on the developers list.
-To make clear that you license your contribution under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0)
+To make clear that you license your contribution under
+the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0)
you have to acknowledge this by using the following check-box.
- - [ ] I hereby declare this contribution to be licenced under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0)
- - [ ] In any other case, please file an [Apache Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf).
+- [ ] I hereby declare this contribution to be licenced under
+ the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0)
+- [ ] In any other case, please file
+ an [Apache Individual Contributor License Agreement](https://www.apache.org/licenses/icla.pdf).
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 6c0b305c69..32e62cf10a 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -59,45 +59,45 @@ jobs:
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- - name: Checkout repository
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
+ - name: Checkout repository
+ uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
- - name: Cache local Maven repository
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
- with:
- path: ~/.m2
- key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
- restore-keys: ${{ runner.os }}-m2
+ - name: Cache local Maven repository
+ uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
- # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
- # queries: security-extended,security-and-quality
+ # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
- # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
+ # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- # If the Autobuild fails above, remove it and uncomment the following three lines.
- # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
+ # If the Autobuild fails above, remove it and uncomment the following three lines.
+ # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
- # - run: |
- # echo "Run, Build Application using script"
- # ./location_of_script_within_repo/buildscript.sh
+ # - run: |
+ # echo "Run, Build Application using script"
+ # ./location_of_script_within_repo/buildscript.sh
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
- with:
- category: "/language:${{matrix.language}}"
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 97377472bc..c6f2c45abc 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -21,7 +21,7 @@ permissions:
contents: read
on:
- workflow_dispatch: {}
+ workflow_dispatch: { }
push:
branches: [ main, '1.11.x', '1.10.x', '1.9.x' ]
pull_request:
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index ce2bee231c..026404e6b4 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -24,7 +24,7 @@ permissions:
pull-requests: write
on:
- workflow_dispatch: {}
+ workflow_dispatch: { }
schedule:
# every day 5min after midnight, UTC.
- cron: "5 0 * * *"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3953cf37bb..48bd0cbb88 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,7 +3,9 @@ Contributing to Apache Shiro
Summary
-------
-This document covers how to contribute to the Apache Shiro project. These instructions assume you have a GitHub.com account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own fork of the Apache Shiro project and you will submit a Pull Request for your changes to be added.
+This document covers how to contribute to the Apache Shiro project. These instructions assume you have a GitHub.com
+account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own
+fork of the Apache Shiro project and you will submit a Pull Request for your changes to be added.
_Lets get started!!!_
@@ -15,7 +17,8 @@ In your browser, navigate to: [https://github.com/apache/shiro](https://github.c
Fork the repository by clicking on the 'Fork' button on the top right hand side.
The fork will happen and you will be taken to your own fork of the repository.
-Copy the Git repository URL by clicking on the clipboard next to the URL on the right hand side of the page under '**HTTPS** clone URL'.
+Copy the Git repository URL by clicking on the clipboard next to the URL on the right hand side of the page under '*
+*HTTPS** clone URL'.
You will paste this URL when doing the following `git clone` command.
On your computer, follow these steps to setup a local repository for working on Apache Shiro:
@@ -29,15 +32,18 @@ $ git fetch upstream
$ git rebase upstream/main
```
-
Making changes
--------------
-It is important that you create a new branch to make changes on and that you do not change the `main` branch (other than to rebase in changes from `upstream/main`).
-In this example I will assume you will be making your changes to a branch called `feature_x`. This `feature_x` branch will be created on your local repository and
-will be pushed to your forked repository on GitHub. Once this branch is on your fork you will create a Pull Request for the changes to be added to the Apache Shiro project.
+It is important that you create a new branch to make changes on and that you do not change the `main` branch (other than
+to rebase in changes from `upstream/main`).
+In this example I will assume you will be making your changes to a branch called `feature_x`. This `feature_x` branch
+will be created on your local repository and
+will be pushed to your forked repository on GitHub. Once this branch is on your fork you will create a Pull Request for
+the changes to be added to the Apache Shiro project.
-It is best practice to create a new branch each time you want to contribute to the project and only track the changes for that pull request in this branch.
+It is best practice to create a new branch each time you want to contribute to the project and only track the changes
+for that pull request in this branch.
``` bash
$ git checkout -b feature_x
@@ -47,16 +53,20 @@ $ git add .
$ git commit -a -m "descriptive commit message for your changes"
```
-> The `-b` specifies that you want to create a new branch called `feature_x`. You only specify `-b` the first time you checkout because you are creating a new branch.
+> The `-b` specifies that you want to create a new branch called `feature_x`. You only specify `-b` the first time you
+> checkout because you are creating a new branch.
> Once the `feature_x` branch exists, you can later switch to it with only `git checkout feature_x`.
Rebase `feature_x` to include updates from `upstream/main`
------------------------------------------------------------
-It is important that you maintain an up-to-date `main` branch in your local repository. This is done by rebasing in the code changes from `upstream/main`
-(the official Apache Shiro project repository) into your local repository. You will want to do this before you start working on a feature as well as right
-before you submit your changes as a pull request. I recommend you do this process periodically while you work to make sure you are working off the most recent project code.
+It is important that you maintain an up-to-date `main` branch in your local repository. This is done by rebasing in the
+code changes from `upstream/main`
+(the official Apache Shiro project repository) into your local repository. You will want to do this before you start
+working on a feature as well as right
+before you submit your changes as a pull request. I recommend you do this process periodically while you work to make
+sure you are working off the most recent project code.
This process will do the following:
@@ -78,10 +88,12 @@ $ git rebase main
Make a GitHub Pull Request to contribute your changes
-----------------------------------------------------
-When you are happy with your changes and you are ready to contribute them, you will create a Pull Request on GitHub to do so. This is done by pushing your local changes
+When you are happy with your changes and you are ready to contribute them, you will create a Pull Request on GitHub to
+do so. This is done by pushing your local changes
to your forked repository (default remote name is `origin`) and then initiating a pull request on GitHub.
-> **IMPORTANT:** Make sure you have rebased your `feature_x` branch to include the latest code from `upstream/main` _before_ you do this.
+> **IMPORTANT:** Make sure you have rebased your `feature_x` branch to include the latest code from `upstream/main`
+_before_ you do this.
``` bash
$ git push origin main
@@ -92,22 +104,27 @@ Now that the `feature_x` branch has been pushed to your GitHub repository, you c
To initiate the pull request, do the following:
-1. In your browser, navigate to your forked repository: [https://github.com/YOUR_ACCOUNT/shiro](https://github.com/YOUR_ACCOUNT/shiro)
-2. Click the new button called '**Compare & pull request**' that showed up just above the main area in your forked repository
+1. In your browser, navigate to your forked
+ repository: [https://github.com/YOUR_ACCOUNT/shiro](https://github.com/YOUR_ACCOUNT/shiro)
+2. Click the new button called '**Compare & pull request**' that showed up just above the main area in your forked
+ repository
3. Validate the pull request will be into the upstream `main` and will be from your `feature_x` branch
4. Enter a detailed description of the work you have done and then click '**Send pull request**'
-If you are requested to make modifications to your proposed changes, make the changes locally on your `feature_x` branch, re-push the `feature_x` branch to your fork.
+If you are requested to make modifications to your proposed changes, make the changes locally on your `feature_x`
+branch, re-push the `feature_x` branch to your fork.
The existing pull request should automatically pick up the change and update accordingly.
Cleaning up after a successful pull request
-------------------------------------------
-Once the `feature_x` branch has been committed into the `upstream/main` branch, your local `feature_x` branch and the `origin/feature_x` branch are no longer needed.
+Once the `feature_x` branch has been committed into the `upstream/main` branch, your local `feature_x` branch and
+the `origin/feature_x` branch are no longer needed.
If you want to make additional changes, restart the process with a new branch.
-> **IMPORTANT:** Make sure that your changes are in `upstream/main` before you delete your `feature_x` and `origin/feature_x` branches!
+> **IMPORTANT:** Make sure that your changes are in `upstream/main` before you delete your `feature_x`
+> and `origin/feature_x` branches!
You can delete these deprecated branches with the following:
diff --git a/LICENSE b/LICENSE
index 753842b672..f49a4e16e6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,201 +1,201 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- 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
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ 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.
\ No newline at end of file
diff --git a/README.md b/README.md
index effbff5373..4d01f468c2 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,10 @@
Apache Shiro
============
-[Apache Shiro](http://shiro.apache.org) is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.
+[Apache Shiro](http://shiro.apache.org) is a powerful and easy-to-use Java security framework that performs
+authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can
+quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise
+applications.
Documentation and Examples
--------------------------
@@ -15,8 +18,9 @@ http://shiro.apache.org
Tutorials
---------
+
* [10 Minute Tutorial](http://shiro.apache.org/10-minute-tutorial.html)
-* [Web Application](http://shiro.apache.org/webapp-tutorial.html)
+* [Web Application](http://shiro.apache.org/webapp-tutorial.html)
License
-------
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 58e3501db0..2be485aecd 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -1,572 +1,572 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you 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.
-
-This is not an official release notes document. It exists for Shiro developers
-to jot down their notes while working in the source code. These notes will be
-combined with Jira’s auto-generated release notes during a release for the
-total set.
-
-###########################################################
-# 2.0.0
-###########################################################
-
-Improvement
-
- [SHIRO-290] Implement bcrypt and argon2 KDF algorithms
-
-Backwards Incompatible Changes
---------------------------------
-
-* Changed default DefaultPasswordService.java algorithm to "Argon2id".
-* PasswordService.encryptPassword(Object plaintext) will now throw a NullPointerException on null parameter.
- It was never specified how this method would behave.
-* Made salt non-nullable.
-* Removed methods in PasswordMatcher.
-
-
-###########################################################
-# 1.7.1
-###########################################################
-
-Bug
-
- [SHIRO-797] - Shiro 1.7.0 is lower than using springboot version 2.0.7 dependency error
-
-
-###########################################################
-# 1.7.0
-###########################################################
-
-Bug
-
- [SHIRO-767] - org.apache.shiro.util.ClassUtil cannot load the array of Primitive DataType when use undertow as web container
- [SHIRO-792] - ShiroWebFilterConfiguration seems to conflict with other FilterRegistrationBean
-
-New Feature
-
- [SHIRO-789] - Also add cookie SameSite option to Spring
-
-Improvement
-
- [SHIRO-740] - SslFilter with HTTP Strict Transport Security (HSTS)
- [SHIRO-794] - Add system property to enable backslash path normalization
- [SHIRO-795] - Disable session path rewriting by default
-
-Task
-
- [SHIRO-793] - deleteMe cookie should use the defined "sameSite"
-
-
-###########################################################
-# 1.6.0
-###########################################################
-
-Bug
-
- [SHIRO-610] - Incorrect filterchainResolver in 1.4.0-RC2
- [SHIRO-762] - SecurityUtils.securityManager should be volatile
- [SHIRO-766] - ArrayIndexOutOfBoundsException in Base64#decode
-
-New Feature
-
- [SHIRO-788] - Add support for Global Filters
-
-Wish
-
- [SHIRO-780] - NOTICE files of shiro components don't match NOTICE in source code repository
-
-
-###########################################################
-# 1.5.3
-###########################################################
-
-Bug
-
- [SHIRO-530] - INI parser does not properly handled backslashes at end of values
- [SHIRO-751] - SimplePrincipalMap and SimplePrincipalCollection throw different exceptions for the same problem
- [SHIRO-753] - Regression in URI parsing in Shiro 1.5.2
-
-Dependency upgrade
-
- [SHIRO-754] - Upgrade to Apache Commons Codec 1.14
- [SHIRO-755] - Upgrade to Hazelcast 3.12.6
- [SHIRO-756] - Upgrade to Spring 5.2.5.RELEASE and Spring boot 2.2.6.RELEASE
- [SHIRO-757] - Upgrade to Htmlunit 2.39.0
- [SHIRO-758] - Upgrade to Jetty 9.4.27.v20200227
- [SHIRO-759] - Upgrade to Karaf 4.2.8
-
-
-###########################################################
-# 1.5.2
-###########################################################
-
-Bug
-
- [SHIRO-747] - FirstSuccessfulStrategy doesn't properly short circuit
- [SHIRO-749] - shiro-all jar is missing cache package
-
-Improvement
-
- [SHIRO-748] - Update Commons Configuration to 2.7
-
-
-###########################################################
-# 1.5.1
-###########################################################
-
-Bug
-
- [SHIRO-736] - DefaultCipherInstance is an alias which is not available in every JVM or JCA Provider
- [SHIRO-739] - Bean reflection property failed with Enum values
- [SHIRO-741] - Matching of / (root) is broken
- [SHIRO-742] - fix throw exception when request uri is /
-
-Dependency upgrade
-
- [SHIRO-738] - Upgrade to Spring 5.2.3.RELEASE and Spring boot 2.2.4.RELEASE
-
-
-###########################################################
-# 1.5.0
-###########################################################
-
-Notes: this release require a JRE 8 minimum.
-
-Bug
-
- [SHIRO-458] - Possible leaked timing information from DefaultPasswordService
- [SHIRO-469] - Wrong description of JdbcRealm#setPermissionsQuery
- [SHIRO-552] - JdbcRealm in SaltStyle.COLUMN assumes that password column is Base64 but salt column is utf8 bytes
- [SHIRO-661] - Add check for the principal of subject whether is null
- [SHIRO-682] - fix the potential threat when use "uri = uri + '/' " to bypassed shiro protect
- [SHIRO-684] - INI parser keeps escape characters in keys and values
- [SHIRO-685] - Potential NullPointerException if PermissionResolver return null/empty string
- [SHIRO-687] - Additional Servlet Filters are not available to ShiroFilterFactorBean (unless using XML based beans)
-
-New Feature
-
- [SHIRO-694] - Adds BearerToken support
- [SHIRO-722] - Add SameSite option to cookies
-
-Improvement
-
- [SHIRO-668] - Catch unexpected errors which can lead to oom
- [SHIRO-669] - Included a boolean flag in FirstSuccessfulStrategy to break after first successful authentication
- [SHIRO-670] - ByteSource Serializable
- [SHIRO-681] - Upgrade to compiler Java 8
- [SHIRO-693] - Update plugins
- [SHIRO-700] - Minor spring updates
- [SHIRO-706] - Switch to Guice4 by default in the build
- [SHIRO-709] - Fix Shiro Spring feature
- [SHIRO-710] - Update Commons Lang3 + remove older Commons Lang
- [SHIRO-711] - Deprecate JavaEnvironment
- [SHIRO-712] - Add BasicIniEnvironment
- [SHIRO-715] - Remove old JSTL jars
- [SHIRO-720] - Update Commons BeanUtils
- [SHIRO-724] - Update Jetty, Spring, Spring Boot, Htmlunit dependencies
- [SHIRO-726] - Add dynamic import package
- [SHIRO-728] - Update Spring Boot to 2.1.10
- [SHIRO-729] - Update Quartz
- [SHIRO-730] - Updates the default Cipher mode to GCM in AesCipherService
- [SHIRO-731] - Use OWasp Java Encoder to escape user supplied content to the logs
-
-Test
-
- [SHIRO-697] - Reduce shiro test logging level to INFO
-
-Task
-
- [SHIRO-690] - Validate JDK11 compatibility
- [SHIRO-692] - Upgrade and enforce min build maven version to 3.5.0
- [SHIRO-698] - Improve build with maven profile
- [SHIRO-734] - Remove Spring-client sample
- [SHIRO-735] - Shiro does not support servlet-3.1 void method(@Suspended AsyncResponse)
-
-Dependency upgrade
-
- [SHIRO-688] - Upgrade to commons-cli 1.4
- [SHIRO-689] - Upgrade to commons-codec 1.12
- [SHIRO-691] - Upgrade to maven-jar-plugin 3.1.1
- [SHIRO-695] - Update Hazelcast
- [SHIRO-696] - Update Jetty
- [SHIRO-699] - Fix maven warning for exec-maven-plugin and upgrade to 1.6.0
- [SHIRO-701] - Update logback
- [SHIRO-702] - Upgrade to jacoco-maven-plugin 0.8.4
- [SHIRO-703] - Update HSQL
- [SHIRO-704] - Update Spring, Spring Boot, Hibernate
- [SHIRO-705] - Update Easymock + Powermock
- [SHIRO-707] - Misc dependency updates
- [SHIRO-716] - Upgrade to commons-codec 1.13
- [SHIRO-717] - Upgrade to maven-pmd-plugin 3.12.0
- [SHIRO-718] - Upgrade to xmlsec 2.1.4
- [SHIRO-719] - Upgrade to Karaf 4.2.6
-
-Request
-
- [SHIRO-723] - Provide Minor Shiro Release that includes CVE-2019-10086 Fix
-
-
-###########################################################
-# 1.4.2
-###########################################################
-
-Bug
-
- [SHIRO-721] - RememberMe Padding Oracle Vulnerability
-
-Improvement
-
- [SHIRO-730] - Updates the default Cipher mode to GCM in AesCipherService
-
-
-###########################################################
-# 1.4.1
-###########################################################
-
-Bug
-
- [SHIRO-457] - Login without static VM security manager cause exception in debug
- [SHIRO-563] - shiro-aspectj karaf feature can't be installed
- [SHIRO-624] - OSGI: commons configuration import should be optional
- [SHIRO-626] - Bundle symbolic name conflict
- [SHIRO-637] - Refresh cached session in HTTP request after user logs out
- [SHIRO-650] - Shiro JAX-RS is not an OSGi bundle
- [SHIRO-653] - Spring-boot registers shiro filter only on REQUEST dispatcher
- [SHIRO-655] - shiro-core has an undesirable runtime OSGi dependency to spring-beans
- [SHIRO-658] - Problems building shiro on openjdk-8 on current debian stable (9.6 "stretch")
- [SHIRO-660] - Bug in FirstSuccessfulStrategy
- [SHIRO-680] - Duplicate Bundle-SymbolicName for Different Shiro Modules
-
-New Feature
-
- [SHIRO-638] - Update osgi bundle manifest to support Spring 4.x
-
-Improvement
-
- [SHIRO-560] - Shiro-web feature can't be installed in karaf 4.0.4
- [SHIRO-652] - Upgrade Shiro Feature to Karaf 4.x
- [SHIRO-664] - Upgrade to Apache pom parent 21
- [SHIRO-665] - Upgrade to maven-bundle-plugin 4.1.0
- [SHIRO-667] - Upgrade to Spring 4.3.22-RELEASE
- [SHIRO-672] - Upgrade to jacoco-maven-plugin 0.8.3
- [SHIRO-673] - Upgrade to maven-compiler-plugin 3.8.0
- [SHIRO-674] - Upgrade to maven-dependency-plugin to 3.1.1
- [SHIRO-675] - Upgrade to maven-surefire-plugins 3.0.0-M3
- [SHIRO-676] - Upgrade to maven-jar-plugin 3.1.0
- [SHIRO-677] - Upgrade to versions-maven-plugin 2.7
- [SHIRO-683] - Upgrade to spring-boot 1.5.19.RELEASE
-
-Task
-
- [SHIRO-662] - Constant Name Change in AuthenticationRealm
- [SHIRO-663] - Clean up pom parent relative path
-
-Dependency upgrade
-
- [SHIRO-659] - Upgrade to OWASP dependency-check-maven plugin 4.0.0
-
-
-###########################################################
-# 1.4.0
-###########################################################
-
-Bug
-
- [SHIRO-559] - shiro-guice violates the JEE specification
- [SHIRO-579] - Permission filter is validating last matched path
- [SHIRO-603] - Endless recursion in ShiroSecurityContext.getUserPrincipal()
- [SHIRO-605] - ShiroWebModule creates out of order filter chain.
- [SHIRO-607] - AuthorizationAttributeSourceAdvisor ignores type-annotations
- [SHIRO-608] - Use a ServiceLoader to discover WebEnvironments
- [SHIRO-611] - Spring web module does not load correct SessionStorageEvaluator
-
-Improvement
-
- [SHIRO-596] - shiro-tools-hasher needs private salt option
- [SHIRO-618] - Spring Boot Web Starter- Autoconfiguration for Realm and ShiroFilterChainDefinition
-
-
-###########################################################
-# 1.4.0-RC2
-###########################################################
-
-Bug
-
- [SHIRO-493] - shiro-guice not working with the guice 4.x
- [SHIRO-576] - Commons-beanutils dependency is not security compliant
- [SHIRO-586] - Can't Search For Groups In Active Directory Without A System User
- [SHIRO-587] - Can't Access Groups If userPrincipalName Doesn't Exist
- [SHIRO-591] - Basic Auth Filter permissive mode does NOT work
- [SHIRO-592] - ModularRealmAuthenticator causes log spam when one realm throws exception
- [SHIRO-593] - Allow for IniWebEnvironment subclasses to specify defaults objects to ReflectionBuilder
- [SHIRO-594] - Update Hazelcast version to latest supported version (3.7.2)
- [SHIRO-595] - Allow for POST only logout requests
- [SHIRO-612] - Need to upgrade BeanUtils to avoid vulnerability
-
-New Feature
-
- [SHIRO-501] - Add ability to set system properties in shiro.ini
- [SHIRO-589] - Add Servlet 3.x fragment
- [SHIRO-590] - Add Spring Boot support / starters
-
-Improvement
-
- [SHIRO-296] - Typo fixes
- [SHIRO-301] - Call permissionResolver directly in AuthorizingRealm
- [SHIRO-392] - Shiro Extension for JAX-RS
- [SHIRO-599] - Fix file encoding warnings during maven build and reporting
-
-
-###########################################################
-# 1.3.2
-###########################################################
-
-Bug
-
- [SHIRO-584] - URL Path matching issue with WebUtils.getPathWithinApplication
-
-
-###########################################################
-# 1.3.1
-###########################################################
-
-Bug
-
- [SHIRO-577] - Regression - Unable to set custom SessionValidationScheduler
- [SHIRO-581] - Improve log message when remember me cipher has changed
-
-
-###########################################################
-# 1.3.0
-###########################################################
-
-Bug
-
- [SHIRO-373] - Complete CAS remember-me support
- [SHIRO-397] - SingleArgumentMethodEventListenerTest fails
- [SHIRO-421] - Unable to set long timeouts on HttpServletSession
- [SHIRO-435] - SecurityManager is not a singleton in ShiroWebModule
- [SHIRO-473] - DefaultAnnotationResolver.getAnnotation throws NullPointerException
- [SHIRO-480] - setTarget method in DomainPermission does not set targets
- [SHIRO-483] - passwordsMatch() returns false with right plain password-encrypted password in JVM with default locale tr_TR
- [SHIRO-502] - OSGi import of com.google.inject in shiro-guice has incorrect version range
- [SHIRO-513] - Misleading error message when using custom WebEnvironment
- [SHIRO-515] - ExecutorServiceSessionValidationScheduler leaks resources due to improper synchronization
- [SHIRO-547] - Use MessageDigest#isEqual() instead of Arrays#equals() for comparing digests
- [SHIRO-568] - hash iterations is calculated wrongly in SimpleHash
- [SHIRO-570] - SimpleCookie should check the path of the cookie
-
-New Feature
-
- [SHIRO-200] - Add ability to configure basic authentication for specific HTTP methods
- [SHIRO-395] - Add an Event Bus for event publishing and low-coupling for custom components/plugins.
- [SHIRO-412] - Hazelcast-based caching and session clustering
- [SHIRO-436] - Add EnvironmentLoader finalizeEnvironment method
-
-Improvement
-
- [SHIRO-278] - Rename JndiLdapRealm to DefaultLdapRealm
- [SHIRO-300] - WildcardPermission: change visibility of field 'parts' to protected
- [SHIRO-361] - HttpServletResponse.encodeURL: only append JSESSIONID when necessary
- [SHIRO-428] - AuthorizingRealm "no cache" logging should be at DEBUG level, not INFO, OR is should log only once
- [SHIRO-437] - WildcardPermission: conformed toString
- [SHIRO-514] - ExecutorServiceSessionValidationScheduler should create threads with a configurable name
- [SHIRO-564] - WildcardPermission case-insensitive makes parts collections twice
- [SHIRO-566] - CollectionUtils should use Collections wrappers of arrays if possible
-
-Task
-
- [SHIRO-208] - Correct JDK 1.5 / 1.6 incompatibilities
- [SHIRO-320] - Add an example for using Guice integration.
- [SHIRO-571] - Mark shiro-cas deprecated (replaced with buji-pac4j)
-
-
-###########################################################
-# 1.2.6
-###########################################################
-
-Bug
-
- [SHIRO-545] - JavaEnvironment version getter
- [SHIRO-567] - shiro-root-1.2.5.pom uses invalid encoding, fails to parse with Gradle 2.14
-
-
-###########################################################
-# 1.2.5
-###########################################################
-
-Bug
-
- [SHIRO-443] - SessionValidationScheduler created multiple times, enabling it is not thread safe
- [SHIRO-462] - Authentication exceptions are swallowed
- [SHIRO-467] - Authentication exception gets swallowed
- [SHIRO-550] - Randomize default remember me cipher
-
-Improvement
-
- [SHIRO-504] - Java 8 support
- [SHIRO-516] - Explicitly specify the version of aspectjtools to avoid build warning
- [SHIRO-562] - WildcardPermission calls String.trim() twice in setParts()
-
-
-###########################################################
-# 1.2.4
-###########################################################
-
-Bug
-
- [SHIRO-517] - Caused by: java.lang.NoClassDefFoundError: Lcom/google/inject/internal/util/$ImmutableList;
- [SHIRO-518] - Shiro-CAS: Security Problem in cas-client-core versions older than 3.3.2
- [SHIRO-556] - https://shiro.apache.org/realm.html appears to link to the javadoc under static/current/apidocs not static/latest
-
-Improvement
-
- [SHIRO-332] - Change access level of method 'isPermitted' in org.apache.shiro.realm.AuthorizingRealm (line 461) from private to protected
- [SHIRO-496] - Update shiro.guice dependency
- [SHIRO-498] - ThreadLocal should not be created when not necessary
-
-
-###########################################################
-# 1.2.2
-###########################################################
-
-Bug:
-
- [SHIRO-316] - Annotations in samples-aspectj Project Does not Work
- [SHIRO-351] - Shiro Native Session implementation cannot extract JSESSIONID From URL if JSESSIONID is URL parameter (not HTTP parameter)
- [SHIRO-379] - SimpleAccountRealm concurrency access to roles and users
- [SHIRO-380] - runAs feature (still) doesn't work
- [SHIRO-387] - EnvironmentLoader destroys wrong environment
- [SHIRO-388] - Stackoverflow org.apache.shiro.session.SessionListener.onStop()
- [SHIRO-389] - Fix OSGI Exports for shiro-ehcache
- [SHIRO-390] - OSGi Import for JSP (javax.servlet.jsp) should be declared optional
- [SHIRO-394] - PropertiesRealm reloading not working when loading from file
- [SHIRO-399] - Memory leak for invalid sessions
- [SHIRO-403] - Trunk will not build under JDK 1.7 due to webstart plugin
- [SHIRO-413] - init() method is not called on class that implements org.apache.shiro.util.Initializable
- [SHIRO-415] - isLoginAttempt method in BasicHttpAuthenticationFilter class fails if used in any locale other than English
- [SHIRO-418] - Javadoc typo in JdbcRealm.SaltStyle
- [SHIRO-423] - INI ReflectionBuilder should not wrap reference values
- [SHIRO-429] - perms filter parsing is too sensitive to a trailing space
- [SHIRO-431] - please use git ignore
- [SHIRO-447] - Broken Javadoc links
-
-
-###########################################################
-# 1.2.1
-###########################################################
-
-Bug:
-
- [SHIRO-341] - ReflectionBuilder has invalid log message format
- [SHIRO-342] - Running the example as described at http://shiro.apache.org/10-minute-tutorial.html fails
- [SHIRO-344] - runAs feature doesn't work
- [SHIRO-350] - Creating a subject should not create a session
- [SHIRO-353] - DefaultSecurityManager has invalid SLF4J log instruction
- [SHIRO-354] - Authentication cache
- [SHIRO-358] - Source Tarball doesn't Build
- [SHIRO-363] - PasswordMatcher should support character arrays
- [SHIRO-368] - DomainPermission(string, string) constructor sets targets to the same value as actions
- [SHIRO-375] - Basic authentication issue when using COLON character
- [SHIRO-376] - shiro-cas feature should not depend on shiro-cas
- [SHIRO-377] - PropertiesRealm unable to reload Properties
-
-
-###########################################################
-# 1.2.0
-###########################################################
-
-Backwards Incompatible Changes
---------------------------------
-- The following org.apache.shiro.mgt.DefaultSecurityManager methods have been removed:
- bindPrincipalsToSession(principals, context)
-
- This logic has been moved into a SubjectDAO concept to allow end-users to control
- exactly how the Session may be used for subject state persistence. This allows a
- single point of control rather than needing to configure Shiro in multiple places.
-
- If you overrode this method in Shiro 1.0 or 1.1, please look at the new
- org.apache.shiro.mgt.DefaultSubjectDAO implementation, which performs compatible logic.
- Documentation for this is covered here:
- http://shiro.apache.org/session-management.html#SessionManagement-SessionsandSubjectState
-
-- The org.apache.shiro.web.session.mgt.ServletContainerSessionManager implementation
- (enabled by default for all web applications) no longer subclasses
- org.apache.shiro.session.mgt.AbstractSessionManager. AbstractSessionManager existed
- originally to consolidate a 'globalSessionTimeout' configuration property for
- subclasses. However, the ServletContainerSessionManager has been changed to always
- reflect the session configuration from web.xml (per its namesake). Because web.xml
- is the definitive source for session timeout configuration, the 'extends' clause
- was removed to avoid configuration confusion: if someone attempted to configure
- 'globalSessionTimeout' on a ServletContainerSessionManager instance, it would never
- be honored. It was better to remove the extends clause to ensure that any
- such configuration would fail fast when Shiro starts up to reflect the invalid config.
-
-
-Potential Breaking Changes
---------------------------------
-- The org.apache.shiro.web.filter.mgt.FilterChainManager class's
- addFilter(String name, Filter filter) semantics have changed. It now no longer
- attempts to initialize a filter by default before adding the filter to the chain.
- If you ever called this method, you can call the
- addFilter(name, filter, true) method to achieve the <= 1.1 behavior.
-
-- The org.apache.shiro.crypto.SecureRandomNumberGenerator previously defaulted to generating
- 128 random _bytes_ each time the nextBytes() method was called. This is too large for most purposes, so the
- default has been changed to 16 _bytes_ (which equals 128 bits - what was originally intended). If for some reason
- you need more than 16 bytes (128 bits) of randomly generated bits, you will need to configure the
- 'defaultNextByteSize' property to match your desired size (in bytes, NOT bits).
-
-- Shiro's Block Cipher Services (AesCipherService, BlowfishCipherService) have had the following changes:
-
- 1) The internal Cipher Mode and Streaming Cipher Mode have been changed from CFB to the new default of CBC.
- CBC is more commonly used for block ciphers today (e.g. SSL).
- If you were using an AES or Blowfish CipherService you will want to revert to the previous defaults in your config
- to ensure you can still decrypt previously encrypted data. For example, in code:
-
- blockCipherService.setMode(OperationMode.CFB);
- blockCipherService.setStreamingMode(OperationMode.CFB);
-
- or, in shiro.ini:
-
- blockCipherService.modeName = CFB
- blockCipherService.streamingModeName = CFB
-
- 2) The internal Streaming Padding Scheme has been changed from NONE to PKCS5 as PKCS5 is more commonly used.
- If you were using an AES or Blowfish CipherService for streaming operations, you will want to revert to the
- previous padding scheme default to ensure you can still decrypt previously encrypted data. For example, in code:
-
- blockCipherService.setStreamingPaddingScheme(PaddingScheme.NONE);
-
- or, in shiro.ini:
-
- blockCipherService.streamingPaddingSchemeName = NoPadding
-
- Note the difference in code vs shiro.ini in this last example: 'NoPadding' is the correct text value, 'NONE' is
- the correct Enum value.
-
-###########################################################
-# 1.1.0
-###########################################################
-
-Backwards Incompatible Changes
---------------------------------
-- The org.apache.shiro.web.util.RedirectView class's
- appendQueryProperties(StringBuffer targetUrl, Map model, String encodingScheme)
- method has been changed to accept a StringBuilder argument instead of a
- StringBuffer per SHIRO-191. RedirectView is considered an internal
- implementation support class and Shiro end-users should not be affected by this.
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+This is not an official release notes document. It exists for Shiro developers
+to jot down their notes while working in the source code. These notes will be
+combined with Jira’s auto-generated release notes during a release for the
+total set.
+
+###########################################################
+# 2.0.0
+###########################################################
+
+Improvement
+
+ [SHIRO-290] Implement bcrypt and argon2 KDF algorithms
+
+Backwards Incompatible Changes
+--------------------------------
+
+* Changed default DefaultPasswordService.java algorithm to "Argon2id".
+* PasswordService.encryptPassword(Object plaintext) will now throw a NullPointerException on null parameter.
+ It was never specified how this method would behave.
+* Made salt non-nullable.
+* Removed methods in PasswordMatcher.
+
+
+###########################################################
+# 1.7.1
+###########################################################
+
+Bug
+
+ [SHIRO-797] - Shiro 1.7.0 is lower than using springboot version 2.0.7 dependency error
+
+
+###########################################################
+# 1.7.0
+###########################################################
+
+Bug
+
+ [SHIRO-767] - org.apache.shiro.util.ClassUtil cannot load the array of Primitive DataType when use undertow as web container
+ [SHIRO-792] - ShiroWebFilterConfiguration seems to conflict with other FilterRegistrationBean
+
+New Feature
+
+ [SHIRO-789] - Also add cookie SameSite option to Spring
+
+Improvement
+
+ [SHIRO-740] - SslFilter with HTTP Strict Transport Security (HSTS)
+ [SHIRO-794] - Add system property to enable backslash path normalization
+ [SHIRO-795] - Disable session path rewriting by default
+
+Task
+
+ [SHIRO-793] - deleteMe cookie should use the defined "sameSite"
+
+
+###########################################################
+# 1.6.0
+###########################################################
+
+Bug
+
+ [SHIRO-610] - Incorrect filterchainResolver in 1.4.0-RC2
+ [SHIRO-762] - SecurityUtils.securityManager should be volatile
+ [SHIRO-766] - ArrayIndexOutOfBoundsException in Base64#decode
+
+New Feature
+
+ [SHIRO-788] - Add support for Global Filters
+
+Wish
+
+ [SHIRO-780] - NOTICE files of shiro components don't match NOTICE in source code repository
+
+
+###########################################################
+# 1.5.3
+###########################################################
+
+Bug
+
+ [SHIRO-530] - INI parser does not properly handled backslashes at end of values
+ [SHIRO-751] - SimplePrincipalMap and SimplePrincipalCollection throw different exceptions for the same problem
+ [SHIRO-753] - Regression in URI parsing in Shiro 1.5.2
+
+Dependency upgrade
+
+ [SHIRO-754] - Upgrade to Apache Commons Codec 1.14
+ [SHIRO-755] - Upgrade to Hazelcast 3.12.6
+ [SHIRO-756] - Upgrade to Spring 5.2.5.RELEASE and Spring boot 2.2.6.RELEASE
+ [SHIRO-757] - Upgrade to Htmlunit 2.39.0
+ [SHIRO-758] - Upgrade to Jetty 9.4.27.v20200227
+ [SHIRO-759] - Upgrade to Karaf 4.2.8
+
+
+###########################################################
+# 1.5.2
+###########################################################
+
+Bug
+
+ [SHIRO-747] - FirstSuccessfulStrategy doesn't properly short circuit
+ [SHIRO-749] - shiro-all jar is missing cache package
+
+Improvement
+
+ [SHIRO-748] - Update Commons Configuration to 2.7
+
+
+###########################################################
+# 1.5.1
+###########################################################
+
+Bug
+
+ [SHIRO-736] - DefaultCipherInstance is an alias which is not available in every JVM or JCA Provider
+ [SHIRO-739] - Bean reflection property failed with Enum values
+ [SHIRO-741] - Matching of / (root) is broken
+ [SHIRO-742] - fix throw exception when request uri is /
+
+Dependency upgrade
+
+ [SHIRO-738] - Upgrade to Spring 5.2.3.RELEASE and Spring boot 2.2.4.RELEASE
+
+
+###########################################################
+# 1.5.0
+###########################################################
+
+Notes: this release require a JRE 8 minimum.
+
+Bug
+
+ [SHIRO-458] - Possible leaked timing information from DefaultPasswordService
+ [SHIRO-469] - Wrong description of JdbcRealm#setPermissionsQuery
+ [SHIRO-552] - JdbcRealm in SaltStyle.COLUMN assumes that password column is Base64 but salt column is utf8 bytes
+ [SHIRO-661] - Add check for the principal of subject whether is null
+ [SHIRO-682] - fix the potential threat when use "uri = uri + '/' " to bypassed shiro protect
+ [SHIRO-684] - INI parser keeps escape characters in keys and values
+ [SHIRO-685] - Potential NullPointerException if PermissionResolver return null/empty string
+ [SHIRO-687] - Additional Servlet Filters are not available to ShiroFilterFactorBean (unless using XML based beans)
+
+New Feature
+
+ [SHIRO-694] - Adds BearerToken support
+ [SHIRO-722] - Add SameSite option to cookies
+
+Improvement
+
+ [SHIRO-668] - Catch unexpected errors which can lead to oom
+ [SHIRO-669] - Included a boolean flag in FirstSuccessfulStrategy to break after first successful authentication
+ [SHIRO-670] - ByteSource Serializable
+ [SHIRO-681] - Upgrade to compiler Java 8
+ [SHIRO-693] - Update plugins
+ [SHIRO-700] - Minor spring updates
+ [SHIRO-706] - Switch to Guice4 by default in the build
+ [SHIRO-709] - Fix Shiro Spring feature
+ [SHIRO-710] - Update Commons Lang3 + remove older Commons Lang
+ [SHIRO-711] - Deprecate JavaEnvironment
+ [SHIRO-712] - Add BasicIniEnvironment
+ [SHIRO-715] - Remove old JSTL jars
+ [SHIRO-720] - Update Commons BeanUtils
+ [SHIRO-724] - Update Jetty, Spring, Spring Boot, Htmlunit dependencies
+ [SHIRO-726] - Add dynamic import package
+ [SHIRO-728] - Update Spring Boot to 2.1.10
+ [SHIRO-729] - Update Quartz
+ [SHIRO-730] - Updates the default Cipher mode to GCM in AesCipherService
+ [SHIRO-731] - Use OWasp Java Encoder to escape user supplied content to the logs
+
+Test
+
+ [SHIRO-697] - Reduce shiro test logging level to INFO
+
+Task
+
+ [SHIRO-690] - Validate JDK11 compatibility
+ [SHIRO-692] - Upgrade and enforce min build maven version to 3.5.0
+ [SHIRO-698] - Improve build with maven profile
+ [SHIRO-734] - Remove Spring-client sample
+ [SHIRO-735] - Shiro does not support servlet-3.1 void method(@Suspended AsyncResponse)
+
+Dependency upgrade
+
+ [SHIRO-688] - Upgrade to commons-cli 1.4
+ [SHIRO-689] - Upgrade to commons-codec 1.12
+ [SHIRO-691] - Upgrade to maven-jar-plugin 3.1.1
+ [SHIRO-695] - Update Hazelcast
+ [SHIRO-696] - Update Jetty
+ [SHIRO-699] - Fix maven warning for exec-maven-plugin and upgrade to 1.6.0
+ [SHIRO-701] - Update logback
+ [SHIRO-702] - Upgrade to jacoco-maven-plugin 0.8.4
+ [SHIRO-703] - Update HSQL
+ [SHIRO-704] - Update Spring, Spring Boot, Hibernate
+ [SHIRO-705] - Update Easymock + Powermock
+ [SHIRO-707] - Misc dependency updates
+ [SHIRO-716] - Upgrade to commons-codec 1.13
+ [SHIRO-717] - Upgrade to maven-pmd-plugin 3.12.0
+ [SHIRO-718] - Upgrade to xmlsec 2.1.4
+ [SHIRO-719] - Upgrade to Karaf 4.2.6
+
+Request
+
+ [SHIRO-723] - Provide Minor Shiro Release that includes CVE-2019-10086 Fix
+
+
+###########################################################
+# 1.4.2
+###########################################################
+
+Bug
+
+ [SHIRO-721] - RememberMe Padding Oracle Vulnerability
+
+Improvement
+
+ [SHIRO-730] - Updates the default Cipher mode to GCM in AesCipherService
+
+
+###########################################################
+# 1.4.1
+###########################################################
+
+Bug
+
+ [SHIRO-457] - Login without static VM security manager cause exception in debug
+ [SHIRO-563] - shiro-aspectj karaf feature can't be installed
+ [SHIRO-624] - OSGI: commons configuration import should be optional
+ [SHIRO-626] - Bundle symbolic name conflict
+ [SHIRO-637] - Refresh cached session in HTTP request after user logs out
+ [SHIRO-650] - Shiro JAX-RS is not an OSGi bundle
+ [SHIRO-653] - Spring-boot registers shiro filter only on REQUEST dispatcher
+ [SHIRO-655] - shiro-core has an undesirable runtime OSGi dependency to spring-beans
+ [SHIRO-658] - Problems building shiro on openjdk-8 on current debian stable (9.6 "stretch")
+ [SHIRO-660] - Bug in FirstSuccessfulStrategy
+ [SHIRO-680] - Duplicate Bundle-SymbolicName for Different Shiro Modules
+
+New Feature
+
+ [SHIRO-638] - Update osgi bundle manifest to support Spring 4.x
+
+Improvement
+
+ [SHIRO-560] - Shiro-web feature can't be installed in karaf 4.0.4
+ [SHIRO-652] - Upgrade Shiro Feature to Karaf 4.x
+ [SHIRO-664] - Upgrade to Apache pom parent 21
+ [SHIRO-665] - Upgrade to maven-bundle-plugin 4.1.0
+ [SHIRO-667] - Upgrade to Spring 4.3.22-RELEASE
+ [SHIRO-672] - Upgrade to jacoco-maven-plugin 0.8.3
+ [SHIRO-673] - Upgrade to maven-compiler-plugin 3.8.0
+ [SHIRO-674] - Upgrade to maven-dependency-plugin to 3.1.1
+ [SHIRO-675] - Upgrade to maven-surefire-plugins 3.0.0-M3
+ [SHIRO-676] - Upgrade to maven-jar-plugin 3.1.0
+ [SHIRO-677] - Upgrade to versions-maven-plugin 2.7
+ [SHIRO-683] - Upgrade to spring-boot 1.5.19.RELEASE
+
+Task
+
+ [SHIRO-662] - Constant Name Change in AuthenticationRealm
+ [SHIRO-663] - Clean up pom parent relative path
+
+Dependency upgrade
+
+ [SHIRO-659] - Upgrade to OWASP dependency-check-maven plugin 4.0.0
+
+
+###########################################################
+# 1.4.0
+###########################################################
+
+Bug
+
+ [SHIRO-559] - shiro-guice violates the JEE specification
+ [SHIRO-579] - Permission filter is validating last matched path
+ [SHIRO-603] - Endless recursion in ShiroSecurityContext.getUserPrincipal()
+ [SHIRO-605] - ShiroWebModule creates out of order filter chain.
+ [SHIRO-607] - AuthorizationAttributeSourceAdvisor ignores type-annotations
+ [SHIRO-608] - Use a ServiceLoader to discover WebEnvironments
+ [SHIRO-611] - Spring web module does not load correct SessionStorageEvaluator
+
+Improvement
+
+ [SHIRO-596] - shiro-tools-hasher needs private salt option
+ [SHIRO-618] - Spring Boot Web Starter- Autoconfiguration for Realm and ShiroFilterChainDefinition
+
+
+###########################################################
+# 1.4.0-RC2
+###########################################################
+
+Bug
+
+ [SHIRO-493] - shiro-guice not working with the guice 4.x
+ [SHIRO-576] - Commons-beanutils dependency is not security compliant
+ [SHIRO-586] - Can't Search For Groups In Active Directory Without A System User
+ [SHIRO-587] - Can't Access Groups If userPrincipalName Doesn't Exist
+ [SHIRO-591] - Basic Auth Filter permissive mode does NOT work
+ [SHIRO-592] - ModularRealmAuthenticator causes log spam when one realm throws exception
+ [SHIRO-593] - Allow for IniWebEnvironment subclasses to specify defaults objects to ReflectionBuilder
+ [SHIRO-594] - Update Hazelcast version to latest supported version (3.7.2)
+ [SHIRO-595] - Allow for POST only logout requests
+ [SHIRO-612] - Need to upgrade BeanUtils to avoid vulnerability
+
+New Feature
+
+ [SHIRO-501] - Add ability to set system properties in shiro.ini
+ [SHIRO-589] - Add Servlet 3.x fragment
+ [SHIRO-590] - Add Spring Boot support / starters
+
+Improvement
+
+ [SHIRO-296] - Typo fixes
+ [SHIRO-301] - Call permissionResolver directly in AuthorizingRealm
+ [SHIRO-392] - Shiro Extension for JAX-RS
+ [SHIRO-599] - Fix file encoding warnings during maven build and reporting
+
+
+###########################################################
+# 1.3.2
+###########################################################
+
+Bug
+
+ [SHIRO-584] - URL Path matching issue with WebUtils.getPathWithinApplication
+
+
+###########################################################
+# 1.3.1
+###########################################################
+
+Bug
+
+ [SHIRO-577] - Regression - Unable to set custom SessionValidationScheduler
+ [SHIRO-581] - Improve log message when remember me cipher has changed
+
+
+###########################################################
+# 1.3.0
+###########################################################
+
+Bug
+
+ [SHIRO-373] - Complete CAS remember-me support
+ [SHIRO-397] - SingleArgumentMethodEventListenerTest fails
+ [SHIRO-421] - Unable to set long timeouts on HttpServletSession
+ [SHIRO-435] - SecurityManager is not a singleton in ShiroWebModule
+ [SHIRO-473] - DefaultAnnotationResolver.getAnnotation throws NullPointerException
+ [SHIRO-480] - setTarget method in DomainPermission does not set targets
+ [SHIRO-483] - passwordsMatch() returns false with right plain password-encrypted password in JVM with default locale tr_TR
+ [SHIRO-502] - OSGi import of com.google.inject in shiro-guice has incorrect version range
+ [SHIRO-513] - Misleading error message when using custom WebEnvironment
+ [SHIRO-515] - ExecutorServiceSessionValidationScheduler leaks resources due to improper synchronization
+ [SHIRO-547] - Use MessageDigest#isEqual() instead of Arrays#equals() for comparing digests
+ [SHIRO-568] - hash iterations is calculated wrongly in SimpleHash
+ [SHIRO-570] - SimpleCookie should check the path of the cookie
+
+New Feature
+
+ [SHIRO-200] - Add ability to configure basic authentication for specific HTTP methods
+ [SHIRO-395] - Add an Event Bus for event publishing and low-coupling for custom components/plugins.
+ [SHIRO-412] - Hazelcast-based caching and session clustering
+ [SHIRO-436] - Add EnvironmentLoader finalizeEnvironment method
+
+Improvement
+
+ [SHIRO-278] - Rename JndiLdapRealm to DefaultLdapRealm
+ [SHIRO-300] - WildcardPermission: change visibility of field 'parts' to protected
+ [SHIRO-361] - HttpServletResponse.encodeURL: only append JSESSIONID when necessary
+ [SHIRO-428] - AuthorizingRealm "no cache" logging should be at DEBUG level, not INFO, OR is should log only once
+ [SHIRO-437] - WildcardPermission: conformed toString
+ [SHIRO-514] - ExecutorServiceSessionValidationScheduler should create threads with a configurable name
+ [SHIRO-564] - WildcardPermission case-insensitive makes parts collections twice
+ [SHIRO-566] - CollectionUtils should use Collections wrappers of arrays if possible
+
+Task
+
+ [SHIRO-208] - Correct JDK 1.5 / 1.6 incompatibilities
+ [SHIRO-320] - Add an example for using Guice integration.
+ [SHIRO-571] - Mark shiro-cas deprecated (replaced with buji-pac4j)
+
+
+###########################################################
+# 1.2.6
+###########################################################
+
+Bug
+
+ [SHIRO-545] - JavaEnvironment version getter
+ [SHIRO-567] - shiro-root-1.2.5.pom uses invalid encoding, fails to parse with Gradle 2.14
+
+
+###########################################################
+# 1.2.5
+###########################################################
+
+Bug
+
+ [SHIRO-443] - SessionValidationScheduler created multiple times, enabling it is not thread safe
+ [SHIRO-462] - Authentication exceptions are swallowed
+ [SHIRO-467] - Authentication exception gets swallowed
+ [SHIRO-550] - Randomize default remember me cipher
+
+Improvement
+
+ [SHIRO-504] - Java 8 support
+ [SHIRO-516] - Explicitly specify the version of aspectjtools to avoid build warning
+ [SHIRO-562] - WildcardPermission calls String.trim() twice in setParts()
+
+
+###########################################################
+# 1.2.4
+###########################################################
+
+Bug
+
+ [SHIRO-517] - Caused by: java.lang.NoClassDefFoundError: Lcom/google/inject/internal/util/$ImmutableList;
+ [SHIRO-518] - Shiro-CAS: Security Problem in cas-client-core versions older than 3.3.2
+ [SHIRO-556] - https://shiro.apache.org/realm.html appears to link to the javadoc under static/current/apidocs not static/latest
+
+Improvement
+
+ [SHIRO-332] - Change access level of method 'isPermitted' in org.apache.shiro.realm.AuthorizingRealm (line 461) from private to protected
+ [SHIRO-496] - Update shiro.guice dependency
+ [SHIRO-498] - ThreadLocal should not be created when not necessary
+
+
+###########################################################
+# 1.2.2
+###########################################################
+
+Bug:
+
+ [SHIRO-316] - Annotations in samples-aspectj Project Does not Work
+ [SHIRO-351] - Shiro Native Session implementation cannot extract JSESSIONID From URL if JSESSIONID is URL parameter (not HTTP parameter)
+ [SHIRO-379] - SimpleAccountRealm concurrency access to roles and users
+ [SHIRO-380] - runAs feature (still) doesn't work
+ [SHIRO-387] - EnvironmentLoader destroys wrong environment
+ [SHIRO-388] - Stackoverflow org.apache.shiro.session.SessionListener.onStop()
+ [SHIRO-389] - Fix OSGI Exports for shiro-ehcache
+ [SHIRO-390] - OSGi Import for JSP (javax.servlet.jsp) should be declared optional
+ [SHIRO-394] - PropertiesRealm reloading not working when loading from file
+ [SHIRO-399] - Memory leak for invalid sessions
+ [SHIRO-403] - Trunk will not build under JDK 1.7 due to webstart plugin
+ [SHIRO-413] - init() method is not called on class that implements org.apache.shiro.util.Initializable
+ [SHIRO-415] - isLoginAttempt method in BasicHttpAuthenticationFilter class fails if used in any locale other than English
+ [SHIRO-418] - Javadoc typo in JdbcRealm.SaltStyle
+ [SHIRO-423] - INI ReflectionBuilder should not wrap reference values
+ [SHIRO-429] - perms filter parsing is too sensitive to a trailing space
+ [SHIRO-431] - please use git ignore
+ [SHIRO-447] - Broken Javadoc links
+
+
+###########################################################
+# 1.2.1
+###########################################################
+
+Bug:
+
+ [SHIRO-341] - ReflectionBuilder has invalid log message format
+ [SHIRO-342] - Running the example as described at http://shiro.apache.org/10-minute-tutorial.html fails
+ [SHIRO-344] - runAs feature doesn't work
+ [SHIRO-350] - Creating a subject should not create a session
+ [SHIRO-353] - DefaultSecurityManager has invalid SLF4J log instruction
+ [SHIRO-354] - Authentication cache
+ [SHIRO-358] - Source Tarball doesn't Build
+ [SHIRO-363] - PasswordMatcher should support character arrays
+ [SHIRO-368] - DomainPermission(string, string) constructor sets targets to the same value as actions
+ [SHIRO-375] - Basic authentication issue when using COLON character
+ [SHIRO-376] - shiro-cas feature should not depend on shiro-cas
+ [SHIRO-377] - PropertiesRealm unable to reload Properties
+
+
+###########################################################
+# 1.2.0
+###########################################################
+
+Backwards Incompatible Changes
+--------------------------------
+- The following org.apache.shiro.mgt.DefaultSecurityManager methods have been removed:
+ bindPrincipalsToSession(principals, context)
+
+ This logic has been moved into a SubjectDAO concept to allow end-users to control
+ exactly how the Session may be used for subject state persistence. This allows a
+ single point of control rather than needing to configure Shiro in multiple places.
+
+ If you overrode this method in Shiro 1.0 or 1.1, please look at the new
+ org.apache.shiro.mgt.DefaultSubjectDAO implementation, which performs compatible logic.
+ Documentation for this is covered here:
+ http://shiro.apache.org/session-management.html#SessionManagement-SessionsandSubjectState
+
+- The org.apache.shiro.web.session.mgt.ServletContainerSessionManager implementation
+ (enabled by default for all web applications) no longer subclasses
+ org.apache.shiro.session.mgt.AbstractSessionManager. AbstractSessionManager existed
+ originally to consolidate a 'globalSessionTimeout' configuration property for
+ subclasses. However, the ServletContainerSessionManager has been changed to always
+ reflect the session configuration from web.xml (per its namesake). Because web.xml
+ is the definitive source for session timeout configuration, the 'extends' clause
+ was removed to avoid configuration confusion: if someone attempted to configure
+ 'globalSessionTimeout' on a ServletContainerSessionManager instance, it would never
+ be honored. It was better to remove the extends clause to ensure that any
+ such configuration would fail fast when Shiro starts up to reflect the invalid config.
+
+
+Potential Breaking Changes
+--------------------------------
+- The org.apache.shiro.web.filter.mgt.FilterChainManager class's
+ addFilter(String name, Filter filter) semantics have changed. It now no longer
+ attempts to initialize a filter by default before adding the filter to the chain.
+ If you ever called this method, you can call the
+ addFilter(name, filter, true) method to achieve the <= 1.1 behavior.
+
+- The org.apache.shiro.crypto.SecureRandomNumberGenerator previously defaulted to generating
+ 128 random _bytes_ each time the nextBytes() method was called. This is too large for most purposes, so the
+ default has been changed to 16 _bytes_ (which equals 128 bits - what was originally intended). If for some reason
+ you need more than 16 bytes (128 bits) of randomly generated bits, you will need to configure the
+ 'defaultNextByteSize' property to match your desired size (in bytes, NOT bits).
+
+- Shiro's Block Cipher Services (AesCipherService, BlowfishCipherService) have had the following changes:
+
+ 1) The internal Cipher Mode and Streaming Cipher Mode have been changed from CFB to the new default of CBC.
+ CBC is more commonly used for block ciphers today (e.g. SSL).
+ If you were using an AES or Blowfish CipherService you will want to revert to the previous defaults in your config
+ to ensure you can still decrypt previously encrypted data. For example, in code:
+
+ blockCipherService.setMode(OperationMode.CFB);
+ blockCipherService.setStreamingMode(OperationMode.CFB);
+
+ or, in shiro.ini:
+
+ blockCipherService.modeName = CFB
+ blockCipherService.streamingModeName = CFB
+
+ 2) The internal Streaming Padding Scheme has been changed from NONE to PKCS5 as PKCS5 is more commonly used.
+ If you were using an AES or Blowfish CipherService for streaming operations, you will want to revert to the
+ previous padding scheme default to ensure you can still decrypt previously encrypted data. For example, in code:
+
+ blockCipherService.setStreamingPaddingScheme(PaddingScheme.NONE);
+
+ or, in shiro.ini:
+
+ blockCipherService.streamingPaddingSchemeName = NoPadding
+
+ Note the difference in code vs shiro.ini in this last example: 'NoPadding' is the correct text value, 'NONE' is
+ the correct Enum value.
+
+###########################################################
+# 1.1.0
+###########################################################
+
+Backwards Incompatible Changes
+--------------------------------
+- The org.apache.shiro.web.util.RedirectView class's
+ appendQueryProperties(StringBuffer targetUrl, Map model, String encodingScheme)
+ method has been changed to accept a StringBuilder argument instead of a
+ StringBuffer per SHIRO-191. RedirectView is considered an internal
+ implementation support class and Shiro end-users should not be affected by this.
diff --git a/cache/pom.xml b/cache/pom.xml
index efbdae8eec..63b35d83ae 100644
--- a/cache/pom.xml
+++ b/cache/pom.xml
@@ -17,7 +17,8 @@
~ specific language governing permissions and limitations
~ under the License.
-->
-
* To be merged:
*
* Result:
* Please note: Since Shiro sometimes logs authentication operations, please ensure your AuthenticationInfo's
- * (Shiro's default Authenticator allows null hosts to support localhost and proxy server environments).CacheException
.
diff --git a/cache/src/main/java/org/apache/shiro/cache/CacheManager.java b/cache/src/main/java/org/apache/shiro/cache/CacheManager.java
index f50f06fa42..0b96b93071 100644
--- a/cache/src/main/java/org/apache/shiro/cache/CacheManager.java
+++ b/cache/src/main/java/org/apache/shiro/cache/CacheManager.java
@@ -38,5 +38,5 @@ public interface CacheManager {
* @return the Cache with the given name
* @throws CacheException if there is an error acquiring the Cache instance.
*/
- public MapCache
is a {@link Cache Cache} implementation that uses a backing {@link Map} instance to store
* and retrieve cached data.
*
+ * @param
*
- *
+ * [section1]
@@ -324,7 +346,7 @@ public void load(Reader reader) {
* [section2]
* key2 = new value
*
*
[section1]
@@ -397,8 +419,8 @@ public void load(Scanner scanner) {
sectionName = newSectionName;
- if (log.isDebugEnabled()) {
- log.debug("Parsing " + SECTION_PREFIX + sectionName + SECTION_SUFFIX);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Parsing " + SECTION_PREFIX + sectionName + SECTION_SUFFIX);
}
} else {
//normal line - add it to the existing content buffer:
@@ -501,7 +523,7 @@ public Set
value
and returns the result.
+ *
* @param value the source text
* @return the String result of the interpolation, or value
, if there was not change.
*/
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/ReflectionBuilder.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/ReflectionBuilder.java
index f198eba0d6..b931f7b3e4 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/ReflectionBuilder.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/ReflectionBuilder.java
@@ -67,11 +67,10 @@
*
* @since 0.9
*/
+@SuppressWarnings("checkstyle:MethodCount")
public class ReflectionBuilder {
- //TODO - complete JavaDoc
-
- private static final Logger log = LoggerFactory.getLogger(ReflectionBuilder.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionBuilder.class);
private static final String OBJECT_REFERENCE_BEGIN_TOKEN = "$";
private static final String ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN = "\\$";
@@ -90,6 +89,7 @@ public class ReflectionBuilder {
/**
* Interpolation allows for ${key} substitution of values.
+ *
* @since 1.4
*/
private Interpolator interpolator;
@@ -98,6 +98,7 @@ public class ReflectionBuilder {
* @since 1.3
*/
private EventBus eventBus;
+
/**
* Keeps track of event subscribers that were automatically registered by this ReflectionBuilder during
* object construction. This is used in case a new EventBus is discovered during object graph
@@ -106,20 +107,13 @@ public class ReflectionBuilder {
*
* @since 1.3
*/
- private final Map{@link org.apache.shiro.SecurityUtils#getSubject SecurityUtils.getSubject()}
.
+ * This default implementation merely calls
+ * {@link org.apache.shiro.SecurityUtils#getSubject SecurityUtils.getSubject()}
.
*
* @return the {@link org.apache.shiro.subject.Subject Subject} associated with the currently-executing code.
*/
diff --git a/core/src/main/java/org/apache/shiro/aop/AnnotationMethodInterceptor.java b/core/src/main/java/org/apache/shiro/aop/AnnotationMethodInterceptor.java
index 9179651dcf..fab7d3cdbc 100644
--- a/core/src/main/java/org/apache/shiro/aop/AnnotationMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/aop/AnnotationMethodInterceptor.java
@@ -75,7 +75,7 @@ public AnnotationMethodInterceptor(AnnotationHandler handler, AnnotationResolver
* an annotation discovered at runtime.
*
* @return the {@code AnnotationHandler} used to perform authorization behavior based on
- * an annotation discovered at runtime.
+ * an annotation discovered at runtime.
*/
public AnnotationHandler getHandler() {
return handler;
@@ -98,7 +98,7 @@ public void setHandler(AnnotationHandler handler) {
* perform authorization logic.
*
* @return the {@code AnnotationResolver} to use to acquire annotations from intercepted
- * methods at runtime.
+ * methods at runtime.
* @since 1.1
*/
public AnnotationResolver getResolver() {
@@ -128,7 +128,7 @@ public void setResolver(AnnotationResolver resolver) {
*
* @param mi the MethodInvocation
for the method being invoked.
* @return true
if this interceptor supports, that is, should inspect, the specified
- * MethodInvocation
, false
otherwise.
+ * MethodInvocation
, false
otherwise.
*/
public boolean supports(MethodInvocation mi) {
return getAnnotation(mi) != null;
diff --git a/core/src/main/java/org/apache/shiro/aop/AnnotationResolver.java b/core/src/main/java/org/apache/shiro/aop/AnnotationResolver.java
index 7934884503..2e96dff31e 100644
--- a/core/src/main/java/org/apache/shiro/aop/AnnotationResolver.java
+++ b/core/src/main/java/org/apache/shiro/aop/AnnotationResolver.java
@@ -1,42 +1,42 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.shiro.aop;
-
-import java.lang.annotation.Annotation;
-
-/**
- * Defines an AOP-framework-independent way of determining if an Annotation exists on a Method.
- *
- * @since 1.1
- */
-public interface AnnotationResolver {
-
- /**
- * Returns an {@link Annotation} instance of the specified type based on the given
- * {@link MethodInvocation MethodInvocation} argument, or {@code null} if no annotation
- * of that type could be found. First checks the invoked method itself and if not found,
- * then the class for the existence of the same annotation.
- *
- * @param mi the intercepted method to be invoked.
- * @param clazz the annotation class of the annotation to find.
- * @return the method's annotation of the specified type or {@code null} if no annotation of
- * that type could be found.
- */
- Annotation getAnnotation(MethodInvocation mi, Class extends Annotation> clazz);
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shiro.aop;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Defines an AOP-framework-independent way of determining if an Annotation exists on a Method.
+ *
+ * @since 1.1
+ */
+public interface AnnotationResolver {
+
+ /**
+ * Returns an {@link Annotation} instance of the specified type based on the given
+ * {@link MethodInvocation MethodInvocation} argument, or {@code null} if no annotation
+ * of that type could be found. First checks the invoked method itself and if not found,
+ * then the class for the existence of the same annotation.
+ *
+ * @param mi the intercepted method to be invoked.
+ * @param clazz the annotation class of the annotation to find.
+ * @return the method's annotation of the specified type or {@code null} if no annotation of
+ * that type could be found.
+ */
+ Annotation getAnnotation(MethodInvocation mi, Class extends Annotation> clazz);
+}
diff --git a/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java b/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java
index d7fd4aec7a..c020588ce1 100644
--- a/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java
+++ b/core/src/main/java/org/apache/shiro/aop/DefaultAnnotationResolver.java
@@ -1,69 +1,70 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.shiro.aop;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-
-/**
- * Default {@code AnnotationResolver} implementation that merely inspects the
- * {@link MethodInvocation MethodInvocation}'s {@link MethodInvocation#getMethod() target method},
- * and returns {@code targetMethod}.{@link Method#getAnnotation(Class) getAnnotation(class)}.
- *
- * Unfortunately Java's default reflection API for Annotations is not very robust, and this logic
- * may not be enough - if the incoming method invocation represents a method from an interface,
- * this default logic would not discover the annotation if it existed on the method implementation
- * directly (as opposed to being defined directly in the interface definition).
- *
- * More complex class hierarchy traversal logic is required to exhaust a method's target object's
- * classes, parent classes, interfaces and parent interfaces. That logic will likely be added
- * to this implementation in due time, but for now, this implementation relies on the JDK's default
- * {@link Method#getAnnotation(Class) Method.getAnnotation(class)} logic.
- *
- * @since 1.1
- */
-public class DefaultAnnotationResolver implements AnnotationResolver {
-
- /**
- * Returns {@code methodInvocation.}{@link org.apache.shiro.aop.MethodInvocation#getMethod() getMethod()}.{@link Method#getAnnotation(Class) getAnnotation(clazz)}.
- *
- * @param mi the intercepted method to be invoked.
- * @param clazz the annotation class to use to find an annotation instance on the method.
- * @return the discovered annotation or {@code null} if an annotation instance could not be
- * found.
- */
- public Annotation getAnnotation(MethodInvocation mi, Class extends Annotation> clazz) {
- if (mi == null) {
- throw new IllegalArgumentException("method argument cannot be null");
- }
- Method m = mi.getMethod();
- if (m == null) {
- String msg = MethodInvocation.class.getName() + " parameter incorrectly constructed. getMethod() returned null";
- throw new IllegalArgumentException(msg);
-
- }
- Annotation annotation = m.getAnnotation(clazz);
- if (annotation == null ) {
- Object miThis = mi.getThis();
- //SHIRO-473 - miThis could be null for static methods, just return null
- annotation = miThis != null ? miThis.getClass().getAnnotation(clazz) : null;
- }
- return annotation;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shiro.aop;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+/**
+ * Default {@code AnnotationResolver} implementation that merely inspects the
+ * {@link MethodInvocation MethodInvocation}'s {@link MethodInvocation#getMethod() target method},
+ * and returns {@code targetMethod}.{@link Method#getAnnotation(Class) getAnnotation(class)}.
+ *
+ * Unfortunately Java's default reflection API for Annotations is not very robust, and this logic
+ * may not be enough - if the incoming method invocation represents a method from an interface,
+ * this default logic would not discover the annotation if it existed on the method implementation
+ * directly (as opposed to being defined directly in the interface definition).
+ *
+ * More complex class hierarchy traversal logic is required to exhaust a method's target object's
+ * classes, parent classes, interfaces and parent interfaces. That logic will likely be added
+ * to this implementation in due time, but for now, this implementation relies on the JDK's default
+ * {@link Method#getAnnotation(Class) Method.getAnnotation(class)} logic.
+ *
+ * @since 1.1
+ */
+public class DefaultAnnotationResolver implements AnnotationResolver {
+
+ /**
+ * Returns {@code methodInvocation.}{@link org.apache.shiro.aop.MethodInvocation#getMethod() getMethod()}.
+ * {@link Method#getAnnotation(Class) getAnnotation(clazz)}.
+ *
+ * @param mi the intercepted method to be invoked.
+ * @param clazz the annotation class to use to find an annotation instance on the method.
+ * @return the discovered annotation or {@code null} if an annotation instance could not be
+ * found.
+ */
+ public Annotation getAnnotation(MethodInvocation mi, Class extends Annotation> clazz) {
+ if (mi == null) {
+ throw new IllegalArgumentException("method argument cannot be null");
+ }
+ Method m = mi.getMethod();
+ if (m == null) {
+ String msg = MethodInvocation.class.getName() + " parameter incorrectly constructed. getMethod() returned null";
+ throw new IllegalArgumentException(msg);
+
+ }
+ Annotation annotation = m.getAnnotation(clazz);
+ if (annotation == null) {
+ Object miThis = mi.getThis();
+ //SHIRO-473 - miThis could be null for static methods, just return null
+ annotation = miThis != null ? miThis.getClass().getAnnotation(clazz) : null;
+ }
+ return annotation;
+ }
+}
diff --git a/core/src/main/java/org/apache/shiro/aop/MethodInterceptorSupport.java b/core/src/main/java/org/apache/shiro/aop/MethodInterceptorSupport.java
index e21772ecda..2be6b3f1fb 100644
--- a/core/src/main/java/org/apache/shiro/aop/MethodInterceptorSupport.java
+++ b/core/src/main/java/org/apache/shiro/aop/MethodInterceptorSupport.java
@@ -40,7 +40,8 @@ public MethodInterceptorSupport() {
/**
* Returns the {@link Subject Subject} associated with the currently-executing code.
*
- * This default implementation merely calls {@link org.apache.shiro.SecurityUtils#getSubject SecurityUtils.getSubject()}
.
+ * This default implementation merely calls
+ * {@link org.apache.shiro.SecurityUtils#getSubject SecurityUtils.getSubject()}
.
*
* @return the {@link org.apache.shiro.subject.Subject Subject} associated with the currently-executing code.
*/
diff --git a/core/src/main/java/org/apache/shiro/aop/package-info.java b/core/src/main/java/org/apache/shiro/aop/package-info.java
index 0daa7749a0..3e9806cc24 100644
--- a/core/src/main/java/org/apache/shiro/aop/package-info.java
+++ b/core/src/main/java/org/apache/shiro/aop/package-info.java
@@ -23,4 +23,4 @@
* useful for any AOP environment and/or function. Feature-dependent AOP classes (e.g. authorization,
* authentication, etc.) will use these classes as their base in their respective packages.
*/
-package org.apache.shiro.aop;
\ No newline at end of file
+package org.apache.shiro.aop;
diff --git a/core/src/main/java/org/apache/shiro/authc/AbstractAuthenticator.java b/core/src/main/java/org/apache/shiro/authc/AbstractAuthenticator.java
index 125929bf72..278dae9010 100644
--- a/core/src/main/java/org/apache/shiro/authc/AbstractAuthenticator.java
+++ b/core/src/main/java/org/apache/shiro/authc/AbstractAuthenticator.java
@@ -48,7 +48,7 @@ public abstract class AbstractAuthenticator implements Authenticator, LogoutAwar
/**
* Private class log instance.
*/
- private static final Logger log = LoggerFactory.getLogger(AbstractAuthenticator.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAuthenticator.class);
/*-------------------------------------------
| I N S T A N C E V A R I A B L E S |
@@ -95,7 +95,7 @@ public void setAuthenticationListeners(CollectiontoString()
implementation does not print out account credentials (password, etc.), as these might be viewable to
- * someone reading your logs. This is good practice anyway, and account credentials should rarely (if ever) be printed
+ * toString()
implementation does not print out account credentials (password, etc.),
+ * as these might be viewable to someone reading your logs.
+ * This is good practice anyway, and account credentials should rarely (if ever) be printed
* out for any reason. If you're using Shiro's default implementations of this interface, they only ever print the
* account {@link #getPrincipals() principals}, so you do not need to do anything additional.true
if the specified object is also a {@link SimpleAccount SimpleAccount} and its
- * {@link #getPrincipals() principals} are equal to this object's principals
, false
otherwise.
+ * {@link #getPrincipals() principals} are equal to this object's principals
, false
otherwise.
*/
public boolean equals(Object o) {
if (o == this) {
@@ -491,4 +495,4 @@ public String toString() {
return getPrincipals() != null ? getPrincipals().toString() : "empty";
}
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/org/apache/shiro/authc/SimpleAuthenticationInfo.java b/core/src/main/java/org/apache/shiro/authc/SimpleAuthenticationInfo.java
index 8ab6ae9b3e..8cae62fbe2 100644
--- a/core/src/main/java/org/apache/shiro/authc/SimpleAuthenticationInfo.java
+++ b/core/src/main/java/org/apache/shiro/authc/SimpleAuthenticationInfo.java
@@ -165,7 +165,7 @@ public void setCredentials(Object credentials) {
* use for salts. Therefore it doesn't make sense to 'merge' salts in a multi-realm scenario.
*
* @return the salt used to hash the credentials, or {@code null} if no salt was used or credentials were not
- * hashed at all.
+ * hashed at all.
* @since 1.1
*/
@Override
@@ -196,7 +196,7 @@ public void setCredentialsSalt(ByteSource salt) {
* @param info the AuthenticationInfo
to add into this instance.
*/
@Override
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({"unchecked", "checkstyle:NPathComplexity"})
public void merge(AuthenticationInfo info) {
if (info == null || info.getPrincipals() == null || info.getPrincipals().isEmpty()) {
return;
@@ -254,7 +254,7 @@ public void merge(AuthenticationInfo info) {
*
* @param o the object to compare for equality.
* @return true
if the Object argument is an instanceof SimpleAuthenticationInfo
and
- * its {@link #getPrincipals() principals} are equal to this instance's principals, false
otherwise.
+ * its {@link #getPrincipals() principals} are equal to this instance's principals, false
otherwise.
*/
@Override
public boolean equals(Object o) {
diff --git a/core/src/main/java/org/apache/shiro/authc/UsernamePasswordToken.java b/core/src/main/java/org/apache/shiro/authc/UsernamePasswordToken.java
index 23768f2166..21d76c56ec 100644
--- a/core/src/main/java/org/apache/shiro/authc/UsernamePasswordToken.java
+++ b/core/src/main/java/org/apache/shiro/authc/UsernamePasswordToken.java
@@ -65,7 +65,7 @@ public class UsernamePasswordToken implements HostAuthenticationToken, RememberM
* Whether or not 'rememberMe' should be enabled for the corresponding login attempt;
* default is false
*/
- private boolean rememberMe = false;
+ private boolean rememberMe;
/**
* The location from where the login attempt occurs, or null
if not known or explicitly
@@ -279,7 +279,7 @@ public Object getCredentials() {
* true
always no matter what the method arguments are.
*
- * @param token the token submitted for authentication.
- * @param info the account being verified for access
+ * @param token the token submitted for authentication.
+ * @param info the account being verified for access
* @return true
always.
*/
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
diff --git a/core/src/main/java/org/apache/shiro/authc/credential/CredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/CredentialsMatcher.java
index 58b7514b83..89c9dd93c7 100644
--- a/core/src/main/java/org/apache/shiro/authc/credential/CredentialsMatcher.java
+++ b/core/src/main/java/org/apache/shiro/authc/credential/CredentialsMatcher.java
@@ -21,7 +21,6 @@
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
-
/**
* Interface implemented by classes that can determine if an AuthenticationToken's provided
* credentials matches a corresponding account's credentials stored in the system.
@@ -44,11 +43,11 @@ public interface CredentialsMatcher {
* Returns {@code true} if the provided token credentials match the stored account credentials,
* {@code false} otherwise.
*
- * @param token the {@code AuthenticationToken} submitted during the authentication attempt
- * @param info the {@code AuthenticationInfo} stored in the system.
+ * @param token the {@code AuthenticationToken} submitted during the authentication attempt
+ * @param info the {@code AuthenticationInfo} stored in the system.
* @return {@code true} if the provided token credentials match the stored account credentials,
- * {@code false} otherwise.
+ * {@code false} otherwise.
*/
boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/org/apache/shiro/authc/credential/DefaultPasswordService.java b/core/src/main/java/org/apache/shiro/authc/credential/DefaultPasswordService.java
index 25c0898a59..73fd341362 100644
--- a/core/src/main/java/org/apache/shiro/authc/credential/DefaultPasswordService.java
+++ b/core/src/main/java/org/apache/shiro/authc/credential/DefaultPasswordService.java
@@ -47,15 +47,21 @@
*/
public class DefaultPasswordService implements HashingPasswordService {
+ /**
+ * default hash algorithm.
+ */
public static final String DEFAULT_HASH_ALGORITHM = "argon2id";
- private static final Logger log = LoggerFactory.getLogger(DefaultPasswordService.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPasswordService.class);
private HashService hashService;
private HashFormat hashFormat;
private HashFormatFactory hashFormatFactory;
- private volatile boolean hashFormatWarned; //used to avoid excessive log noise
+ /**
+ * used to avoid excessive log noise
+ */
+ private volatile boolean hashFormatWarned;
/**
* Constructs a new PasswordService with a default hash service and the default
@@ -122,13 +128,13 @@ protected void checkHashFormatDurability() {
HashFormat format = this.hashFormat;
- if (!(format instanceof ParsableHashFormat) && log.isWarnEnabled()) {
- String msg = "The configured hashFormat instance [" + format.getClass().getName() + "] is not a " +
- ParsableHashFormat.class.getName() + " implementation. This is " +
- "required if you wish to support backwards compatibility for saved password checking (almost " +
- "always desirable). Without a " + ParsableHashFormat.class.getSimpleName() + " instance, " +
- "any hashService configuration changes will break previously hashed/saved passwords.";
- log.warn(msg);
+ if (!(format instanceof ParsableHashFormat) && LOGGER.isWarnEnabled()) {
+ String msg = "The configured hashFormat instance [" + format.getClass().getName() + "] is not a "
+ + ParsableHashFormat.class.getName() + " implementation. This is "
+ + "required if you wish to support backwards compatibility for saved password checking (almost "
+ + "always desirable). Without a " + ParsableHashFormat.class.getSimpleName() + " instance, "
+ + "any hashService configuration changes will break previously hashed/saved passwords.";
+ LOGGER.warn(msg);
this.hashFormatWarned = true;
}
}
diff --git a/core/src/main/java/org/apache/shiro/authc/credential/HashedCredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/HashedCredentialsMatcher.java
index 4e73810602..0ba10d6464 100644
--- a/core/src/main/java/org/apache/shiro/authc/credential/HashedCredentialsMatcher.java
+++ b/core/src/main/java/org/apache/shiro/authc/credential/HashedCredentialsMatcher.java
@@ -7,7 +7,7 @@
* "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
+ * 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
@@ -36,7 +36,7 @@
* before being compared to those in the {@code AuthenticationInfo} from the data store.
*
* Credential hashing is one of the most common security techniques when safeguarding a user's private credentials
- * (passwords, keys, etc). Most developers never want to store their users' credentials in plain form, viewable by
+ * (passwords, keys, etc.). Most developers never want to store their users' credentials in plain form, viewable by
* anyone, so they often hash the users' credentials before they are saved in the data store.
*
* This class (and its subclasses) function as follows:
@@ -55,7 +55,7 @@
* "Why add salt?" and 6 "Hardening against the attacker's attack").
new {@link org.apache.shiro.authc.SimpleAuthenticationInfo SimpleAuthenticationInfo}();
, which supports
* aggregating account data across realms.
@@ -40,6 +45,7 @@ public AuthenticationInfo beforeAllAttempts(Collection extends Realm> realms,
return new SimpleAuthenticationInfo();
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Simply returns the aggregate
method argument, without modification.
*/
@@ -51,7 +57,9 @@ public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token,
* Base implementation that will aggregate the specified singleRealmInfo
into the
* aggregateInfo
and then returns the aggregate. Can be overridden by subclasses for custom behavior.
*/
- public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
+ public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token,
+ AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo,
+ Throwable t) throws AuthenticationException {
AuthenticationInfo info;
if (singleRealmInfo == null) {
info = aggregateInfo;
@@ -78,15 +86,16 @@ public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, A
* {@link org.apache.shiro.authc.MergableAuthenticationInfo MergableAuthenticationInfo} is not desired for some reason.
*/
protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) {
- if( aggregate instanceof MergableAuthenticationInfo ) {
- ((MergableAuthenticationInfo)aggregate).merge(info);
+ if (aggregate instanceof MergableAuthenticationInfo) {
+ ((MergableAuthenticationInfo) aggregate).merge(info);
return aggregate;
} else {
- throw new IllegalArgumentException( "Attempt to merge authentication info from multiple realms, but aggregate " +
- "AuthenticationInfo is not of type MergableAuthenticationInfo." );
+ throw new IllegalArgumentException("Attempt to merge authentication info from multiple realms, but aggregate "
+ + "AuthenticationInfo is not of type MergableAuthenticationInfo.");
}
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Simply returns the aggregate
argument without modification. Can be overridden for custom behavior.
*/
diff --git a/core/src/main/java/org/apache/shiro/authc/pam/AllSuccessfulStrategy.java b/core/src/main/java/org/apache/shiro/authc/pam/AllSuccessfulStrategy.java
index a6dbbfe8d3..05b7fb9ba9 100644
--- a/core/src/main/java/org/apache/shiro/authc/pam/AllSuccessfulStrategy.java
+++ b/core/src/main/java/org/apache/shiro/authc/pam/AllSuccessfulStrategy.java
@@ -40,9 +40,12 @@
*/
public class AllSuccessfulStrategy extends AbstractAuthenticationStrategy {
- /** Private class log instance. */
- private static final Logger log = LoggerFactory.getLogger(AllSuccessfulStrategy.class);
+ /**
+ * Private class log instance.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(AllSuccessfulStrategy.class);
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Because all realms in this strategy must complete successfully, this implementation ensures that the given
* Realm
{@link org.apache.shiro.realm.Realm#supports(org.apache.shiro.authc.AuthenticationToken) supports} the given
@@ -50,12 +53,13 @@ public class AllSuccessfulStrategy extends AbstractAuthenticationStrategy {
* {@link UnsupportedTokenException UnsupportedTokenException} to end the authentication
* process immediately. If the realm does support the token, the info
argument is returned immediately.
*/
- public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
+ public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token,
+ AuthenticationInfo info) throws AuthenticationException {
if (!realm.supports(token)) {
- String msg = "Realm [" + realm + "] of type [" + realm.getClass().getName() + "] does not support " +
- " the submitted AuthenticationToken [" + token + "]. The [" + getClass().getName() +
- "] implementation requires all configured realm(s) to support and be able to process the submitted " +
- "AuthenticationToken.";
+ String msg = "Realm [" + realm + "] of type [" + realm.getClass().getName() + "] does not support "
+ + " the submitted AuthenticationToken [" + token + "]. The [" + getClass().getName()
+ + "] implementation requires all configured realm(s) to support and be able to process the submitted "
+ + "AuthenticationToken.";
throw new UnsupportedTokenException(msg);
}
@@ -72,6 +76,7 @@ public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token,
* realm did in fact authenticate successfully
*
*/
+ @SuppressWarnings("checkstyle:LineLength")
public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo info, AuthenticationInfo aggregate, Throwable t)
throws AuthenticationException {
if (t != null) {
@@ -79,21 +84,21 @@ public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, A
//propagate:
throw ((AuthenticationException) t);
} else {
- String msg = "Unable to acquire account data from realm [" + realm + "]. The [" +
- getClass().getName() + " implementation requires all configured realm(s) to operate successfully " +
- "for a successful authentication.";
+ String msg = "Unable to acquire account data from realm [" + realm + "]. The ["
+ + getClass().getName() + " implementation requires all configured realm(s) to operate successfully "
+ + "for a successful authentication.";
throw new AuthenticationException(msg, t);
}
}
if (info == null) {
- String msg = "Realm [" + realm + "] could not find any associated account data for the submitted " +
- "AuthenticationToken [" + token + "]. The [" + getClass().getName() + "] implementation requires " +
- "all configured realm(s) to acquire valid account data for a submitted token during the " +
- "log-in process.";
+ String msg = "Realm [" + realm + "] could not find any associated account data for the submitted "
+ + "AuthenticationToken [" + token + "]. The [" + getClass().getName() + "] implementation requires "
+ + "all configured realm(s) to acquire valid account data for a submitted token during the "
+ + "log-in process.";
throw new UnknownAccountException(msg);
}
- log.debug("Account successfully authenticated using realm [{}]", realm);
+ LOGGER.debug("Account successfully authenticated using realm [{}]", realm);
// If non-null account is returned, then the realm was able to authenticate the
// user - so merge the account with any accumulated before:
diff --git a/core/src/main/java/org/apache/shiro/authc/pam/AtLeastOneSuccessfulStrategy.java b/core/src/main/java/org/apache/shiro/authc/pam/AtLeastOneSuccessfulStrategy.java
index aa201d73d2..1278ea7310 100644
--- a/core/src/main/java/org/apache/shiro/authc/pam/AtLeastOneSuccessfulStrategy.java
+++ b/core/src/main/java/org/apache/shiro/authc/pam/AtLeastOneSuccessfulStrategy.java
@@ -51,13 +51,14 @@ private static boolean isEmpty(PrincipalCollection pc) {
* is not null
, and if either is null
, throws an AuthenticationException to indicate
* that none of the realms authenticated successfully.
*/
+ @SuppressWarnings("checkstyle:LineLength")
public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
//we know if one or more were able to successfully authenticate if the aggregated account object does not
//contain null or empty data:
if (aggregate == null || isEmpty(aggregate.getPrincipals())) {
- throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " +
- "could not be authenticated by any configured realms. Please ensure that at least one realm can " +
- "authenticate these tokens.");
+ throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] "
+ + "could not be authenticated by any configured realms. Please ensure that at least one realm can "
+ + "authenticate these tokens.");
}
return aggregate;
diff --git a/core/src/main/java/org/apache/shiro/authc/pam/AuthenticationStrategy.java b/core/src/main/java/org/apache/shiro/authc/pam/AuthenticationStrategy.java
index e816e74a0e..622bfb8f64 100644
--- a/core/src/main/java/org/apache/shiro/authc/pam/AuthenticationStrategy.java
+++ b/core/src/main/java/org/apache/shiro/authc/pam/AuthenticationStrategy.java
@@ -56,8 +56,10 @@ public interface AuthenticationStrategy {
* @return an empty AuthenticationInfo object that will populated with data from multiple realms.
* @throws AuthenticationException if the strategy implementation does not wish the Authentication attempt to execute.
*/
+ @SuppressWarnings("checkstyle:LineLength")
AuthenticationInfo beforeAllAttempts(Collection extends Realm> realms, AuthenticationToken token) throws AuthenticationException;
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Method invoked by the ModularAuthenticator just prior to the realm being consulted for account data,
* allowing pre-authentication-attempt logic for that realm only.
@@ -70,13 +72,13 @@ public interface AuthenticationStrategy {
* @param token the {@code AuthenticationToken} submitted for the subject attempting system log-in.
* @param aggregate the aggregated AuthenticationInfo object being used across the multi-realm authentication attempt
* @return the AuthenticationInfo object that will be presented to further realms in the authentication process - returning
- * the {@code aggregate} method argument is the normal case if no special action needs to be taken.
- * @throws org.apache.shiro.authc.AuthenticationException
- * an exception thrown by the Strategy implementation if it wishes the login
- * process for the associated subject (user) to stop immediately.
+ * the {@code aggregate} method argument is the normal case if no special action needs to be taken.
+ * @throws org.apache.shiro.authc.AuthenticationException an exception thrown by the Strategy implementation if it wishes the login
+ * process for the associated subject (user) to stop immediately.
*/
AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException;
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Method invoked by the ModularAuthenticator just after the given realm has been consulted for authentication,
* allowing post-authentication-attempt logic for that realm only.
@@ -91,13 +93,16 @@ public interface AuthenticationStrategy {
* @param aggregateInfo the aggregate info representing all realms in a multi-realm environment.
* @param t the Throwable thrown by the Realm during the attempt, or {@code null} if the method returned normally.
* @return the AuthenticationInfo object that will be presented to further realms in the authentication process - returning
- * the {@code aggregateAccount} method argument is the normal case if no special action needs to be taken.
+ * the {@code aggregateAccount} method argument is the normal case if no special action needs to be taken.
* @throws AuthenticationException an exception thrown by the Strategy implementation if it wishes the login process
* for the associated subject (user) to stop immediately.
*/
- AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t)
+ AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token,
+ AuthenticationInfo singleRealmInfo,
+ AuthenticationInfo aggregateInfo, Throwable t)
throws AuthenticationException;
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Method invoked by the ModularAuthenticator signifying that all of its configured Realms have been consulted
* for account data, allowing post-processing after all realms have completed.
diff --git a/core/src/main/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategy.java b/core/src/main/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategy.java
index 3d332f1cee..98907aa9ba 100644
--- a/core/src/main/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategy.java
+++ b/core/src/main/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategy.java
@@ -39,27 +39,28 @@ public class FirstSuccessfulStrategy extends AbstractAuthenticationStrategy {
private boolean stopAfterFirstSuccess;
- public void setStopAfterFirstSuccess (boolean stopAfterFirstSuccess ) {
-
- this.stopAfterFirstSuccess = stopAfterFirstSuccess ;
+ public void setStopAfterFirstSuccess(boolean stopAfterFirstSuccess) {
+ this.stopAfterFirstSuccess = stopAfterFirstSuccess;
}
public boolean getStopAfterFirstSuccess() {
- return stopAfterFirstSuccess ;
+ return stopAfterFirstSuccess;
}
/**
* Returns {@code null} immediately, relying on this class's {@link #merge merge} implementation to return
* only the first {@code info} object it encounters, ignoring all subsequent ones.
*/
+ @SuppressWarnings("checkstyle:LineLength")
public AuthenticationInfo beforeAllAttempts(Collection extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
return null;
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
- * Throws ShortCircuitIterationException if stopAfterFirstSuccess is set and authentication is
- * successful with a previously consulted realm.
+ * Throws ShortCircuitIterationException if stopAfterFirstSuccess is set and authentication is
+ * successful with a previously consulted realm.
* Returns the aggregate
method argument, without modification
* otherwise.
*/
@@ -70,8 +71,6 @@ public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token,
return aggregate;
}
-
-
private static boolean isEmpty(PrincipalCollection pc) {
return pc == null || pc.isEmpty();
}
diff --git a/core/src/main/java/org/apache/shiro/authc/pam/ModularRealmAuthenticator.java b/core/src/main/java/org/apache/shiro/authc/pam/ModularRealmAuthenticator.java
index 6e8cbc058f..c59ea6d2c7 100644
--- a/core/src/main/java/org/apache/shiro/authc/pam/ModularRealmAuthenticator.java
+++ b/core/src/main/java/org/apache/shiro/authc/pam/ModularRealmAuthenticator.java
@@ -18,7 +18,12 @@
*/
package org.apache.shiro.authc.pam;
-import org.apache.shiro.authc.*;
+import org.apache.shiro.authc.AbstractAuthenticator;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.LogoutAware;
+import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
@@ -63,10 +68,7 @@
*/
public class ModularRealmAuthenticator extends AbstractAuthenticator {
- /*--------------------------------------------
- | C O N S T A N T S |
- ============================================*/
- private static final Logger log = LoggerFactory.getLogger(ModularRealmAuthenticator.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ModularRealmAuthenticator.class);
/*--------------------------------------------
| I N S T A N C E V A R I A B L E S |
@@ -156,8 +158,8 @@ public void setAuthenticationStrategy(AuthenticationStrategy authenticationStrat
protected void assertRealmsConfigured() throws IllegalStateException {
CollectionstopAfterFirstSuccess
set.
- * This is a signal to short circuit the authentication from proceeding
- * with subsequent {@link org.apache.shiro.realm.Realm Realm}s
+ * {@link org.apache.shiro.authc.pam.FirstSuccessfulStrategy}, with
+ * stopAfterFirstSuccess
set.
+ * This is a signal to short circuit the authentication from proceeding
+ * with subsequent {@link org.apache.shiro.realm.Realm Realm}s
* after a first successful authentication.
*
* @see org.apache.shiro.authc.pam.AuthenticationStrategy
diff --git a/core/src/main/java/org/apache/shiro/authc/pam/package-info.java b/core/src/main/java/org/apache/shiro/authc/pam/package-info.java
index e6b3dc4a16..a8abac1aea 100644
--- a/core/src/main/java/org/apache/shiro/authc/pam/package-info.java
+++ b/core/src/main/java/org/apache/shiro/authc/pam/package-info.java
@@ -16,17 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
+
/**
* Support for PAM, or Pluggable Authentication Modules, which is
* the capability to authenticate a user against multiple configurable (pluggable) modules (Shiro
* calls these {@link org.apache.shiro.realm.Realm Realm}s).
*
- * The primary class of interest here is the {@link org.apache.shiro.authc.pam.ModularRealmAuthenticator ModularRealmAuthenticator}
- * which is an Authenticator
implementation that coordinates authentication attempts across
+ * The primary class of interest here is the
+ * {@link org.apache.shiro.authc.pam.ModularRealmAuthenticator ModularRealmAuthenticator}
+ * * which is an Authenticator
implementation that coordinates authentication attempts across
* one or more Realm instances.
*
* How the ModularRealmAuthenticator
actually coordinates this behavior is configurable based on your
* application's needs using an injectable
- * {@link AuthenticationStrategy}.
+ * {@link org.apache.shiro.authc.pam.AuthenticationStrategy}.
*/
package org.apache.shiro.authc.pam;
diff --git a/core/src/main/java/org/apache/shiro/authz/AuthorizationException.java b/core/src/main/java/org/apache/shiro/authz/AuthorizationException.java
index 317decf93c..3887fb30b3 100644
--- a/core/src/main/java/org/apache/shiro/authz/AuthorizationException.java
+++ b/core/src/main/java/org/apache/shiro/authz/AuthorizationException.java
@@ -26,8 +26,7 @@
*
* @since 0.1
*/
-public class AuthorizationException extends ShiroException
-{
+public class AuthorizationException extends ShiroException {
/**
* Creates a new AuthorizationException.
diff --git a/core/src/main/java/org/apache/shiro/authz/Authorizer.java b/core/src/main/java/org/apache/shiro/authz/Authorizer.java
index 9316af113e..7f77ba6769 100644
--- a/core/src/main/java/org/apache/shiro/authz/Authorizer.java
+++ b/core/src/main/java/org/apache/shiro/authz/Authorizer.java
@@ -57,7 +57,7 @@ public interface Authorizer {
* @param principals the application-specific subject/user identifier.
* @param permission the String representation of a Permission that is being checked.
* @return true if the corresponding Subject/user is permitted, false otherwise.
- * @see #isPermitted(PrincipalCollection principals,Permission permission)
+ * @see #isPermitted(PrincipalCollection principals, Permission permission)
* @since 0.9
*/
boolean isPermitted(PrincipalCollection principals, String permission);
@@ -85,9 +85,9 @@ public interface Authorizer {
* @param subjectPrincipal the application-specific subject/user identifier.
* @param permissions the String representations of the Permissions that are being checked.
* @return an array of booleans whose indices correspond to the index of the
- * permissions in the given list. A true value at an index indicates the user is permitted for
- * for the associated Permission string in the list. A false value at an index
- * indicates otherwise.
+ * permissions in the given list. A true value at an index indicates the user is permitted for
+ * for the associated Permission string in the list. A false value at an index
+ * indicates otherwise.
* @since 0.9
*/
boolean[] isPermitted(PrincipalCollection subjectPrincipal, String... permissions);
@@ -106,9 +106,9 @@ public interface Authorizer {
* @param subjectPrincipal the application-specific subject/user identifier.
* @param permissions the permissions that are being checked.
* @return an array of booleans whose indices correspond to the index of the
- * permissions in the given list. A true value at an index indicates the user is permitted for
- * for the associated Permission object in the list. A false value at an index
- * indicates otherwise.
+ * permissions in the given list. A true value at an index indicates the user is permitted for
+ * for the associated Permission object in the list. A false value at an index
+ * indicates otherwise.
*/
boolean[] isPermitted(PrincipalCollection subjectPrincipal, List* If the subject's existing associated permissions do not * {@link Permission#implies(Permission) imply} all of the given permissions, * an {@link AuthorizationException} will be thrown. @@ -192,7 +190,7 @@ public interface Authorizer { * Ensures the corresponding Subject/user * {@link Permission#implies(Permission) implies} all of the * specified permission strings. - * + *
* If the subject's existing associated permissions do not
* {@link Permission#implies(Permission) imply} all of the given permissions,
* an {@link AuthorizationException} will be thrown.
@@ -222,8 +220,8 @@ public interface Authorizer {
* @param subjectPrincipal the application-specific subject/user identifier.
* @param roleIdentifiers the application-specific role identifiers to check (usually role ids or role names).
* @return an array of booleans whose indices correspond to the index of the
- * roles in the given identifiers. A true value indicates the user has the
- * role at that index. False indicates the user does not have the role at that index.
+ * roles in the given identifiers. A true value indicates the user has the
+ * role at that index. False indicates the user does not have the role at that index.
*/
boolean[] hasRoles(PrincipalCollection subjectPrincipal, List
* {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest} annotations in a method
* declaration.
*/
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationHandler.java
index 9c1816236c..c74e86b67f 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationHandler.java
@@ -24,7 +24,7 @@
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.annotation.RequiresGuest;
-
+@SuppressWarnings("checkstyle:LineLength")
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest} annotation
* is declared, and if so, ensures the calling
* {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest} annotations in a method
* declaration.
*/
@@ -53,14 +53,13 @@ public GuestAnnotationHandler() {
*
* {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser} annotations.
*/
public UserAnnotationHandler() {
super(RequiresUser.class);
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Ensures that the calling
* {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser} annotations in a method
* declaration.
*/
public UserAnnotationMethodInterceptor() {
- super( new UserAnnotationHandler() );
+ super(new UserAnnotationHandler());
}
/**
- *
* @param resolver
* @since 1.1
*/
diff --git a/core/src/main/java/org/apache/shiro/authz/permission/DomainPermission.java b/core/src/main/java/org/apache/shiro/authz/permission/DomainPermission.java
index cfdc0b2dea..154b511b99 100644
--- a/core/src/main/java/org/apache/shiro/authz/permission/DomainPermission.java
+++ b/core/src/main/java/org/apache/shiro/authz/permission/DomainPermission.java
@@ -32,12 +32,12 @@
*/
public class DomainPermission extends WildcardPermission {
+ private static final long serialVersionUID = 1L;
+
private String domain;
private Setnull
all of the wrapped realms that
* implement the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface.
@@ -120,7 +121,8 @@ public void setPermissionResolver(PermissionResolver permissionResolver) {
/**
* Sets the internal {@link #getPermissionResolver} on any internal configured
- * {@link #getRealms Realms} that implement the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface.
+ * {@link #getRealms Realms} that implement
+ * the {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware}interface.
*
* This method is called after setting a permissionResolver on this ModularRealmAuthorizer via the
* {@link #setPermissionResolver(org.apache.shiro.authz.permission.PermissionResolver) setPermissionResolver} method.
@@ -147,13 +149,14 @@ protected void applyPermissionResolverToRealms() {
* if all realm instances will each configure their own permission resolver.
*
* @return the RolePermissionResolver to be used on all configured realms, or null
all of the wrapped realms that
* implement the {@link org.apache.shiro.authz.permission.RolePermissionResolverAware PermissionResolverAware} interface.
@@ -173,7 +176,8 @@ public void setRolePermissionResolver(RolePermissionResolver rolePermissionResol
/**
* Sets the internal {@link #getRolePermissionResolver} on any internal configured
- * {@link #getRealms Realms} that implement the {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface.
+ * {@link #getRealms Realms} that implement the
+ * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface.
*
* This method is called after setting a rolePermissionResolver on this ModularRealmAuthorizer via the
* {@link #setRolePermissionResolver(org.apache.shiro.authz.permission.RolePermissionResolver) setRolePermissionResolver} method.
@@ -205,8 +209,8 @@ protected void applyRolePermissionResolverToRealms() {
protected void assertRealmsConfigured() throws IllegalStateException {
CollectionSubject
is authenticated, and if not, throws an
* {@link org.apache.shiro.authz.UnauthenticatedException UnauthenticatedException} indicating the method is not allowed to be executed.
*
* @param a the annotation to inspect
* @throws org.apache.shiro.authz.UnauthenticatedException if the calling Subject
has not yet
- * authenticated.
+ * authenticated.
*/
public void assertAuthorized(Annotation a) throws UnauthenticatedException {
- if (a instanceof RequiresAuthentication && !getSubject().isAuthenticated() ) {
- throw new UnauthenticatedException( "The current Subject is not authenticated. Access denied." );
+ if (a instanceof RequiresAuthentication && !getSubject().isAuthenticated()) {
+ throw new UnauthenticatedException("The current Subject is not authenticated. Access denied.");
}
}
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingAnnotationMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingAnnotationMethodInterceptor.java
index 0728eca723..26d02dbad6 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingAnnotationMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingAnnotationMethodInterceptor.java
@@ -30,27 +30,26 @@
*
* @since 0.1
*/
-public abstract class AuthorizingAnnotationMethodInterceptor extends AnnotationMethodInterceptor
-{
-
+public abstract class AuthorizingAnnotationMethodInterceptor extends AnnotationMethodInterceptor {
+
/**
* Constructor that ensures the internal handler
is set which will be used to perform the
* authorization assertion checks when a supported annotation is encountered.
- * @param handler the internal handler
used to perform authorization assertion checks when a
- * supported annotation is encountered.
+ *
+ * @param handler the internal handler
used to perform authorization assertion checks when a
+ * supported annotation is encountered.
*/
- public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler ) {
+ public AuthorizingAnnotationMethodInterceptor(AuthorizingAnnotationHandler handler) {
super(handler);
}
/**
- *
* @param handler
* @param resolver
* @since 1.1
*/
- public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler handler,
- AnnotationResolver resolver) {
+ public AuthorizingAnnotationMethodInterceptor(AuthorizingAnnotationHandler handler,
+ AnnotationResolver resolver) {
super(handler, resolver);
}
@@ -59,15 +58,17 @@ public AuthorizingAnnotationMethodInterceptor( AuthorizingAnnotationHandler hand
* {@link #assertAuthorized(org.apache.shiro.aop.MethodInvocation) assertAuthorized} method first.
*
* @param methodInvocation the method invocation to check for authorization prior to allowing it to proceed/execute.
- * @return the return value from the method invocation (the value of {@link org.apache.shiro.aop.MethodInvocation#proceed() MethodInvocation.proceed()}).
+ * @return the return value from the method invocation
+ * (the value of {@link org.apache.shiro.aop.MethodInvocation#proceed() MethodInvocation.proceed()}).
* @throws org.apache.shiro.authz.AuthorizationException if the MethodInvocation
is not allowed to proceed.
- * @throws Throwable if any other error occurs.
+ * @throws Throwable if any other error occurs.
*/
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
assertAuthorized(methodInvocation);
return methodInvocation.proceed();
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Ensures the calling Subject is authorized to execute the specified MethodInvocation
.
*
@@ -81,14 +82,15 @@ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
*/
public void assertAuthorized(MethodInvocation mi) throws AuthorizationException {
try {
- ((AuthorizingAnnotationHandler)getHandler()).assertAuthorized(getAnnotation(mi));
- }
- catch(AuthorizationException ae) {
- // Annotation handler doesn't know why it was called, so add the information here if possible.
- // Don't wrap the exception here since we don't want to mask the specific exception, such as
- // UnauthenticatedException etc.
- if (ae.getCause() == null) ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
+ ((AuthorizingAnnotationHandler) getHandler()).assertAuthorized(getAnnotation(mi));
+ } catch (AuthorizationException ae) {
+ // Annotation handler doesn't know why it was called, so add the information here if possible.
+ // Don't wrap the exception here since we don't want to mask the specific exception, such as
+ // UnauthenticatedException etc.
+ if (ae.getCause() == null) {
+ ae.initCause(new AuthorizationException("Not authorized to invoke method: " + mi.getMethod()));
+ }
throw ae;
- }
+ }
}
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingMethodInterceptor.java
index 08b310aad2..c4fc450cb6 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/AuthorizingMethodInterceptor.java
@@ -42,6 +42,7 @@ public Object invoke(MethodInvocation methodInvocation) throws Throwable {
/**
* Asserts that the specified MethodInvocation is allowed to continue by performing any necessary authorization
* (access control) checks first.
+ *
* @param methodInvocation the MethodInvocation
to invoke.
* @throws AuthorizationException if the methodInvocation
should not be allowed to continue/execute.
*/
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/DenyAllAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/DenyAllAnnotationHandler.java
index c60b4a4911..73e087a601 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/DenyAllAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/DenyAllAnnotationHandler.java
@@ -35,7 +35,7 @@ public class DenyAllAnnotationHandler extends AuthorizingAnnotationHandler {
/**
* Default no-argument constructor that ensures this interceptor looks for
- *
+ * Subject
does not
@@ -38,7 +38,7 @@ public class GuestAnnotationHandler extends AuthorizingAnnotationHandler {
/**
* Default no-argument constructor that ensures this interceptor looks for
- *
+ * AuthorizingException
will be thrown indicating that execution is not allowed to continue.
*
* @param a the annotation to check for one or more roles
- * @throws org.apache.shiro.authz.AuthorizationException
- * if the calling Subject
is not a "guest".
+ * @throws org.apache.shiro.authz.AuthorizationException if the calling Subject
is not a "guest".
*/
public void assertAuthorized(Annotation a) throws AuthorizationException {
if (a instanceof RequiresGuest && getSubject().getPrincipal() != null) {
- throw new UnauthenticatedException("Attempting to perform a guest-only operation. The current Subject is " +
- "not a guest (they have been authenticated or remembered from a previous login). Access " +
- "denied.");
+ throw new UnauthenticatedException("Attempting to perform a guest-only operation. The current Subject is "
+ + "not a guest (they have been authenticated or remembered from a previous login). Access "
+ + "denied.");
}
}
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationMethodInterceptor.java
index 8828acbd83..a89409bbf0 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/GuestAnnotationMethodInterceptor.java
@@ -20,6 +20,7 @@
import org.apache.shiro.aop.AnnotationResolver;
+@SuppressWarnings("checkstyle:LineLength")
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest} annotation
* is declared, and if so, ensures the calling Subject
does not
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java
index a463123ad7..d943a28c77 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java
@@ -21,7 +21,6 @@
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
-import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import java.lang.annotation.Annotation;
@@ -54,17 +53,19 @@ protected String[] getAnnotationValue(Annotation a) {
return rpAnnotation.value();
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Ensures that the calling Subject
has the Annotation's specified permissions, and if not, throws an
* AuthorizingException
indicating access is denied.
*
* @param a the RequiresPermission annotation being inspected to check for one or more permissions
- * @throws org.apache.shiro.authz.AuthorizationException
- * if the calling Subject
does not have the permission(s) necessary to
- * continue access or execution.
+ * @throws org.apache.shiro.authz.AuthorizationException if the calling Subject
does not have the permission(s) necessary to
+ * continue access or execution.
*/
public void assertAuthorized(Annotation a) throws AuthorizationException {
- if (!(a instanceof RequiresPermissions)) return;
+ if (!(a instanceof RequiresPermissions)) {
+ return;
+ }
RequiresPermissions rpAnnotation = (RequiresPermissions) a;
String[] perms = getAnnotationValue(a);
@@ -88,8 +89,10 @@ public void assertAuthorized(Annotation a) throws AuthorizationException {
}
}
// Cause the exception if none of the role match, note that the exception message will be a bit misleading
- if (!hasAtLeastOnePermission) getSubject().checkPermission(perms[0]);
-
+ if (!hasAtLeastOnePermission) {
+ getSubject().checkPermission(perms[0]);
+ }
+
}
}
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationMethodInterceptor.java
index c4f8082641..1a20e486cc 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationMethodInterceptor.java
@@ -20,9 +20,11 @@
import org.apache.shiro.aop.AnnotationResolver;
+@SuppressWarnings("checkstyle:LineLength")
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotation is declared, and if so, performs
* a permission check to see if the calling Subject
is allowed to call the method.
+ *
* @since 0.9
*/
public class PermissionAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
@@ -37,7 +39,7 @@ public class PermissionAnnotationMethodInterceptor extends AuthorizingAnnotation
* {@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotations in a method declaration.
*/
public PermissionAnnotationMethodInterceptor() {
- super( new PermissionAnnotationHandler() );
+ super(new PermissionAnnotationHandler());
}
/**
@@ -45,7 +47,7 @@ public PermissionAnnotationMethodInterceptor() {
* @since 1.1
*/
public PermissionAnnotationMethodInterceptor(AnnotationResolver resolver) {
- super( new PermissionAnnotationHandler(), resolver);
+ super(new PermissionAnnotationHandler(), resolver);
}
/*
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandler.java
index 71a61e74cd..ca51e9a4e7 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandler.java
@@ -44,5 +44,6 @@ public PermitAllAnnotationHandler() {
* @param a the annotation to check for one or more roles
*/
@Override
- public void assertAuthorized(Annotation a) { }
+ public void assertAuthorized(Annotation a) {
+ }
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java
index db54424428..d827ce807d 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java
@@ -25,6 +25,7 @@
import java.lang.annotation.Annotation;
import java.util.Arrays;
+@SuppressWarnings("checkstyle:LineLength")
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles} annotation is declared, and if so, performs
* a role check to see if the calling Subject
is allowed to proceed.
@@ -41,17 +42,19 @@ public RoleAnnotationHandler() {
super(RequiresRoles.class);
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Ensures that the calling Subject
has the Annotation's specified roles, and if not, throws an
* AuthorizingException
indicating that access is denied.
*
* @param a the RequiresRoles annotation to use to check for one or more roles
- * @throws org.apache.shiro.authz.AuthorizationException
- * if the calling Subject
does not have the role(s) necessary to
- * proceed.
+ * @throws org.apache.shiro.authz.AuthorizationException if the calling Subject
does not have the role(s) necessary to
+ * proceed.
*/
public void assertAuthorized(Annotation a) throws AuthorizationException {
- if (!(a instanceof RequiresRoles)) return;
+ if (!(a instanceof RequiresRoles)) {
+ return;
+ }
RequiresRoles rrAnnotation = (RequiresRoles) a;
String[] roles = rrAnnotation.value();
@@ -67,9 +70,15 @@ public void assertAuthorized(Annotation a) throws AuthorizationException {
if (Logical.OR.equals(rrAnnotation.logical())) {
// Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
boolean hasAtLeastOneRole = false;
- for (String role : roles) if (getSubject().hasRole(role)) hasAtLeastOneRole = true;
+ for (String role : roles) {
+ if (getSubject().hasRole(role)) {
+ hasAtLeastOneRole = true;
+ }
+ }
// Cause the exception if none of the role match, note that the exception message will be a bit misleading
- if (!hasAtLeastOneRole) getSubject().checkRole(roles[0]);
+ if (!hasAtLeastOneRole) {
+ getSubject().checkRole(roles[0]);
+ }
}
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationMethodInterceptor.java
index a03404248b..2401e81d9c 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationMethodInterceptor.java
@@ -35,7 +35,7 @@ public class RoleAnnotationMethodInterceptor extends AuthorizingAnnotationMethod
* {@link RequiresRoles RequiresRoles} annotations in a method declaration.
*/
public RoleAnnotationMethodInterceptor() {
- super( new RoleAnnotationHandler() );
+ super(new RoleAnnotationHandler());
}
/**
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandler.java
index 467fc80a91..745d90e173 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandler.java
@@ -30,6 +30,7 @@
* @since 2.0
*/
public class RolesAllowedAnnotationHandler extends AuthorizingAnnotationHandler {
+
/**
* Default no-argument constructor that ensures this handler looks for
* {@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles} annotations.
@@ -38,18 +39,20 @@ public RolesAllowedAnnotationHandler() {
super(RolesAllowed.class);
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Ensures that the calling Subject
has one of the Annotation's specified roles, and if not, throws an
* AuthorizingException
indicating that access is denied.
*
* @param a the RolesAllowed annotation to use to check for one or more roles
- * @throws org.apache.shiro.authz.AuthorizationException
- * if the calling Subject
does not have the role necessary to
- * proceed.
+ * @throws org.apache.shiro.authz.AuthorizationException if the calling Subject
does not have the role necessary to
+ * proceed.
*/
@Override
public void assertAuthorized(Annotation a) throws AuthorizationException {
- if (!(a instanceof RolesAllowed)) return;
+ if (!(a instanceof RolesAllowed)) {
+ return;
+ }
RolesAllowed raAnnotation = (RolesAllowed) a;
String[] roles = raAnnotation.value();
@@ -63,8 +66,14 @@ public void assertAuthorized(Annotation a) throws AuthorizationException {
// Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
boolean hasAtLeastOneRole = false;
- for (String role : roles) if (getSubject().hasRole(role)) hasAtLeastOneRole = true;
+ for (String role : roles) {
+ if (getSubject().hasRole(role)) {
+ hasAtLeastOneRole = true;
+ }
+ }
// Cause the exception if none of the role match, note that the exception message will be a bit misleading
- if (!hasAtLeastOneRole) getSubject().checkRole(roles[0]);
+ if (!hasAtLeastOneRole) {
+ getSubject().checkRole(roles[0]);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationHandler.java
index d48ca81911..a3ebe94fb9 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationHandler.java
@@ -24,7 +24,7 @@
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.annotation.RequiresUser;
-
+@SuppressWarnings("checkstyle:LineLength")
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser} annotation
* is declared, and if so, ensures the calling Subject
is either
@@ -39,13 +39,14 @@ public class UserAnnotationHandler extends AuthorizingAnnotationHandler {
/**
* Default no-argument constructor that ensures this handler looks for
- *
+ * Subject
is a user, that is, they are either
* {@link org.apache.shiro.subject.Subject#isAuthenticated() authenticated} or remembered via remember
@@ -53,14 +54,13 @@ public UserAnnotationHandler() {
* AuthorizingException
indicating access is not allowed.
*
* @param a the RequiresUser annotation to check
- * @throws org.apache.shiro.authz.AuthorizationException
- * if the calling Subject
is not authenticated or remembered via rememberMe services.
+ * @throws org.apache.shiro.authz.AuthorizationException if the calling Subject
is not authenticated or remembered via rememberMe services.
*/
public void assertAuthorized(Annotation a) throws AuthorizationException {
if (a instanceof RequiresUser && getSubject().getPrincipal() == null) {
- throw new UnauthenticatedException("Attempting to perform a user-only operation. The current Subject is " +
- "not a user (they haven't been authenticated or remembered from a previous login). " +
- "Access denied.");
+ throw new UnauthenticatedException("Attempting to perform a user-only operation. The current Subject is "
+ + "not a user (they haven't been authenticated or remembered from a previous login). "
+ + "Access denied.");
}
}
}
diff --git a/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationMethodInterceptor.java
index 2b680ef0a0..3c5532b28f 100644
--- a/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationMethodInterceptor.java
+++ b/core/src/main/java/org/apache/shiro/authz/aop/UserAnnotationMethodInterceptor.java
@@ -20,6 +20,7 @@
import org.apache.shiro.aop.AnnotationResolver;
+@SuppressWarnings("checkstyle:LineLength")
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser} annotation
* is declared, and if so, ensures the calling Subject
is either
@@ -34,16 +35,15 @@ public class UserAnnotationMethodInterceptor extends AuthorizingAnnotationMethod
/**
* Default no-argument constructor that ensures this interceptor looks for
- *
+ * WildcardPermission
.
- * @since 1.3.0
+ *
* @param parts pre-split String parts.
+ * @since 1.3.0
*/
protected void setParts(List
* {@link Callable Callable} applicationWork = //instantiate or acquire Callable from somewhere
- * {@link Subject Subject} subject = {@link org.apache.shiro.SecurityUtils SecurityUtils}.{@link org.apache.shiro.SecurityUtils#getSubject() getSubject()};
+ * {@link Subject Subject} subject = {@link org.apache.shiro.SecurityUtils SecurityUtils}.
+ * {@link org.apache.shiro.SecurityUtils#getSubject() getSubject()};
* {@link Callable Callable} work = subject.{@link Subject#associateWith(Callable) associateWith(applicationWork)};
* {@link ExecutorService anExecutorService}.{@link ExecutorService#submit(Callable) submit(work)};
*
@@ -78,8 +85,8 @@ public void setTargetExecutorService(ExecutorService targetExecutorService) {
@Override
public void setTargetExecutor(Executor targetExecutor) {
if (!(targetExecutor instanceof ExecutorService)) {
- String msg = "The " + getClass().getName() + " implementation only accepts " +
- ExecutorService.class.getName() + " target instances.";
+ String msg = "The " + getClass().getName() + " implementation only accepts "
+ + ExecutorService.class.getName() + " target instances.";
throw new IllegalArgumentException(msg);
}
super.setTargetExecutor(targetExecutor);
diff --git a/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareScheduledExecutorService.java b/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareScheduledExecutorService.java
index 9013ec8275..227604b086 100644
--- a/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareScheduledExecutorService.java
+++ b/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareScheduledExecutorService.java
@@ -18,7 +18,12 @@
*/
package org.apache.shiro.concurrent;
-import java.util.concurrent.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
/**
* Same concept as the {@link SubjectAwareExecutorService} but additionally supports the
@@ -47,8 +52,8 @@ public void setTargetScheduledExecutorService(ScheduledExecutorService targetSch
@Override
public void setTargetExecutor(Executor targetExecutor) {
if (!(targetExecutor instanceof ScheduledExecutorService)) {
- String msg = "The " + getClass().getName() + " implementation only accepts " +
- ScheduledExecutorService.class.getName() + " target instances.";
+ String msg = "The " + getClass().getName() + " implementation only accepts "
+ + ScheduledExecutorService.class.getName() + " target instances.";
throw new IllegalArgumentException(msg);
}
super.setTargetExecutorService((ScheduledExecutorService) targetExecutor);
@@ -57,8 +62,8 @@ public void setTargetExecutor(Executor targetExecutor) {
@Override
public void setTargetExecutorService(ExecutorService targetExecutorService) {
if (!(targetExecutorService instanceof ScheduledExecutorService)) {
- String msg = "The " + getClass().getName() + " implementation only accepts " +
- ScheduledExecutorService.class.getName() + " target instances.";
+ String msg = "The " + getClass().getName() + " implementation only accepts "
+ + ScheduledExecutorService.class.getName() + " target instances.";
throw new IllegalArgumentException(msg);
}
super.setTargetExecutorService(targetExecutorService);
diff --git a/core/src/main/java/org/apache/shiro/concurrent/package-info.java b/core/src/main/java/org/apache/shiro/concurrent/package-info.java
index 9163cdd0c5..4d11d40b98 100644
--- a/core/src/main/java/org/apache/shiro/concurrent/package-info.java
+++ b/core/src/main/java/org/apache/shiro/concurrent/package-info.java
@@ -20,9 +20,9 @@
* {@link java.util.concurrent.Executor Executor}, {@link java.util.concurrent.ExecutorService ExecutorService},
* and {@link java.util.concurrent.ScheduledExecutorService ScheduledExecutorService} implementations for transparent
* {@link org.apache.shiro.subject.Subject Subject} association with threads in an asynchronous execution environment.
- *
- * @see SubjectAwareExecutor
- * @see SubjectAwareExecutorService
- * @see SubjectAwareScheduledExecutorService
+ *
+ * @see org.apache.shiro.concurrent.SubjectAwareExecutor
+ * @see org.apache.shiro.concurrent.SubjectAwareExecutorService
+ * @see org.apache.shiro.concurrent.SubjectAwareScheduledExecutorService
*/
-package org.apache.shiro.concurrent;
\ No newline at end of file
+package org.apache.shiro.concurrent;
diff --git a/core/src/main/java/org/apache/shiro/dao/package-info.java b/core/src/main/java/org/apache/shiro/dao/package-info.java
index d2798cd4c4..e91e186717 100644
--- a/core/src/main/java/org/apache/shiro/dao/package-info.java
+++ b/core/src/main/java/org/apache/shiro/dao/package-info.java
@@ -23,4 +23,4 @@
*
* @since 1.2
*/
-package org.apache.shiro.dao;
\ No newline at end of file
+package org.apache.shiro.dao;
diff --git a/core/src/main/java/org/apache/shiro/env/BasicIniEnvironment.java b/core/src/main/java/org/apache/shiro/env/BasicIniEnvironment.java
index 280809ffa5..c4abba0b9b 100644
--- a/core/src/main/java/org/apache/shiro/env/BasicIniEnvironment.java
+++ b/core/src/main/java/org/apache/shiro/env/BasicIniEnvironment.java
@@ -19,6 +19,7 @@
package org.apache.shiro.env;
import java.util.function.Function;
+
import org.apache.shiro.config.Ini;
import org.apache.shiro.ini.IniSecurityManagerFactory;
diff --git a/core/src/main/java/org/apache/shiro/env/DefaultEnvironment.java b/core/src/main/java/org/apache/shiro/env/DefaultEnvironment.java
index 45b3433906..c243db88b3 100644
--- a/core/src/main/java/org/apache/shiro/env/DefaultEnvironment.java
+++ b/core/src/main/java/org/apache/shiro/env/DefaultEnvironment.java
@@ -73,13 +73,13 @@ public DefaultEnvironment(Mapnull
.
* @since 1.4
*/
@@ -74,6 +79,7 @@ public void setIni(Ini ini) {
/**
* Sets the default objects used by this factory. These defaults may be used in conjunction with the INI
* configuration.
+ *
* @param defaultBeans String to object mapping used for default configuration in this factory.
* @since 1.4
*/
@@ -86,16 +92,16 @@ public void setDefaults(Mapnull
; if a not so well-behaved
- * JNDI implementations returns null, a NamingException gets thrown)
+ * JNDI implementations returns null, a NamingException gets thrown)
* @throws NamingException if there is no object with the given
* name bound to JNDI
*/
public Object lookup(final String name) throws NamingException {
- log.debug("Looking up JNDI object with name '{}'", name);
+ LOGGER.debug("Looking up JNDI object with name '{}'", name);
return execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
Object located = ctx.lookup(name);
@@ -155,16 +156,16 @@ public Object doInContext(Context ctx) throws NamingException {
* if the value is Object.class
, this method will succeed whatever
* the class of the returned instance.
* @return object found (cannot be null
; if a not so well-behaved
- * JNDI implementations returns null, a NamingException gets thrown)
+ * JNDI implementations returns null, a NamingException gets thrown)
* @throws NamingException if there is no object with the given
* name bound to JNDI
*/
public Object lookup(String name, Class requiredType) throws NamingException {
Object jndiObject = lookup(name);
if (requiredType != null && !requiredType.isInstance(jndiObject)) {
- String msg = "Jndi object acquired under name '" + name + "' is of type [" +
- jndiObject.getClass().getName() + "] and not assignable to the required type [" +
- requiredType.getName() + "].";
+ String msg = "Jndi object acquired under name '" + name + "' is of type ["
+ + jndiObject.getClass().getName() + "] and not assignable to the required type ["
+ + requiredType.getName() + "].";
throw new NamingException(msg);
}
return jndiObject;
@@ -178,7 +179,7 @@ public Object lookup(String name, Class requiredType) throws NamingException {
* @throws NamingException thrown by JNDI, mostly name already bound
*/
public void bind(final String name, final Object object) throws NamingException {
- log.debug("Binding JNDI object with name '{}'", name);
+ LOGGER.debug("Binding JNDI object with name '{}'", name);
execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
ctx.bind(name, object);
@@ -196,7 +197,7 @@ public Object doInContext(Context ctx) throws NamingException {
* @throws NamingException thrown by JNDI
*/
public void rebind(final String name, final Object object) throws NamingException {
- log.debug("Rebinding JNDI object with name '{}'", name);
+ LOGGER.debug("Rebinding JNDI object with name '{}'", name);
execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
ctx.rebind(name, object);
@@ -212,7 +213,7 @@ public Object doInContext(Context ctx) throws NamingException {
* @throws NamingException thrown by JNDI, mostly name not found
*/
public void unbind(final String name) throws NamingException {
- log.debug("Unbinding JNDI object with name '{}'", name);
+ LOGGER.debug("Unbinding JNDI object with name '{}'", name);
execute(new JndiCallback() {
public Object doInContext(Context ctx) throws NamingException {
ctx.unbind(name);
diff --git a/core/src/main/java/org/apache/shiro/ldap/package-info.java b/core/src/main/java/org/apache/shiro/ldap/package-info.java
index 48ccc3b6c5..bef3f3780d 100644
--- a/core/src/main/java/org/apache/shiro/ldap/package-info.java
+++ b/core/src/main/java/org/apache/shiro/ldap/package-info.java
@@ -17,10 +17,9 @@
* under the License.
*/
-package org.apache.shiro.ldap;
-
/**
* Support for accessing LDAP data sources.
*
* @since 1.2
- */
\ No newline at end of file
+ */
+package org.apache.shiro.ldap;
diff --git a/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java b/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java
index 0d1b13d58d..0dcf38c69b 100644
--- a/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java
+++ b/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java
@@ -18,7 +18,9 @@
*/
package org.apache.shiro.mgt;
+import java.util.Objects;
import java.util.function.Supplier;
+
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
@@ -68,7 +70,7 @@ public abstract class AbstractRememberMeManager implements RememberMeManager {
/**
* private inner log instance.
*/
- private static final Logger log = LoggerFactory.getLogger(AbstractRememberMeManager.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRememberMeManager.class);
/**
* Serializer to use for converting PrincipalCollection instances to/from byte arrays
@@ -78,7 +80,8 @@ public abstract class AbstractRememberMeManager implements RememberMeManager {
/**
* Cipher to use for encrypting/decrypting serialized byte arrays for added security
*/
- private CipherService cipherService = new AesCipherService();;
+ private CipherService cipherService = new AesCipherService();
+ ;
/**
* Cipher encryption key to use with the Cipher when encrypting data
@@ -117,7 +120,7 @@ public AbstractRememberMeManager(SupplierAuthenticator
instance that this SecurityManager uses to perform all
- * authentication operations.
+ * authentication operations.
*/
public Authenticator getAuthenticator() {
return authenticator;
diff --git a/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java b/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java
index e2555d8bf9..daf2d27664 100644
--- a/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java
+++ b/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java
@@ -145,6 +145,7 @@ public void checkPermissions(PrincipalCollection principals, String... permissio
this.authorizer.checkPermissions(principals, permissions);
}
+ @SuppressWarnings("checkstyle:LineLength")
public void checkPermissions(PrincipalCollection principals, CollectionRealm
diff --git a/core/src/main/java/org/apache/shiro/mgt/SessionStorageEvaluator.java b/core/src/main/java/org/apache/shiro/mgt/SessionStorageEvaluator.java
index ebdd9dfed6..8a062b213f 100644
--- a/core/src/main/java/org/apache/shiro/mgt/SessionStorageEvaluator.java
+++ b/core/src/main/java/org/apache/shiro/mgt/SessionStorageEvaluator.java
@@ -54,8 +54,8 @@ public interface SessionStorageEvaluator {
*
* @param subject the {@code Subject} for which session state persistence may be enabled
* @return {@code true} if the specified {@code Subject}'s
- * {@link org.apache.shiro.subject.Subject#getSession() session} may be used to persist that Subject's
- * state, {@code false} otherwise.
+ * {@link org.apache.shiro.subject.Subject#getSession() session} may be used to persist that Subject's
+ * state, {@code false} otherwise.
* @see Subject#getSession()
* @see Subject#getSession(boolean)
*/
diff --git a/core/src/main/java/org/apache/shiro/mgt/SessionsSecurityManager.java b/core/src/main/java/org/apache/shiro/mgt/SessionsSecurityManager.java
index abe60ece28..3f9dfd3f73 100644
--- a/core/src/main/java/org/apache/shiro/mgt/SessionsSecurityManager.java
+++ b/core/src/main/java/org/apache/shiro/mgt/SessionsSecurityManager.java
@@ -97,6 +97,7 @@ public SessionManager getSessionManager() {
return this.sessionManager;
}
+ @SuppressWarnings("checkstyle:LineLength")
/**
* Calls {@link org.apache.shiro.mgt.AuthorizingSecurityManager#afterCacheManagerSet() super.afterCacheManagerSet()} and then immediately calls
* {@link #applyCacheManagerToSessionManager() applyCacheManagerToSessionManager()} to ensure the
@@ -144,7 +145,7 @@ protected void applyCacheManagerToSessionManager() {
protected void applyEventBusToSessionManager() {
EventBus eventBus = getEventBus();
if (eventBus != null && this.sessionManager instanceof EventBusAware) {
- ((EventBusAware)this.sessionManager).setEventBus(eventBus);
+ ((EventBusAware) this.sessionManager).setEventBus(eventBus);
}
}
diff --git a/core/src/main/java/org/apache/shiro/realm/AuthenticatingRealm.java b/core/src/main/java/org/apache/shiro/realm/AuthenticatingRealm.java
index 54d3963a1d..be0395352a 100644
--- a/core/src/main/java/org/apache/shiro/realm/AuthenticatingRealm.java
+++ b/core/src/main/java/org/apache/shiro/realm/AuthenticatingRealm.java
@@ -112,9 +112,7 @@
*/
public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {
- //TODO - complete JavaDoc
-
- private static final Logger log = LoggerFactory.getLogger(AuthenticatingRealm.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticatingRealm.class);
private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger();
@@ -191,7 +189,7 @@ public AuthenticatingRealm(CacheManager cacheManager, CredentialsMatcher matcher
* value is a {@link org.apache.shiro.authc.credential.SimpleCredentialsMatcher SimpleCredentialsMatcher} instance.
*
* @return the CredentialsMatcher
used during an authentication attempt to verify submitted
- * credentials with those stored in the system.
+ * credentials with those stored in the system.
*/
public CredentialsMatcher getCredentialsMatcher() {
return credentialsMatcher;
@@ -264,7 +262,7 @@ public void setAuthenticationCache(Cache
Implementations would need to implement the - * {@link #queryForAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken ,LdapContextFactory)} and - * {@link #queryForAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection ,LdapContextFactory)} abstract methods.
+ * {@link #queryForAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken, LdapContextFactory)} and + * {@link #queryForAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection, LdapContextFactory)} abstract methods. * *By default, this implementation will create an instance of {@link JndiLdapContextFactory} to use for * creating LDAP connections using the principalSuffix, searchBase, url, systemUsername, and systemPassword properties @@ -46,19 +46,17 @@ * sufficient. If more customized connections are needed, you should inject a custom {@link LdapContextFactory}, which * will cause these properties specified on the realm to be ignored.
* - * @see #queryForAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken , LdapContextFactory) - * @see #queryForAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection , LdapContextFactory) + * @see #queryForAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken, LdapContextFactory) + * @see #queryForAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection, LdapContextFactory) * @since 0.1 */ public abstract class AbstractLdapRealm extends AuthorizingRealm { - //TODO - complete JavaDoc - /*-------------------------------------------- | C O N S T A N T S | ============================================*/ - private static final Logger log = LoggerFactory.getLogger(AbstractLdapRealm.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractLdapRealm.class); /*-------------------------------------------- | I N S T A N C E V A R I A B L E S | @@ -69,26 +67,26 @@ public abstract class AbstractLdapRealm extends AuthorizingRealm { * AD Example: * User's Principal Name be "John.Doe" * User's E-Mail Address be "John.Doe@example.com" - * * For the example below, set: - * realm.principalSuffix = @example.com - * + * realm.principalSuffix = @example.com * Only then, "John.Doe" and also "John.Doe@example.com" can authorize against groups */ - protected String principalSuffix = null; + protected String principalSuffix; - protected String searchBase = null; + protected String searchBase; - protected String url = null; + protected String url; - protected String systemUsername = null; + protected String systemUsername; - protected String systemPassword = null; + protected String systemPassword; - //SHIRO-115 - prevent potential code injection: + /** + * SHIRO-115 - prevent potential code injection. + */ protected String searchFilter = "(&(objectClass=*)(userPrincipalName={0}))"; - private LdapContextFactory ldapContextFactory = null; + private LdapContextFactory ldapContextFactory; /*-------------------------------------------- | C O N S T R U C T O R S | @@ -177,8 +175,8 @@ protected void onInit() { private LdapContextFactory ensureContextFactory() { if (this.ldapContextFactory == null) { - if (log.isDebugEnabled()) { - log.debug("No LdapContextFactory specified - creating a default instance."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No LdapContextFactory specified - creating a default instance."); } JndiLdapContextFactory defaultFactory = new JndiLdapContextFactory(); @@ -230,7 +228,9 @@ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal * @return an {@link AuthenticationInfo} instance containing information retrieved from the LDAP server. * @throws NamingException if any LDAP errors occur during the search. */ - protected abstract AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException; + @SuppressWarnings("checkstyle:LineLength") + protected abstract AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) + throws NamingException; /** @@ -243,6 +243,8 @@ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal * @return an {@link AuthorizationInfo} instance containing information retrieved from the LDAP server. * @throws NamingException if any LDAP errors occur during the search. */ - protected abstract AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principal, LdapContextFactory ldapContextFactory) throws NamingException; + @SuppressWarnings("checkstyle:LineLength") + protected abstract AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principal, LdapContextFactory ldapContextFactory) + throws NamingException; } diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/DefaultLdapRealm.java b/core/src/main/java/org/apache/shiro/realm/ldap/DefaultLdapRealm.java index 75f477e44e..ed01701e29 100644 --- a/core/src/main/java/org/apache/shiro/realm/ldap/DefaultLdapRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/ldap/DefaultLdapRealm.java @@ -1,430 +1,430 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.shiro.realm.ldap; - -import org.apache.shiro.authc.AuthenticationException; -import org.apache.shiro.authc.AuthenticationInfo; -import org.apache.shiro.authc.AuthenticationToken; -import org.apache.shiro.authc.SimpleAuthenticationInfo; -import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher; -import org.apache.shiro.authz.AuthorizationException; -import org.apache.shiro.authz.AuthorizationInfo; -import org.apache.shiro.ldap.UnsupportedAuthenticationMechanismException; -import org.apache.shiro.realm.AuthorizingRealm; -import org.apache.shiro.subject.PrincipalCollection; -import org.apache.shiro.lang.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.naming.AuthenticationNotSupportedException; -import javax.naming.NamingException; -import javax.naming.ldap.LdapContext; - -/** - * An LDAP {@link org.apache.shiro.realm.Realm Realm} implementation utilizing Sun's/Oracle's - * JNDI API as an LDAP API. This is - * Shiro's default implementation for supporting LDAP, as using the JNDI API has been a common approach for Java LDAP - * support for many years. - * - * This realm implementation and its backing {@link JndiLdapContextFactory} should cover 99% of all Shiro-related LDAP - * authentication and authorization needs. However, if it does not suit your needs, you might want to look into - * creating your own realm using an alternative, perhaps more robust, LDAP communication API, such as the - * Apache LDAP API. - *- * [main] - * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm - * ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com - * ldapRealm.contextFactory.url = ldap://ldapHost:389 - * ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 - * ldapRealm.contextFactory.environment[some.obscure.jndi.key] = some value - * ... - *- * The default {@link #setContextFactory contextFactory} instance is a {@link JndiLdapContextFactory}. See that - * class's JavaDoc for more information on configuring the LDAP connection as well as specifying JNDI environment - * properties as necessary. - * - * @see JndiLdapContextFactory - * - * @since 1.3 - */ -public class DefaultLdapRealm extends AuthorizingRealm { - - private static final Logger log = LoggerFactory.getLogger(DefaultLdapRealm.class); - - //The zero index currently means nothing, but could be utilized in the future for other substitution techniques. - private static final String USERDN_SUBSTITUTION_TOKEN = "{0}"; - - private String userDnPrefix; - private String userDnSuffix; - - /*-------------------------------------------- - | I N S T A N C E V A R I A B L E S | - ============================================*/ - /** - * The LdapContextFactory instance used to acquire {@link javax.naming.ldap.LdapContext LdapContext}'s at runtime - * to acquire connections to the LDAP directory to perform authentication attempts and authorization queries. - */ - private LdapContextFactory contextFactory; - - /*-------------------------------------------- - | C O N S T R U C T O R S | - ============================================*/ - - /** - * Default no-argument constructor that defaults the internal {@link LdapContextFactory} instance to a - * {@link JndiLdapContextFactory}. - */ - public DefaultLdapRealm() { - //Credentials Matching is not necessary - the LDAP directory will do it automatically: - setCredentialsMatcher(new AllowAllCredentialsMatcher()); - //Any Object principal and Object credentials may be passed to the LDAP provider, so accept any token: - setAuthenticationTokenClass(AuthenticationToken.class); - this.contextFactory = new JndiLdapContextFactory(); - } - - /*-------------------------------------------- - | A C C E S S O R S / M O D I F I E R S | - ============================================*/ - - /** - * Returns the User DN prefix to use when building a runtime User DN value or {@code null} if no - * {@link #getUserDnTemplate() userDnTemplate} has been configured. If configured, this value is the text that - * occurs before the {@link #USERDN_SUBSTITUTION_TOKEN} in the {@link #getUserDnTemplate() userDnTemplate} value. - * - * @return the the User DN prefix to use when building a runtime User DN value or {@code null} if no - * {@link #getUserDnTemplate() userDnTemplate} has been configured. - */ - protected String getUserDnPrefix() { - return userDnPrefix; - } - - /** - * Returns the User DN suffix to use when building a runtime User DN value. or {@code null} if no - * {@link #getUserDnTemplate() userDnTemplate} has been configured. If configured, this value is the text that - * occurs after the {@link #USERDN_SUBSTITUTION_TOKEN} in the {@link #getUserDnTemplate() userDnTemplate} value. - * - * @return the User DN suffix to use when building a runtime User DN value or {@code null} if no - * {@link #getUserDnTemplate() userDnTemplate} has been configured. - */ - protected String getUserDnSuffix() { - return userDnSuffix; - } - - /*-------------------------------------------- - | M E T H O D S | - ============================================*/ - - /** - * Sets the User Distinguished Name (DN) template to use when creating User DNs at runtime. A User DN is an LDAP - * fully-qualified unique user identifier which is required to establish a connection with the LDAP - * directory to authenticate users and query for authorization information. - *
uid=jsmith,ou=users,dc=mycompany,dc=com- * - * in which case you would set this property with the following template value: - * - *
uid={0},ou=users,dc=mycompany,dc=com- * - * If no template is configured, the raw {@code AuthenticationToken} - * {@link AuthenticationToken#getPrincipal() principal} will be used as the LDAP principal. This is likely - * incorrect as most LDAP directories expect a fully-qualified User DN as opposed to the raw uid or username. So, - * ensure you set this property to match your environment! - * - * @param template the User Distinguished Name template to use for runtime substitution - * @throws IllegalArgumentException if the template is null, empty, or does not contain the - * {@code {0}} substitution token. - * @see LdapContextFactory#getLdapContext(Object,Object) - */ - public void setUserDnTemplate(String template) throws IllegalArgumentException { - if (!StringUtils.hasText(template)) { - String msg = "User DN template cannot be null or empty."; - throw new IllegalArgumentException(msg); - } - int index = template.indexOf(USERDN_SUBSTITUTION_TOKEN); - if (index < 0) { - String msg = "User DN template must contain the '" + - USERDN_SUBSTITUTION_TOKEN + "' replacement token to understand where to " + - "insert the runtime authentication principal."; - throw new IllegalArgumentException(msg); - } - String prefix = template.substring(0, index); - String suffix = template.substring(prefix.length() + USERDN_SUBSTITUTION_TOKEN.length()); - if (log.isDebugEnabled()) { - log.debug("Determined user DN prefix [{}] and suffix [{}]", prefix, suffix); - } - this.userDnPrefix = prefix; - this.userDnSuffix = suffix; - } - - /** - * Returns the User Distinguished Name (DN) template to use when creating User DNs at runtime - see the - * {@link #setUserDnTemplate(String) setUserDnTemplate} JavaDoc for a full explanation. - * - * @return the User Distinguished Name (DN) template to use when creating User DNs at runtime. - */ - public String getUserDnTemplate() { - return getUserDn(USERDN_SUBSTITUTION_TOKEN); - } - - /** - * Returns the LDAP User Distinguished Name (DN) to use when acquiring an - * {@link javax.naming.ldap.LdapContext LdapContext} from the {@link LdapContextFactory}. - * - * If the the {@link #getUserDnTemplate() userDnTemplate} property has been set, this implementation will construct - * the User DN by substituting the specified {@code principal} into the configured template. If the - * {@link #getUserDnTemplate() userDnTemplate} has not been set, the method argument will be returned directly - * (indicating that the submitted authentication token principal is the User DN). - * - * @param principal the principal to substitute into the configured {@link #getUserDnTemplate() userDnTemplate}. - * @return the constructed User DN to use at runtime when acquiring an {@link javax.naming.ldap.LdapContext}. - * @throws IllegalArgumentException if the method argument is null or empty - * @throws IllegalStateException if the {@link #getUserDnTemplate userDnTemplate} has not been set. - * @see LdapContextFactory#getLdapContext(Object, Object) - */ - protected String getUserDn(String principal) throws IllegalArgumentException, IllegalStateException { - if (!StringUtils.hasText(principal)) { - throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction."); - } - String prefix = getUserDnPrefix(); - String suffix = getUserDnSuffix(); - if (prefix == null && suffix == null) { - log.debug("userDnTemplate property has not been configured, indicating the submitted " + - "AuthenticationToken's principal is the same as the User DN. Returning the method argument " + - "as is."); - return principal; - } - - int prefixLength = prefix != null ? prefix.length() : 0; - int suffixLength = suffix != null ? suffix.length() : 0; - StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength); - if (prefixLength > 0) { - sb.append(prefix); - } - sb.append(principal); - if (suffixLength > 0) { - sb.append(suffix); - } - return sb.toString(); - } - - /** - * Sets the LdapContextFactory instance used to acquire connections to the LDAP directory during authentication - * attempts and authorization queries. Unless specified otherwise, the default is a {@link JndiLdapContextFactory} - * instance. - * - * @param contextFactory the LdapContextFactory instance used to acquire connections to the LDAP directory during - * authentication attempts and authorization queries - */ - @SuppressWarnings({"UnusedDeclaration"}) - public void setContextFactory(LdapContextFactory contextFactory) { - this.contextFactory = contextFactory; - } - - /** - * Returns the LdapContextFactory instance used to acquire connections to the LDAP directory during authentication - * attempts and authorization queries. Unless specified otherwise, the default is a {@link JndiLdapContextFactory} - * instance. - * - * @return the LdapContextFactory instance used to acquire connections to the LDAP directory during - * authentication attempts and authorization queries - */ - public LdapContextFactory getContextFactory() { - return this.contextFactory; - } - - /*-------------------------------------------- - | M E T H O D S | - ============================================*/ - - /** - * Delegates to {@link #queryForAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken, LdapContextFactory)}, - * wrapping any {@link NamingException}s in a Shiro {@link AuthenticationException} to satisfy the parent method - * signature. - * - * @param token the authentication token containing the user's principal and credentials. - * @return the {@link AuthenticationInfo} acquired after a successful authentication attempt - * @throws AuthenticationException if the authentication attempt fails or if a - * {@link NamingException} occurs. - */ - protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { - AuthenticationInfo info; - try { - info = queryForAuthenticationInfo(token, getContextFactory()); - } catch (AuthenticationNotSupportedException e) { - String msg = "Unsupported configured authentication mechanism"; - throw new UnsupportedAuthenticationMechanismException(msg, e); - } catch (javax.naming.AuthenticationException e) { - throw new AuthenticationException("LDAP authentication failed.", e); - } catch (NamingException e) { - String msg = "LDAP naming error while attempting to authenticate user."; - throw new AuthenticationException(msg, e); - } - - return info; - } - - - protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { - AuthorizationInfo info; - try { - info = queryForAuthorizationInfo(principals, getContextFactory()); - } catch (NamingException e) { - String msg = "LDAP naming error while attempting to retrieve authorization for user [" + principals + "]."; - throw new AuthorizationException(msg, e); - } - - return info; - } - - /** - * Returns the principal to use when creating the LDAP connection for an authentication attempt. - * - * This implementation uses a heuristic: it checks to see if the specified token's - * {@link AuthenticationToken#getPrincipal() principal} is a {@code String}, and if so, - * {@link #getUserDn(String) converts it} from what is - * assumed to be a raw uid or username {@code String} into a User DN {@code String}. Almost all LDAP directories - * expect the authentication connection to present a User DN and not an unqualified username or uid. - * - * If the token's {@code principal} is not a String, it is assumed to already be in the format supported by the - * underlying {@link LdapContextFactory} implementation and the raw principal is returned directly. - * - * @param token the {@link AuthenticationToken} submitted during the authentication process - * @return the User DN or raw principal to use to acquire the LdapContext. - * @see LdapContextFactory#getLdapContext(Object, Object) - */ - protected Object getLdapPrincipal(AuthenticationToken token) { - Object principal = token.getPrincipal(); - if (principal instanceof String) { - String sPrincipal = (String) principal; - return getUserDn(sPrincipal); - } - return principal; - } - - /** - * This implementation opens an LDAP connection using the token's - * {@link #getLdapPrincipal(org.apache.shiro.authc.AuthenticationToken) discovered principal} and provided - * {@link AuthenticationToken#getCredentials() credentials}. If the connection opens successfully, the - * authentication attempt is immediately considered successful and a new - * {@link AuthenticationInfo} instance is - * {@link #createAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken, Object, Object, javax.naming.ldap.LdapContext) created} - * and returned. If the connection cannot be opened, either because LDAP authentication failed or some other - * JNDI problem, an {@link NamingException} will be thrown. - * - * @param token the submitted authentication token that triggered the authentication attempt. - * @param ldapContextFactory factory used to retrieve LDAP connections. - * @return an {@link AuthenticationInfo} instance representing the authenticated user's information. - * @throws NamingException if any LDAP errors occur. - */ - protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, - LdapContextFactory ldapContextFactory) - throws NamingException { - - Object principal = token.getPrincipal(); - Object credentials = token.getCredentials(); - - log.debug("Authenticating user '{}' through LDAP", principal); - - principal = getLdapPrincipal(token); - - LdapContext ctx = null; - try { - ctx = ldapContextFactory.getLdapContext(principal, credentials); - //context was opened successfully, which means their credentials were valid. Return the AuthenticationInfo: - return createAuthenticationInfo(token, principal, credentials, ctx); - } finally { - LdapUtils.closeContext(ctx); - } - } - - /** - * Returns the {@link AuthenticationInfo} resulting from a Subject's successful LDAP authentication attempt. - * - * This implementation ignores the {@code ldapPrincipal}, {@code ldapCredentials}, and the opened - * {@code ldapContext} arguments and merely returns an {@code AuthenticationInfo} instance mirroring the - * submitted token's principal and credentials. This is acceptable because this method is only ever invoked after - * a successful authentication attempt, which means the provided principal and credentials were correct, and can - * be used directly to populate the (now verified) {@code AuthenticationInfo}. - * - * Subclasses however are free to override this method for more advanced construction logic. - * - * @param token the submitted {@code AuthenticationToken} that resulted in a successful authentication - * @param ldapPrincipal the LDAP principal used when creating the LDAP connection. Unlike the token's - * {@link AuthenticationToken#getPrincipal() principal}, this value is usually a constructed - * User DN and not a simple username or uid. The exact value is depending on the - * configured - * - * LDAP authentication mechanism in use. - * @param ldapCredentials the LDAP credentials used when creating the LDAP connection. - * @param ldapContext the LdapContext created that resulted in a successful authentication. It can be used - * further by subclasses for more complex operations. It does not need to be closed - - * it will be closed automatically after this method returns. - * @return the {@link AuthenticationInfo} resulting from a Subject's successful LDAP authentication attempt. - * @throws NamingException if there was any problem using the {@code LdapContext} - */ - @SuppressWarnings({"UnusedDeclaration"}) - protected AuthenticationInfo createAuthenticationInfo(AuthenticationToken token, Object ldapPrincipal, - Object ldapCredentials, LdapContext ldapContext) - throws NamingException { - return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName()); - } - - - /** - * Method that should be implemented by subclasses to build an - * {@link AuthorizationInfo} object by querying the LDAP context for the - * specified principal. - * - * @param principals the principals of the Subject whose AuthenticationInfo should be queried from the LDAP server. - * @param ldapContextFactory factory used to retrieve LDAP connections. - * @return an {@link AuthorizationInfo} instance containing information retrieved from the LDAP server. - * @throws NamingException if any LDAP errors occur during the search. - */ - protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, - LdapContextFactory ldapContextFactory) throws NamingException { - return null; - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.shiro.realm.ldap; + +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher; +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.ldap.UnsupportedAuthenticationMechanismException; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.lang.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.naming.AuthenticationNotSupportedException; +import javax.naming.NamingException; +import javax.naming.ldap.LdapContext; + +/** + * An LDAP {@link org.apache.shiro.realm.Realm Realm} implementation utilizing Sun's/Oracle's + * JNDI API as an LDAP API. This is + * Shiro's default implementation for supporting LDAP, as using the JNDI API has been a common approach for Java LDAP + * support for many years. + * + * This realm implementation and its backing {@link JndiLdapContextFactory} should cover 99% of all Shiro-related LDAP + * authentication and authorization needs. However, if it does not suit your needs, you might want to look into + * creating your own realm using an alternative, perhaps more robust, LDAP communication API, such as the + * Apache LDAP API. + *
+ * [main] + * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm + * ldapRealm.userDnTemplate = uid={0},ou=users,dc=mycompany,dc=com + * ldapRealm.contextFactory.url = ldap://ldapHost:389 + * ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 + * ldapRealm.contextFactory.environment[some.obscure.jndi.key] = some value + * ... + *+ * The default {@link #setContextFactory contextFactory} instance is a {@link JndiLdapContextFactory}. See that + * class's JavaDoc for more information on configuring the LDAP connection as well as specifying JNDI environment + * properties as necessary. + * + * @see JndiLdapContextFactory + * @since 1.3 + */ +public class DefaultLdapRealm extends AuthorizingRealm { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLdapRealm.class); + + //The zero index currently means nothing, but could be utilized in the future for other substitution techniques. + private static final String USERDN_SUBSTITUTION_TOKEN = "{0}"; + + private String userDnPrefix; + private String userDnSuffix; + + /*-------------------------------------------- + | I N S T A N C E V A R I A B L E S | + ============================================*/ + /** + * The LdapContextFactory instance used to acquire {@link javax.naming.ldap.LdapContext LdapContext}'s at runtime + * to acquire connections to the LDAP directory to perform authentication attempts and authorization queries. + */ + private LdapContextFactory contextFactory; + + /*-------------------------------------------- + | C O N S T R U C T O R S | + ============================================*/ + + /** + * Default no-argument constructor that defaults the internal {@link LdapContextFactory} instance to a + * {@link JndiLdapContextFactory}. + */ + public DefaultLdapRealm() { + //Credentials Matching is not necessary - the LDAP directory will do it automatically: + setCredentialsMatcher(new AllowAllCredentialsMatcher()); + //Any Object principal and Object credentials may be passed to the LDAP provider, so accept any token: + setAuthenticationTokenClass(AuthenticationToken.class); + this.contextFactory = new JndiLdapContextFactory(); + } + + /*-------------------------------------------- + | A C C E S S O R S / M O D I F I E R S | + ============================================*/ + + /** + * Returns the User DN prefix to use when building a runtime User DN value or {@code null} if no + * {@link #getUserDnTemplate() userDnTemplate} has been configured. If configured, this value is the text that + * occurs before the {@link #USERDN_SUBSTITUTION_TOKEN} in the {@link #getUserDnTemplate() userDnTemplate} value. + * + * @return the the User DN prefix to use when building a runtime User DN value or {@code null} if no + * {@link #getUserDnTemplate() userDnTemplate} has been configured. + */ + protected String getUserDnPrefix() { + return userDnPrefix; + } + + /** + * Returns the User DN suffix to use when building a runtime User DN value. or {@code null} if no + * {@link #getUserDnTemplate() userDnTemplate} has been configured. If configured, this value is the text that + * occurs after the {@link #USERDN_SUBSTITUTION_TOKEN} in the {@link #getUserDnTemplate() userDnTemplate} value. + * + * @return the User DN suffix to use when building a runtime User DN value or {@code null} if no + * {@link #getUserDnTemplate() userDnTemplate} has been configured. + */ + protected String getUserDnSuffix() { + return userDnSuffix; + } + + /*-------------------------------------------- + | M E T H O D S | + ============================================*/ + + /** + * Sets the User Distinguished Name (DN) template to use when creating User DNs at runtime. A User DN is an LDAP + * fully-qualified unique user identifier which is required to establish a connection with the LDAP + * directory to authenticate users and query for authorization information. + *
uid=jsmith,ou=users,dc=mycompany,dc=com+ * + * in which case you would set this property with the following template value: + * + *
uid={0},ou=users,dc=mycompany,dc=com+ * + * If no template is configured, the raw {@code AuthenticationToken} + * {@link AuthenticationToken#getPrincipal() principal} will be used as the LDAP principal. This is likely + * incorrect as most LDAP directories expect a fully-qualified User DN as opposed to the raw uid or username. So, + * ensure you set this property to match your environment! + * + * @param template the User Distinguished Name template to use for runtime substitution + * @throws IllegalArgumentException if the template is null, empty, or does not contain the + * {@code {0}} substitution token. + * @see LdapContextFactory#getLdapContext(Object, Object) + */ + public void setUserDnTemplate(String template) throws IllegalArgumentException { + if (!StringUtils.hasText(template)) { + String msg = "User DN template cannot be null or empty."; + throw new IllegalArgumentException(msg); + } + int index = template.indexOf(USERDN_SUBSTITUTION_TOKEN); + if (index < 0) { + String msg = "User DN template must contain the '" + + USERDN_SUBSTITUTION_TOKEN + "' replacement token to understand where to " + + "insert the runtime authentication principal."; + throw new IllegalArgumentException(msg); + } + String prefix = template.substring(0, index); + String suffix = template.substring(prefix.length() + USERDN_SUBSTITUTION_TOKEN.length()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Determined user DN prefix [{}] and suffix [{}]", prefix, suffix); + } + this.userDnPrefix = prefix; + this.userDnSuffix = suffix; + } + + /** + * Returns the User Distinguished Name (DN) template to use when creating User DNs at runtime - see the + * {@link #setUserDnTemplate(String) setUserDnTemplate} JavaDoc for a full explanation. + * + * @return the User Distinguished Name (DN) template to use when creating User DNs at runtime. + */ + public String getUserDnTemplate() { + return getUserDn(USERDN_SUBSTITUTION_TOKEN); + } + + /** + * Returns the LDAP User Distinguished Name (DN) to use when acquiring an + * {@link javax.naming.ldap.LdapContext LdapContext} from the {@link LdapContextFactory}. + * + * If the the {@link #getUserDnTemplate() userDnTemplate} property has been set, this implementation will construct + * the User DN by substituting the specified {@code principal} into the configured template. If the + * {@link #getUserDnTemplate() userDnTemplate} has not been set, the method argument will be returned directly + * (indicating that the submitted authentication token principal is the User DN). + * + * @param principal the principal to substitute into the configured {@link #getUserDnTemplate() userDnTemplate}. + * @return the constructed User DN to use at runtime when acquiring an {@link javax.naming.ldap.LdapContext}. + * @throws IllegalArgumentException if the method argument is null or empty + * @throws IllegalStateException if the {@link #getUserDnTemplate userDnTemplate} has not been set. + * @see LdapContextFactory#getLdapContext(Object, Object) + */ + protected String getUserDn(String principal) throws IllegalArgumentException, IllegalStateException { + if (!StringUtils.hasText(principal)) { + throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction."); + } + String prefix = getUserDnPrefix(); + String suffix = getUserDnSuffix(); + if (prefix == null && suffix == null) { + LOGGER.debug("userDnTemplate property has not been configured, indicating the submitted " + + "AuthenticationToken's principal is the same as the User DN. Returning the method argument " + + "as is."); + return principal; + } + + int prefixLength = prefix != null ? prefix.length() : 0; + int suffixLength = suffix != null ? suffix.length() : 0; + StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength); + if (prefixLength > 0) { + sb.append(prefix); + } + sb.append(principal); + if (suffixLength > 0) { + sb.append(suffix); + } + return sb.toString(); + } + + /** + * Sets the LdapContextFactory instance used to acquire connections to the LDAP directory during authentication + * attempts and authorization queries. Unless specified otherwise, the default is a {@link JndiLdapContextFactory} + * instance. + * + * @param contextFactory the LdapContextFactory instance used to acquire connections to the LDAP directory during + * authentication attempts and authorization queries + */ + @SuppressWarnings({"UnusedDeclaration"}) + public void setContextFactory(LdapContextFactory contextFactory) { + this.contextFactory = contextFactory; + } + + /** + * Returns the LdapContextFactory instance used to acquire connections to the LDAP directory during authentication + * attempts and authorization queries. Unless specified otherwise, the default is a {@link JndiLdapContextFactory} + * instance. + * + * @return the LdapContextFactory instance used to acquire connections to the LDAP directory during + * authentication attempts and authorization queries + */ + public LdapContextFactory getContextFactory() { + return this.contextFactory; + } + + /*-------------------------------------------- + | M E T H O D S | + ============================================*/ + + /** + * Delegates to {@link #queryForAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken, LdapContextFactory)}, + * wrapping any {@link NamingException}s in a Shiro {@link AuthenticationException} to satisfy the parent method + * signature. + * + * @param token the authentication token containing the user's principal and credentials. + * @return the {@link AuthenticationInfo} acquired after a successful authentication attempt + * @throws AuthenticationException if the authentication attempt fails or if a + * {@link NamingException} occurs. + */ + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + AuthenticationInfo info; + try { + info = queryForAuthenticationInfo(token, getContextFactory()); + } catch (AuthenticationNotSupportedException e) { + String msg = "Unsupported configured authentication mechanism"; + throw new UnsupportedAuthenticationMechanismException(msg, e); + } catch (javax.naming.AuthenticationException e) { + throw new AuthenticationException("LDAP authentication failed.", e); + } catch (NamingException e) { + String msg = "LDAP naming error while attempting to authenticate user."; + throw new AuthenticationException(msg, e); + } + + return info; + } + + + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + AuthorizationInfo info; + try { + info = queryForAuthorizationInfo(principals, getContextFactory()); + } catch (NamingException e) { + String msg = "LDAP naming error while attempting to retrieve authorization for user [" + principals + "]."; + throw new AuthorizationException(msg, e); + } + + return info; + } + + /** + * Returns the principal to use when creating the LDAP connection for an authentication attempt. + * + * This implementation uses a heuristic: it checks to see if the specified token's + * {@link AuthenticationToken#getPrincipal() principal} is a {@code String}, and if so, + * {@link #getUserDn(String) converts it} from what is + * assumed to be a raw uid or username {@code String} into a User DN {@code String}. Almost all LDAP directories + * expect the authentication connection to present a User DN and not an unqualified username or uid. + * + * If the token's {@code principal} is not a String, it is assumed to already be in the format supported by the + * underlying {@link LdapContextFactory} implementation and the raw principal is returned directly. + * + * @param token the {@link AuthenticationToken} submitted during the authentication process + * @return the User DN or raw principal to use to acquire the LdapContext. + * @see LdapContextFactory#getLdapContext(Object, Object) + */ + protected Object getLdapPrincipal(AuthenticationToken token) { + Object principal = token.getPrincipal(); + if (principal instanceof String) { + String sPrincipal = (String) principal; + return getUserDn(sPrincipal); + } + return principal; + } + + @SuppressWarnings("checkstyle:LineLength") + /** + * This implementation opens an LDAP connection using the token's + * {@link #getLdapPrincipal(org.apache.shiro.authc.AuthenticationToken) discovered principal} and provided + * {@link AuthenticationToken#getCredentials() credentials}. If the connection opens successfully, the + * authentication attempt is immediately considered successful and a new + * {@link AuthenticationInfo} instance is + * {@link #createAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken, Object, Object, javax.naming.ldap.LdapContext) created} + * and returned. If the connection cannot be opened, either because LDAP authentication failed or some other + * JNDI problem, an {@link NamingException} will be thrown. + * + * @param token the submitted authentication token that triggered the authentication attempt. + * @param ldapContextFactory factory used to retrieve LDAP connections. + * @return an {@link AuthenticationInfo} instance representing the authenticated user's information. + * @throws NamingException if any LDAP errors occur. + */ + protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, + LdapContextFactory ldapContextFactory) + throws NamingException { + + Object principal = token.getPrincipal(); + Object credentials = token.getCredentials(); + + LOGGER.debug("Authenticating user '{}' through LDAP", principal); + + principal = getLdapPrincipal(token); + + LdapContext ctx = null; + try { + ctx = ldapContextFactory.getLdapContext(principal, credentials); + //context was opened successfully, which means their credentials were valid. Return the AuthenticationInfo: + return createAuthenticationInfo(token, principal, credentials, ctx); + } finally { + LdapUtils.closeContext(ctx); + } + } + + /** + * Returns the {@link AuthenticationInfo} resulting from a Subject's successful LDAP authentication attempt. + * + * This implementation ignores the {@code ldapPrincipal}, {@code ldapCredentials}, and the opened + * {@code ldapContext} arguments and merely returns an {@code AuthenticationInfo} instance mirroring the + * submitted token's principal and credentials. This is acceptable because this method is only ever invoked after + * a successful authentication attempt, which means the provided principal and credentials were correct, and can + * be used directly to populate the (now verified) {@code AuthenticationInfo}. + * + * Subclasses however are free to override this method for more advanced construction logic. + * + * @param token the submitted {@code AuthenticationToken} that resulted in a successful authentication + * @param ldapPrincipal the LDAP principal used when creating the LDAP connection. Unlike the token's + * {@link AuthenticationToken#getPrincipal() principal}, this value is usually a constructed + * User DN and not a simple username or uid. The exact value is depending on the + * configured + * + * LDAP authentication mechanism in use. + * @param ldapCredentials the LDAP credentials used when creating the LDAP connection. + * @param ldapContext the LdapContext created that resulted in a successful authentication. It can be used + * further by subclasses for more complex operations. It does not need to be closed - + * it will be closed automatically after this method returns. + * @return the {@link AuthenticationInfo} resulting from a Subject's successful LDAP authentication attempt. + * @throws NamingException if there was any problem using the {@code LdapContext} + */ + @SuppressWarnings({"UnusedDeclaration"}) + protected AuthenticationInfo createAuthenticationInfo(AuthenticationToken token, Object ldapPrincipal, + Object ldapCredentials, LdapContext ldapContext) + throws NamingException { + return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName()); + } + + + /** + * Method that should be implemented by subclasses to build an + * {@link AuthorizationInfo} object by querying the LDAP context for the + * specified principal. + * + * @param principals the principals of the Subject whose AuthenticationInfo should be queried from the LDAP server. + * @param ldapContextFactory factory used to retrieve LDAP connections. + * @return an {@link AuthorizationInfo} instance containing information retrieved from the LDAP server. + * @throws NamingException if any LDAP errors occur during the search. + */ + protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, + LdapContextFactory ldapContextFactory) throws NamingException { + return null; + } +} diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapContextFactory.java b/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapContextFactory.java index db667931d3..fcfd313e9a 100644 --- a/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapContextFactory.java +++ b/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapContextFactory.java @@ -1,533 +1,533 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.shiro.realm.ldap; - -import org.apache.shiro.lang.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.naming.AuthenticationException; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.ldap.InitialLdapContext; -import javax.naming.ldap.LdapContext; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; - -/** - * {@link LdapContextFactory} implementation using the default Sun/Oracle JNDI Ldap API, utilizing JNDI - * environment properties and an {@link javax.naming.InitialContext}. - *
- * [main] - * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm - * ldapRealm.contextFactory.url = ldap://localhost:389 - * ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 - *- * and - *
- * [main] - * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm - * ldapRealm.contextFactory.environment[java.naming.provider.url] = ldap://localhost:389 - * ldapRealm.contextFactory.environment[java.naming.security.authentication] = DIGEST-MD5 - *- * As you can see, the 2nd configuration block is a little more difficult to read and also requires knowledge - * of the underlying JNDI Context property keys. The first is easier to read and understand. - * - * Note that occasionally it will be necessary to use the latter configuration style to set environment properties - * where no corresponding wrapper method exists. In this case, the hybrid approach is still a little easier to read. - * For example: - *
- * [main] - * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm - * ldapRealm.contextFactory.url = ldap://localhost:389 - * ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 - * ldapRealm.contextFactory.environment[some.other.obscure.jndi.key] = some value - *- * - * @since 1.1 - */ -public class JndiLdapContextFactory implements LdapContextFactory { - - /*------------------------------------------- - | C O N S T A N T S | - ===========================================*/ - /** - * The Sun LDAP property used to enable connection pooling. This is used in the default implementation - * to enable LDAP connection pooling. - */ - protected static final String SUN_CONNECTION_POOLING_PROPERTY = "com.sun.jndi.ldap.connect.pool"; - protected static final String DEFAULT_CONTEXT_FACTORY_CLASS_NAME = "com.sun.jndi.ldap.LdapCtxFactory"; - protected static final String SIMPLE_AUTHENTICATION_MECHANISM_NAME = "simple"; - protected static final String DEFAULT_REFERRAL = "follow"; - - private static final Logger log = LoggerFactory.getLogger(JndiLdapContextFactory.class); - - /*------------------------------------------- - | I N S T A N C E V A R I A B L E S | - ============================================*/ - private Map
environment
settings and throws an exception if a problem
- * exists.
- *
- * This implementation will throw a {@link AuthenticationException} if the authentication mechanism is set to
- * 'simple', the principal is non-empty, and the credentials are empty (as per
- * rfc4513 section-5.1.2).
- *
- * @param environment the JNDI environment settings to be validated
- * @throws AuthenticationException if a configuration problem is detected
- */
- protected void validateAuthenticationInfo(Hashtable+ * [main] + * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm + * ldapRealm.contextFactory.url = ldap://localhost:389 + * ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 + *+ * and + *
+ * [main] + * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm + * ldapRealm.contextFactory.environment[java.naming.provider.url] = ldap://localhost:389 + * ldapRealm.contextFactory.environment[java.naming.security.authentication] = DIGEST-MD5 + *+ * As you can see, the 2nd configuration block is a little more difficult to read and also requires knowledge + * of the underlying JNDI Context property keys. The first is easier to read and understand. + * + * Note that occasionally it will be necessary to use the latter configuration style to set environment properties + * where no corresponding wrapper method exists. In this case, the hybrid approach is still a little easier to read. + * For example: + *
+ * [main] + * ldapRealm = org.apache.shiro.realm.ldap.DefaultLdapRealm + * ldapRealm.contextFactory.url = ldap://localhost:389 + * ldapRealm.contextFactory.authenticationMechanism = DIGEST-MD5 + * ldapRealm.contextFactory.environment[some.other.obscure.jndi.key] = some value + *+ * + * @since 1.1 + */ +public class JndiLdapContextFactory implements LdapContextFactory { + + /*------------------------------------------- + | C O N S T A N T S | + ===========================================*/ + /** + * The Sun LDAP property used to enable connection pooling. This is used in the default implementation + * to enable LDAP connection pooling. + */ + protected static final String SUN_CONNECTION_POOLING_PROPERTY = "com.sun.jndi.ldap.connect.pool"; + protected static final String DEFAULT_CONTEXT_FACTORY_CLASS_NAME = "com.sun.jndi.ldap.LdapCtxFactory"; + protected static final String SIMPLE_AUTHENTICATION_MECHANISM_NAME = "simple"; + protected static final String DEFAULT_REFERRAL = "follow"; + + private static final Logger LOGGER = LoggerFactory.getLogger(JndiLdapContextFactory.class); + + /*------------------------------------------- + | I N S T A N C E V A R I A B L E S | + ============================================*/ + private Map
environment
settings and throws an exception if a problem
+ * exists.
+ *
+ * This implementation will throw a {@link AuthenticationException} if the authentication mechanism is set to
+ * 'simple', the principal is non-empty, and the credentials are empty (as per
+ * rfc4513 section-5.1.2).
+ *
+ * @param environment the JNDI environment settings to be validated
+ * @throws AuthenticationException if a configuration problem is detected
+ */
+ @SuppressWarnings({"checkstyle:LineLength", "checkstyle:BooleanExpressionComplexity"})
+ protected void validateAuthenticationInfo(HashtablegetClass().getName() + ",id=" + getId()
.
*
* @return the string representation of this SimpleSession, equal to
- * getClass().getName() + ",id=" + getId()
.
+ * getClass().getName() + ",id=" + getId()
.
* @since 1.0
*/
@Override
@@ -432,6 +438,7 @@ public String toString() {
* @throws IOException if any of this object's fields cannot be written to the stream.
* @since 1.0
*/
+ @SuppressWarnings("checkstyle:NPathComplexity")
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
short alteredFieldsBitMask = getAlteredFieldsBitMask();
@@ -448,7 +455,7 @@ private void writeObject(ObjectOutputStream out) throws IOException {
if (lastAccessTime != null) {
out.writeObject(lastAccessTime);
}
- if (timeout != 0l) {
+ if (timeout != 0L) {
out.writeLong(timeout);
}
if (expired) {
@@ -470,7 +477,7 @@ private void writeObject(ObjectOutputStream out) throws IOException {
* @throws ClassNotFoundException if a required class needed for instantiation is not available in the present JVM
* @since 1.0
*/
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings({"unchecked", "checkstyle:NPathComplexity"})
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
short bitMask = in.readShort();
@@ -509,13 +516,14 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
* @return a bit mask used during serialization indicating which fields have been serialized.
* @since 1.0
*/
+ @SuppressWarnings("checkstyle:NPathComplexity")
private short getAlteredFieldsBitMask() {
int bitMask = 0;
bitMask = id != null ? bitMask | ID_BIT_MASK : bitMask;
bitMask = startTimestamp != null ? bitMask | START_TIMESTAMP_BIT_MASK : bitMask;
bitMask = stopTimestamp != null ? bitMask | STOP_TIMESTAMP_BIT_MASK : bitMask;
bitMask = lastAccessTime != null ? bitMask | LAST_ACCESS_TIME_BIT_MASK : bitMask;
- bitMask = timeout != 0l ? bitMask | TIMEOUT_BIT_MASK : bitMask;
+ bitMask = timeout != 0L ? bitMask | TIMEOUT_BIT_MASK : bitMask;
bitMask = expired ? bitMask | EXPIRED_BIT_MASK : bitMask;
bitMask = host != null ? bitMask | HOST_BIT_MASK : bitMask;
bitMask = !CollectionUtils.isEmpty(attributes) ? bitMask | ATTRIBUTES_BIT_MASK : bitMask;
@@ -531,7 +539,7 @@ private short getAlteredFieldsBitMask() {
* been serialized, 0 means it hasn't been serialized.
* @param fieldBitMask the field bit mask constant identifying which bit to inspect (corresponds to a class attribute).
* @return {@code true} if the given {@code bitMask} argument indicates that the specified field has been
- * serialized and therefore should be read during deserialization, {@code false} otherwise.
+ * serialized and therefore should be read during deserialization, {@code false} otherwise.
* @since 1.0
*/
private static boolean isFieldPresent(short bitMask, int fieldBitMask) {
diff --git a/core/src/main/java/org/apache/shiro/session/mgt/ValidatingSession.java b/core/src/main/java/org/apache/shiro/session/mgt/ValidatingSession.java
index 8b88228261..6d68a17a42 100644
--- a/core/src/main/java/org/apache/shiro/session/mgt/ValidatingSession.java
+++ b/core/src/main/java/org/apache/shiro/session/mgt/ValidatingSession.java
@@ -28,7 +28,7 @@
*
* Validation is usually an exercise of determining when the session was last accessed or modified and determining if
* that time is longer than a specified allowed duration.
- *
+ *
* @since 0.9
*/
public interface ValidatingSession extends Session {
diff --git a/core/src/main/java/org/apache/shiro/session/mgt/eis/AbstractSessionDAO.java b/core/src/main/java/org/apache/shiro/session/mgt/eis/AbstractSessionDAO.java
index b8055e0074..4a472ed5f1 100644
--- a/core/src/main/java/org/apache/shiro/session/mgt/eis/AbstractSessionDAO.java
+++ b/core/src/main/java/org/apache/shiro/session/mgt/eis/AbstractSessionDAO.java
@@ -65,7 +65,7 @@ public AbstractSessionDAO() {
* is a {@link JavaUuidSessionIdGenerator}.
*
* @return the {@code SessionIdGenerator} used by the {@link #generateSessionId(org.apache.shiro.session.Session)}
- * method.
+ * method.
*/
public SessionIdGenerator getSessionIdGenerator() {
return sessionIdGenerator;
@@ -151,7 +151,7 @@ protected void assignSessionId(Session session, Serializable sessionId) {
*
* @param session the Session instance to persist to the EIS.
* @return the id of the session created in the EIS (i.e. this is almost always a primary key and should be the
- * value returned from {@link org.apache.shiro.session.Session#getId() Session.getId()}.
+ * value returned from {@link org.apache.shiro.session.Session#getId() Session.getId()}.
*/
protected abstract Serializable doCreate(Session session);
@@ -178,7 +178,7 @@ public Session readSession(Serializable sessionId) throws UnknownSessionExceptio
*
* @param sessionId the id of the Session to retrieve.
* @return the Session in the EIS identified by sessionId or {@code null} if a
- * session with that ID could not be found.
+ * session with that ID could not be found.
*/
protected abstract Session doReadSession(Serializable sessionId);
diff --git a/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java b/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java
index f48dc75159..6ed409c187 100644
--- a/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java
+++ b/core/src/main/java/org/apache/shiro/session/mgt/eis/CachingSessionDAO.java
@@ -120,7 +120,7 @@ public void setActiveSessionsCacheName(String activeSessionsCacheName) {
* {@code CacheManager} using the {@link #getActiveSessionsCacheName() activeSessionsCacheName}.
*
* @return the cache instance to use for storing active sessions or {@code null} if the {@code Cache} instance
- * should be retrieved from the
+ * should be retrieved from the
*/
public CacheAuthenticationStrategy#{@link org.apache.shiro.authc.pam.AuthenticationStrategy#afterAllAttempts(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) afterAllAttempts}
+ * AuthenticationStrategy#
+ * {@link AuthenticationStrategy#afterAllAttempts(AuthenticationToken, AuthenticationInfo) afterAllAttempts}
* implementation.
*
* @return the primary principal used to uniquely identify the owning account/Subject
@@ -95,7 +100,7 @@ public interface PrincipalCollection extends Iterable, Serializable {
*
* @param type the type of the principals that should be returned.
* @return a Collection of principals that are assignable from the specified type, or
- * an empty Collection if no principals of this type are associated.
+ * an empty Collection if no principals of this type are associated.
*/
* *EXPERIMENTAL for Shiro 1.2 - DO NOT USE YET*
*
* @since 1.2
@@ -48,7 +56,7 @@ public SimplePrincipalMap(Map
* This is typically considered a support class and is not often directly referenced. Most people prefer to use
* the {@code Subject.}{@link Subject#associateWith(Callable) associateWith} method, which will automatically return
* an instance of this class.
@@ -53,6 +53,7 @@
* {@link org.apache.shiro.concurrent.SubjectAwareExecutorService SubjectAwareExecutorService}, which
* transparently uses instances of this class.
*
+ * @param
* This is typically considered a support class and is not often directly referenced. Most people prefer to use
* the {@code Subject.}{@link Subject#execute(Runnable) execute} or
* {@code Subject.}{@link Subject#associateWith(Runnable) associateWith} methods, which transparently perform the
diff --git a/core/src/main/java/org/apache/shiro/subject/support/SubjectThreadState.java b/core/src/main/java/org/apache/shiro/subject/support/SubjectThreadState.java
index 2e439b1425..50a9c043d0 100644
--- a/core/src/main/java/org/apache/shiro/subject/support/SubjectThreadState.java
+++ b/core/src/main/java/org/apache/shiro/subject/support/SubjectThreadState.java
@@ -59,10 +59,10 @@ public SubjectThreadState(Subject subject) {
this.subject = subject;
SecurityManager securityManager = null;
- if ( subject instanceof DelegatingSubject) {
- securityManager = ((DelegatingSubject)subject).getSecurityManager();
+ if (subject instanceof DelegatingSubject) {
+ securityManager = ((DelegatingSubject) subject).getSecurityManager();
}
- if ( securityManager == null) {
+ if (securityManager == null) {
securityManager = ThreadContext.getSecurityManager();
}
this.securityManager = securityManager;
@@ -88,7 +88,7 @@ protected Subject getSubject() {
*/
public void bind() {
SecurityManager securityManager = this.securityManager;
- if ( securityManager == null ) {
+ if (securityManager == null) {
//try just in case the constructor didn't find one at the time:
securityManager = ThreadContext.getSecurityManager();
}
diff --git a/core/src/main/java/org/apache/shiro/subject/support/package-info.java b/core/src/main/java/org/apache/shiro/subject/support/package-info.java
index f3441f93f5..b339001837 100644
--- a/core/src/main/java/org/apache/shiro/subject/support/package-info.java
+++ b/core/src/main/java/org/apache/shiro/subject/support/package-info.java
@@ -19,4 +19,4 @@
/**
* Concrete support implementations of most of the {@code org.apache.shiro.subject} interfaces.
*/
-package org.apache.shiro.subject.support;
\ No newline at end of file
+package org.apache.shiro.subject.support;
diff --git a/core/src/main/java/org/apache/shiro/util/AbstractFactory.java b/core/src/main/java/org/apache/shiro/util/AbstractFactory.java
index 09e7e48cd1..97fce29f0e 100644
--- a/core/src/main/java/org/apache/shiro/util/AbstractFactory.java
+++ b/core/src/main/java/org/apache/shiro/util/AbstractFactory.java
@@ -21,8 +21,9 @@
import org.apache.shiro.lang.util.Factory;
/**
- * TODO - Class JavaDoc
+ * AbstractFactory.
*
+ * @param {@link #getPrincipals()}.{@link org.apache.shiro.subject.PrincipalCollection#getPrimaryPrincipal() getPrimaryPrincipal()}
+ * {@link #getPrincipals()}.
+ * {@link org.apache.shiro.subject.PrincipalCollection#getPrimaryPrincipal() getPrimaryPrincipal()}
*
* @return this Subject's application-specific unique identity.
* @see org.apache.shiro.subject.PrincipalCollection#getPrimaryPrincipal()
@@ -140,9 +142,9 @@ public interface Subject {
*
* @param permissions the String representations of the Permissions that are being checked.
* @return a boolean array where indices correspond to the index of the
- * permissions in the given list. A true value at an index indicates this Subject is permitted for
- * for the associated {@code Permission} string in the list. A false value at an index
- * indicates otherwise.
+ * permissions in the given list. A true value at an index indicates this Subject is permitted for
+ * for the associated {@code Permission} string in the list. A false value at an index
+ * indicates otherwise.
* @since 0.9
*/
boolean[] isPermitted(String... permissions);
@@ -160,9 +162,9 @@ public interface Subject {
*
* @param permissions the permissions that are being checked.
* @return a boolean array where indices correspond to the index of the
- * permissions in the given list. A true value at an index indicates this Subject is permitted for
- * for the associated {@code Permission} object in the list. A false value at an index
- * indicates otherwise.
+ * permissions in the given list. A true value at an index indicates this Subject is permitted for
+ * for the associated {@code Permission} object in the list. A false value at an index
+ * indicates otherwise.
*/
boolean[] isPermitted(List
- * PrincipalCollection identity = new {@link org.apache.shiro.subject.SimplePrincipalCollection#SimplePrincipalCollection(Object, String) SimplePrincipalCollection}("jsmith", "myRealm");
+ * PrincipalCollection identity = new {@link org.apache.shiro.subject.SimplePrincipalCollection#SimplePrincipalCollection(Object, String)
+ * SimplePrincipalCollection}("jsmith", "myRealm");
* Subject jsmith = new Subject.Builder().principals(identity).buildSubject();
*
* Similarly, if your application's unique identifier for users is a {@code long} value (such as might be used
@@ -746,7 +745,8 @@ public Builder session(Session session) {
* instance this way:
*
* long userId = //get user ID from somewhere
- * PrincipalCollection userIdentity = new {@link org.apache.shiro.subject.SimplePrincipalCollection#SimplePrincipalCollection(Object, String) SimplePrincipalCollection}(userId, "jdbcRealm");
+ * PrincipalCollection userIdentity = new {@link org.apache.shiro.subject.SimplePrincipalCollection#SimplePrincipalCollection(Object, String)
+ * SimplePrincipalCollection}(userId, "jdbcRealm");
* Subject user = new Subject.Builder().principals(identity).buildSubject();
*
* @param principals the principals to use as the {@code Subject}'s identity.
@@ -839,7 +839,7 @@ public Builder contextAttribute(String attributeKey, Object attributeValue) {
* framework developer to bind the returned {@code Subject} for continued use if desired.
*
* @return a new {@code Subject} instance reflecting the cumulative state acquired by the
- * other methods in this class.
+ * other methods in this class.
*/
public Subject buildSubject() {
return this.securityManager.createSubject(this.subjectContext);
diff --git a/core/src/main/java/org/apache/shiro/subject/SubjectContext.java b/core/src/main/java/org/apache/shiro/subject/SubjectContext.java
index 3cb7a88099..d9e29a6392 100644
--- a/core/src/main/java/org/apache/shiro/subject/SubjectContext.java
+++ b/core/src/main/java/org/apache/shiro/subject/SubjectContext.java
@@ -63,7 +63,7 @@ public interface SubjectContext extends MapUsage
- *
+ * Usage
- *
+ * path
against the given pattern
.
*
@@ -112,8 +113,10 @@ public boolean matchStart(String pattern, String path) {
* @param fullMatch whether a full pattern match is required
* (else a pattern match as far as the given base path goes is sufficient)
* @return true
if the supplied path
matched,
- * false
if it didn't
+ * false
if it didn't
*/
+ @SuppressWarnings({"checkstyle:ReturnCount", "checkstyle:CyclomaticComplexity",
+ "checkstyle:NPathComplexity", "checkstyle:MethodLength"})
protected boolean doMatch(String pattern, String path, boolean fullMatch) {
if (path == null || path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
return false;
@@ -143,18 +146,18 @@ protected boolean doMatch(String pattern, String path, boolean fullMatch) {
if (pathIdxStart > pathIdxEnd) {
// Path is exhausted, only match if rest of pattern is * or **'s
if (pattIdxStart > pattIdxEnd) {
- return (pattern.endsWith(this.pathSeparator) ?
- path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator));
+ return (pattern.endsWith(this.pathSeparator)
+ ? path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator));
}
if (!fullMatch) {
return true;
}
- if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") &&
- path.endsWith(this.pathSeparator)) {
+ if (pattIdxStart == pattIdxEnd && "*".equals(pattDirs[pattIdxStart])
+ && path.endsWith(this.pathSeparator)) {
return true;
}
for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
- if (!pattDirs[i].equals("**")) {
+ if (!"**".equals(pattDirs[i])) {
return false;
}
}
@@ -249,8 +252,10 @@ protected boolean doMatch(String pattern, String path, boolean fullMatch) {
* @param str string which must be matched against the pattern.
* Must not be null
.
* @return true
if the string matches against the
- * pattern, or false
otherwise.
+ * pattern, or false
otherwise.
*/
+ @SuppressWarnings({"checkstyle:ReturnCount", "checkstyle:CyclomaticComplexity",
+ "checkstyle:NPathComplexity", "checkstyle:MethodLength"})
private boolean matchStrings(String pattern, String str) {
char[] patArr = pattern.toCharArray();
char[] strArr = str.toCharArray();
@@ -271,29 +276,34 @@ private boolean matchStrings(String pattern, String str) {
if (!containsStar) {
// No '*'s, so we make a shortcut
if (patIdxEnd != strIdxEnd) {
- return false; // Pattern and string do not have the same size
+ // Pattern and string do not have the same size
+ return false;
}
for (int i = 0; i <= patIdxEnd; i++) {
ch = patArr[i];
if (ch != '?') {
if (ch != strArr[i]) {
- return false;// Character mismatch
+ // Character mismatch
+ return false;
}
}
}
- return true; // String matches against pattern
+ // String matches against pattern
+ return true;
}
if (patIdxEnd == 0) {
- return true; // Pattern contains only '*', which matches anything
+ // Pattern contains only '*', which matches anything
+ return true;
}
// Process characters before first star
while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
if (ch != '?') {
if (ch != strArr[strIdxStart]) {
- return false;// Character mismatch
+ // Character mismatch
+ return false;
}
}
patIdxStart++;
@@ -314,7 +324,8 @@ private boolean matchStrings(String pattern, String str) {
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
if (ch != '?') {
if (ch != strArr[strIdxEnd]) {
- return false;// Character mismatch
+ // Character mismatch
+ return false;
}
}
patIdxEnd--;
diff --git a/core/src/main/java/org/apache/shiro/util/CollectionUtils.java b/core/src/main/java/org/apache/shiro/util/CollectionUtils.java
index 67fc5c94a4..61cd05b799 100644
--- a/core/src/main/java/org/apache/shiro/util/CollectionUtils.java
+++ b/core/src/main/java/org/apache/shiro/util/CollectionUtils.java
@@ -33,9 +33,10 @@
*
* @since 0.9
*/
-public class CollectionUtils {
+public final class CollectionUtils {
- //TODO - complete JavaDoc
+ private CollectionUtils() {
+ }
public static System.getProperty("java.version");
. */
- private static final String version;
+ /**
+ * The virtual machine version, i.e. System.getProperty("java.version");
.
+ */
+ private static final String VERSION;
/**
* The virtual machine major version. For example, with a version
of
* 1.5.6_10
, this would be 1.5
*/
- private static final int majorVersion;
+ private static final int MAJOR_VERSION;
/**
* Static code initialization block that sets the
@@ -81,25 +83,25 @@ public abstract class JavaEnvironment {
* upon initialization.
*/
static {
- version = System.getProperty("java.version");
+ VERSION = System.getProperty("java.version");
// version String should look like "1.4.2_10"
// NOTE: JDK 1.9 will be versioned differently '9' and/or 9.x.x
// https://blogs.oracle.com/java-platform-group/entry/a_new_jdk_9_version
- if (version.contains("1.8.")) {
- majorVersion = JAVA_18;
- } else if (version.contains("1.7.")) {
- majorVersion = JAVA_17;
- } else if (version.contains("1.6.")) {
- majorVersion = JAVA_16;
- } else if (version.contains("1.5.")) {
- majorVersion = JAVA_15;
- } else if (version.contains("1.4.")) {
- majorVersion = JAVA_14;
+ if (VERSION.contains("1.8.")) {
+ MAJOR_VERSION = JAVA_18;
+ } else if (VERSION.contains("1.7.")) {
+ MAJOR_VERSION = JAVA_17;
+ } else if (VERSION.contains("1.6.")) {
+ MAJOR_VERSION = JAVA_16;
+ } else if (VERSION.contains("1.5.")) {
+ MAJOR_VERSION = JAVA_15;
+ } else if (VERSION.contains("1.4.")) {
+ MAJOR_VERSION = JAVA_14;
} else {
// else leave 1.3 as default (it's either 1.3 or unknown)
- majorVersion = JAVA_13;
+ MAJOR_VERSION = JAVA_13;
}
}
@@ -112,7 +114,7 @@ public abstract class JavaEnvironment {
* @see System#getProperty(String)
*/
public static String getVersion() {
- return version;
+ return VERSION;
}
/**
@@ -128,7 +130,7 @@ public static String getVersion() {
* @see #JAVA_18
*/
public static int getMajorVersion() {
- return majorVersion;
+ return MAJOR_VERSION;
}
/**
@@ -171,7 +173,6 @@ public static boolean isAtLeastVersion15() {
* @see #JAVA_16
* @see #JAVA_17
* @see #JAVA_18
- *
* @since 1.2
*/
public static boolean isAtLeastVersion16() {
diff --git a/core/src/main/java/org/apache/shiro/util/JdbcUtils.java b/core/src/main/java/org/apache/shiro/util/JdbcUtils.java
index 0c5f3aeda2..5c02fdb71b 100644
--- a/core/src/main/java/org/apache/shiro/util/JdbcUtils.java
+++ b/core/src/main/java/org/apache/shiro/util/JdbcUtils.java
@@ -35,10 +35,12 @@
*
* @since 0.2
*/
-public class JdbcUtils {
+public final class JdbcUtils {
- /** Private internal log instance. */
- private static final Logger log = LoggerFactory.getLogger(JdbcUtils.class);
+ /**
+ * Private internal log instance.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(JdbcUtils.class);
/**
* Private constructor to prevent instantiation.
@@ -57,12 +59,12 @@ public static void closeConnection(Connection connection) {
try {
connection.close();
} catch (SQLException ex) {
- if (log.isDebugEnabled()) {
- log.debug("Could not close JDBC Connection", ex);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Could not close JDBC Connection", ex);
}
} catch (Throwable ex) {
- if (log.isDebugEnabled()) {
- log.debug("Unexpected exception on closing JDBC Connection", ex);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Unexpected exception on closing JDBC Connection", ex);
}
}
}
@@ -79,12 +81,12 @@ public static void closeStatement(Statement statement) {
try {
statement.close();
} catch (SQLException ex) {
- if (log.isDebugEnabled()) {
- log.debug("Could not close JDBC Statement", ex);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Could not close JDBC Statement", ex);
}
} catch (Throwable ex) {
- if (log.isDebugEnabled()) {
- log.debug("Unexpected exception on closing JDBC Statement", ex);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Unexpected exception on closing JDBC Statement", ex);
}
}
}
@@ -101,12 +103,12 @@ public static void closeResultSet(ResultSet rs) {
try {
rs.close();
} catch (SQLException ex) {
- if (log.isDebugEnabled()) {
- log.debug("Could not close JDBC ResultSet", ex);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Could not close JDBC ResultSet", ex);
}
} catch (Throwable ex) {
- if (log.isDebugEnabled()) {
- log.debug("Unexpected exception on closing JDBC ResultSet", ex);
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Unexpected exception on closing JDBC ResultSet", ex);
}
}
}
diff --git a/core/src/main/java/org/apache/shiro/util/MapContext.java b/core/src/main/java/org/apache/shiro/util/MapContext.java
index 1ea2437bda..9adbc4d91a 100644
--- a/core/src/main/java/org/apache/shiro/util/MapContext.java
+++ b/core/src/main/java/org/apache/shiro/util/MapContext.java
@@ -19,7 +19,11 @@
package org.apache.shiro.util;
import java.io.Serializable;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
/**
* A {@code MapContext} provides a common base for context-based data storage in a {@link Map}. Type-safe attribute
@@ -61,9 +65,9 @@ protected true
if the given source
matches the specified pattern
,
- * false
otherwise.
+ * false
otherwise.
*/
boolean matches(String pattern, String source);
}
diff --git a/core/src/main/java/org/apache/shiro/util/PermissionUtils.java b/core/src/main/java/org/apache/shiro/util/PermissionUtils.java
index 8d46eb5d72..f1e0ba1097 100644
--- a/core/src/main/java/org/apache/shiro/util/PermissionUtils.java
+++ b/core/src/main/java/org/apache/shiro/util/PermissionUtils.java
@@ -33,7 +33,10 @@
*
* @since 0.1
*/
-public class PermissionUtils {
+public final class PermissionUtils {
+
+ private PermissionUtils() {
+ }
public static Set
- * RandomNumberGenerator saltGenerator = new {@link org.apache.shiro.crypto.SecureRandomNumberGenerator SecureRandomNumberGenerator}(); - * User user = new User(); - * user.setPasswordSalt(saltGenerator.nextBytes().toBase64()); - * userDAO.save(user); - *- * - * @since 1.1 - */ -public interface RandomNumberGenerator { - - /** - * Generates a byte array of fixed length filled with random data, often useful for generating salts, - * initialization vectors or other seed data. The length is specified as a configuration - * value on the underlying implementation. - * - * If you'd like per-invocation control the number of bytes generated, use the - * {@link #nextBytes(int) nextBytes(int)} method instead. - * - * @return a byte array of fixed length filled with random data. - * @see #nextBytes(int) - */ - ByteSource nextBytes(); - - /** - * Generates a byte array of the specified length filled with random data. - * - * @param numBytes the number of bytes to be populated with random data. - * @return a byte array of the specified length filled with random data. - * @see #nextBytes() - */ - ByteSource nextBytes(int numBytes); -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.shiro.crypto; + +import org.apache.shiro.lang.util.ByteSource; + +/** + * A component that can generate random number/byte values as needed. Useful in cryptography or security scenarios + * where random byte arrays are needed, such as for password salts, nonces, initialization vectors and other seeds. + * + * This is essentially the same as a {@link java.security.SecureRandom SecureRandom}, and indeed implementations + * of this interface will probably all use {@link java.security.SecureRandom SecureRandom} instances, but this + * interface provides a few additional benefits to end-users: + *
+ * RandomNumberGenerator saltGenerator = new {@link SecureRandomNumberGenerator SecureRandomNumberGenerator}(); + * User user = new User(); + * user.setPasswordSalt(saltGenerator.nextBytes().toBase64()); + * userDAO.save(user); + *+ * + * @since 1.1 + */ +public interface RandomNumberGenerator { + + /** + * Generates a byte array of fixed length filled with random data, often useful for generating salts, + * initialization vectors or other seed data. The length is specified as a configuration + * value on the underlying implementation. + * + * If you'd like per-invocation control the number of bytes generated, use the + * {@link #nextBytes(int) nextBytes(int)} method instead. + * + * @return a byte array of fixed length filled with random data. + * @see #nextBytes(int) + */ + ByteSource nextBytes(); + + /** + * Generates a byte array of the specified length filled with random data. + * + * @param numBytes the number of bytes to be populated with random data. + * @return a byte array of the specified length filled with random data. + * @see #nextBytes() + */ + ByteSource nextBytes(int numBytes); +} diff --git a/crypto/core/src/main/java/org/apache/shiro/crypto/SecureRandomNumberGenerator.java b/crypto/core/src/main/java/org/apache/shiro/crypto/SecureRandomNumberGenerator.java index 8bcb0f5fb1..25a091eb93 100644 --- a/crypto/core/src/main/java/org/apache/shiro/crypto/SecureRandomNumberGenerator.java +++ b/crypto/core/src/main/java/org/apache/shiro/crypto/SecureRandomNumberGenerator.java @@ -1,120 +1,121 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.shiro.crypto; - -import org.apache.shiro.lang.util.ByteSource; - -import java.security.SecureRandom; - -/** - * Default implementation of the {@link RandomNumberGenerator RandomNumberGenerator} interface, backed by a - * {@link SecureRandom SecureRandom} instance. - * - * This class is a little easier to use than using the JDK's {@code SecureRandom} class directly. It also - * allows for JavaBeans-style of customization, convenient for Shiro's INI configuration or other IoC configuration - * mechanism. - * - * @since 1.1 - */ -public class SecureRandomNumberGenerator implements RandomNumberGenerator { - - protected static final int DEFAULT_NEXT_BYTES_SIZE = 16; //16 bytes == 128 bits (a common number in crypto) - - private int defaultNextBytesSize; - private SecureRandom secureRandom; - - /** - * Creates a new instance with a default backing {@link SecureRandom SecureRandom} and a - * {@link #getDefaultNextBytesSize() defaultNextBytesSize} of {@code 16}, which equals 128 bits, a size commonly - * used in cryptographic algorithms. - */ - public SecureRandomNumberGenerator() { - this.defaultNextBytesSize = DEFAULT_NEXT_BYTES_SIZE; - this.secureRandom = new SecureRandom(); - } - - /** - * Seeds the backing {@link SecureRandom SecureRandom} instance with additional seed data. - * - * @param bytes the seed bytes - * @see SecureRandom#setSeed(byte[]) - */ - public void setSeed(byte[] bytes) { - this.secureRandom.setSeed(bytes); - } - - /** - * Returns the {@link SecureRandom SecureRandom} backing this instance. - * - * @return the {@link SecureRandom SecureRandom} backing this instance. - */ - public SecureRandom getSecureRandom() { - return secureRandom; - } - - /** - * Sets the {@link SecureRandom SecureRandom} to back this instance. - * - * @param random the {@link SecureRandom SecureRandom} to back this instance. - * @throws NullPointerException if the method argument is null - */ - public void setSecureRandom(SecureRandom random) throws NullPointerException { - if (random == null) { - throw new NullPointerException("SecureRandom argument cannot be null."); - } - this.secureRandom = random; - } - - /** - * Returns the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. Defaults to - * {@code 16}, which equals 128 bits, a size commonly used in cryptographic algorithms. - * - * @return the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. - */ - public int getDefaultNextBytesSize() { - return defaultNextBytesSize; - } - - /** - * Sets the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. Defaults to - * {@code 16}, which equals 128 bits, a size commonly used in cryptographic algorithms. - * - * @param defaultNextBytesSize the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. - * @throws IllegalArgumentException if the argument is 0 or negative - */ - public void setDefaultNextBytesSize(int defaultNextBytesSize) throws IllegalArgumentException { - if ( defaultNextBytesSize <= 0) { - throw new IllegalArgumentException("size value must be a positive integer (1 or larger)"); - } - this.defaultNextBytesSize = defaultNextBytesSize; - } - - public ByteSource nextBytes() { - return nextBytes(getDefaultNextBytesSize()); - } - - public ByteSource nextBytes(int numBytes) { - if (numBytes <= 0) { - throw new IllegalArgumentException("numBytes argument must be a positive integer (1 or larger)"); - } - byte[] bytes = new byte[numBytes]; - this.secureRandom.nextBytes(bytes); - return ByteSource.Util.bytes(bytes); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.shiro.crypto; + +import org.apache.shiro.lang.util.ByteSource; + +import java.security.SecureRandom; + +/** + * Default implementation of the {@link RandomNumberGenerator RandomNumberGenerator} interface, backed by a + * {@link SecureRandom SecureRandom} instance. + * + * This class is a little easier to use than using the JDK's {@code SecureRandom} class directly. It also + * allows for JavaBeans-style of customization, convenient for Shiro's INI configuration or other IoC configuration + * mechanism. + * + * @since 1.1 + */ +public class SecureRandomNumberGenerator implements RandomNumberGenerator { + + //16 bytes == 128 bits (a common number in crypto) + protected static final int DEFAULT_NEXT_BYTES_SIZE = 16; + + private int defaultNextBytesSize; + private SecureRandom secureRandom; + + /** + * Creates a new instance with a default backing {@link SecureRandom SecureRandom} and a + * {@link #getDefaultNextBytesSize() defaultNextBytesSize} of {@code 16}, which equals 128 bits, a size commonly + * used in cryptographic algorithms. + */ + public SecureRandomNumberGenerator() { + this.defaultNextBytesSize = DEFAULT_NEXT_BYTES_SIZE; + this.secureRandom = new SecureRandom(); + } + + /** + * Seeds the backing {@link SecureRandom SecureRandom} instance with additional seed data. + * + * @param bytes the seed bytes + * @see SecureRandom#setSeed(byte[]) + */ + public void setSeed(byte[] bytes) { + this.secureRandom.setSeed(bytes); + } + + /** + * Returns the {@link SecureRandom SecureRandom} backing this instance. + * + * @return the {@link SecureRandom SecureRandom} backing this instance. + */ + public SecureRandom getSecureRandom() { + return secureRandom; + } + + /** + * Sets the {@link SecureRandom SecureRandom} to back this instance. + * + * @param random the {@link SecureRandom SecureRandom} to back this instance. + * @throws NullPointerException if the method argument is null + */ + public void setSecureRandom(SecureRandom random) throws NullPointerException { + if (random == null) { + throw new NullPointerException("SecureRandom argument cannot be null."); + } + this.secureRandom = random; + } + + /** + * Returns the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. Defaults to + * {@code 16}, which equals 128 bits, a size commonly used in cryptographic algorithms. + * + * @return the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. + */ + public int getDefaultNextBytesSize() { + return defaultNextBytesSize; + } + + /** + * Sets the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. Defaults to + * {@code 16}, which equals 128 bits, a size commonly used in cryptographic algorithms. + * + * @param defaultNextBytesSize the size of the generated byte array for calls to {@link #nextBytes() nextBytes()}. + * @throws IllegalArgumentException if the argument is 0 or negative + */ + public void setDefaultNextBytesSize(int defaultNextBytesSize) throws IllegalArgumentException { + if (defaultNextBytesSize <= 0) { + throw new IllegalArgumentException("size value must be a positive integer (1 or larger)"); + } + this.defaultNextBytesSize = defaultNextBytesSize; + } + + public ByteSource nextBytes() { + return nextBytes(getDefaultNextBytesSize()); + } + + public ByteSource nextBytes(int numBytes) { + if (numBytes <= 0) { + throw new IllegalArgumentException("numBytes argument must be a positive integer (1 or larger)"); + } + byte[] bytes = new byte[numBytes]; + this.secureRandom.nextBytes(bytes); + return ByteSource.Util.bytes(bytes); + } +} diff --git a/crypto/core/src/main/java/org/apache/shiro/crypto/package-info.java b/crypto/core/src/main/java/org/apache/shiro/crypto/package-info.java new file mode 100644 index 0000000000..0fe457af3a --- /dev/null +++ b/crypto/core/src/main/java/org/apache/shiro/crypto/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * shiro crypto package. + */ +package org.apache.shiro.crypto; diff --git a/crypto/hash/pom.xml b/crypto/hash/pom.xml index 82acf151df..7f7d8001ac 100644 --- a/crypto/hash/pom.xml +++ b/crypto/hash/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> -
Other required parameters must be stored by the implementation.
* * @param algorithmName internal algorithm name, e.g. {@code 2y} for bcrypt and {@code argon2id} for argon2. - * @param hashedData the hashed data as a byte array. Does not include the salt or other parameters. - * @param salt the salt which was used when generating the hash. + * @param hashedData the hashed data as a byte array. Does not include the salt or other parameters. + * @param salt the salt which was used when generating the hash. * @throws IllegalArgumentException if the salt is not the same size as {@link #getSaltLength()}. */ public AbstractCryptHash(final String algorithmName, final byte[] hashedData, final ByteSource salt) { @@ -100,7 +100,7 @@ protected final void checkValid() { /** * Default check method for a valid salt. Can be overridden, because multiple salt lengths could be valid. - * + ** By default, this method checks if the number of bytes in the salt * are equal to the int returned by {@link #getSaltLength()}. * @@ -227,6 +227,7 @@ public boolean equals(final Object other) { * *
Implementations should not override this method, as different algorithms produce different output formats * and require different parameters.
+ * * @return a hashcode from the {@link #formatToCryptString() formatted output}. */ @Override diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java index 684647c7dc..5c84a8799c 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractHash.java @@ -50,16 +50,16 @@ public abstract class AbstractHash extends CodecSupport implements Hash, Seriali /** * The hashed data */ - private byte[] bytes = null; + private byte[] bytes; /** * Cached value of the {@link #toHex() toHex()} call so multiple calls won't incur repeated overhead. */ - private transient String hexEncoded = null; + private transient String hexEncoded; /** * Cached value of the {@link #toBase64() toBase64()} call so multiple calls won't incur repeated overhead. */ - private transient String base64Encoded = null; + private transient String base64Encoded; /** * Creates an new instance without any of its properties set (no hashing is performed). @@ -138,7 +138,7 @@ public AbstractHash(Object source, Object salt, int hashIterations) throws Codec } /** - * Implemented by subclasses, this specifies the {@link MessageDigest MessageDigest} algorithm name + * Implemented by subclasses, this specifies the {@link MessageDigest MessageDigest} algorithm name * to use when performing the hash. * * @return the {@link MessageDigest MessageDigest} algorithm name to use when performing the hash. @@ -218,7 +218,8 @@ protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) throws Unkn digest.update(salt); } byte[] hashed = digest.digest(bytes); - int iterations = hashIterations - 1; //already hashed once above + //already hashed once above + int iterations = hashIterations - 1; //iterate remaining number: for (int i = 0; i < iterations; i++) { digest.reset(); @@ -278,7 +279,7 @@ public String toString() { * * @param o the object (Hash) to check for equality. * @return {@code true} if the specified object is a Hash and its {@link #getBytes byte array} is identical to - * this Hash's byte array, {@code false} otherwise. + * this Hash's byte array, {@code false} otherwise. */ @Override public boolean equals(Object o) { diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/DefaultHashService.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/DefaultHashService.java index ed2653f1c6..4879424c62 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/DefaultHashService.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/DefaultHashService.java @@ -78,7 +78,7 @@ public DefaultHashService() { * * @param request the request to process * @return the response containing the result of the hash computation, as well as any hash salt used that should be - * exposed to the caller. + * exposed to the caller. */ @Override public Hash computeHash(HashRequest request) { diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashRequest.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashRequest.java index 2f0232c1c1..d8bd344ca7 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashRequest.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashRequest.java @@ -54,7 +54,7 @@ public interface HashRequest { * strategy for a request, even if the request did not specify one. * * @return a salt to be used by the {@link HashService} during hash computation, or {@code null} if no salt is - * provided as part of the request. + * provided as part of the request. */ Optional
* If a salt accompanies the return value
* (i.e. returnedHash.{@link org.apache.shiro.crypto.hash.Hash#getSalt() getSalt()} != null
), this
* same exact salt MUST be presented back to the {@code HashService} if hash
diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashSpi.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashSpi.java
index de4f2cf65a..879f74c792 100644
--- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashSpi.java
+++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashSpi.java
@@ -77,10 +77,11 @@ interface HashFactory {
* should use default parameters where applicable.
If the hash requests’ salt is missing or empty, the implementation should create a salt * with a default size.
+ * * @param hashRequest the request to build a Hash from. * @return a generated Hash according to the specs. * @throws IllegalArgumentException if any of the parameters is outside of valid boundaries (algorithm-specific) - * or if the given algorithm is not applicable for this {@link HashFactory}. + * or if the given algorithm is not applicable for this {@link HashFactory}. */ Hash generate(HashRequest hashRequest); } diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha256Hash.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha256Hash.java index 79384695bd..176abb4096 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha256Hash.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha256Hash.java @@ -34,8 +34,9 @@ */ public class Sha256Hash extends SimpleHash { - //TODO - complete JavaDoc - + /** + * Sha256 algorithm name. + */ public static final String ALGORITHM_NAME = "SHA-256"; public Sha256Hash() { diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha384Hash.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha384Hash.java index 9345bc6c3a..8ec0cf90a5 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha384Hash.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha384Hash.java @@ -35,8 +35,9 @@ */ public class Sha384Hash extends SimpleHash { - //TODO - complete JavaDoc - + /** + * Sha384 algorithm name. + */ public static final String ALGORITHM_NAME = "SHA-384"; public Sha384Hash() { diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha512Hash.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha512Hash.java index 400f833483..211a2ea7c4 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha512Hash.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/Sha512Hash.java @@ -34,8 +34,9 @@ */ public class Sha512Hash extends SimpleHash { - //TODO - complete JavaDoc - + /** + * Sha512 algorithm name. + */ public static final String ALGORITHM_NAME = "SHA-512"; public Sha512Hash() { diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java index 3028ceb45e..ed70ba2067 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHash.java @@ -1,482 +1,486 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.shiro.crypto.hash; - -import org.apache.shiro.crypto.UnknownAlgorithmException; -import org.apache.shiro.lang.codec.Base64; -import org.apache.shiro.lang.codec.CodecException; -import org.apache.shiro.lang.codec.Hex; -import org.apache.shiro.lang.util.ByteSource; -import org.apache.shiro.lang.util.SimpleByteSource; -import org.apache.shiro.lang.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - -import static java.util.Objects.requireNonNull; - -/** - * A {@code Hash} implementation that allows any {@link java.security.MessageDigest MessageDigest} algorithm name to - * be used. This class is a less type-safe variant than the other {@code AbstractHash} subclasses - * (e.g. {@link Sha512Hash}, etc.), but it does allow for any algorithm name to be specified in case the other subclass - * implementations do not represent an algorithm that you may want to use. - * - * As of Shiro 1.1, this class effectively replaces the (now-deprecated) {@link AbstractHash} class. It subclasses - * {@code AbstractHash} only to retain backwards-compatibility. - * - * @since 1.1 - */ -public class SimpleHash extends AbstractHash { - - private static final int DEFAULT_ITERATIONS = 1; - private static final long serialVersionUID = -6689895264902387303L; - - private static final Logger LOG = LoggerFactory.getLogger(SimpleHash.class); - - /** - * The {@link java.security.MessageDigest MessageDigest} algorithm name to use when performing the hash. - */ - private final String algorithmName; - - /** - * The hashed data - */ - private byte[] bytes; - - /** - * Supplied salt, if any. - */ - private ByteSource salt; - - /** - * Number of hash iterations to perform. Defaults to 1 in the constructor. - */ - private int iterations; - - /** - * Cached value of the {@link #toHex() toHex()} call so multiple calls won't incur repeated overhead. - */ - private transient String hexEncoded = null; - - /** - * Cached value of the {@link #toBase64() toBase64()} call so multiple calls won't incur repeated overhead. - */ - private transient String base64Encoded = null; - - /** - * Creates an new instance with only its {@code algorithmName} set - no hashing is performed. - * - * Because all other constructors in this class hash the {@code source} constructor argument, this - * constructor is useful in scenarios when you have a byte array that you know is already hashed and - * just want to set the bytes in their raw form directly on an instance. After using this constructor, - * you can then immediately call {@link #setBytes setBytes} to have a fully-initialized instance. - * - * N.B.The algorithm identified by the {@code algorithmName} parameter must be available on the JVM. If it - * is not, a {@link UnknownAlgorithmException} will be thrown when the hash is performed (not at instantiation). - * - * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when - * performing the hash. - * @see UnknownAlgorithmException - */ - public SimpleHash(String algorithmName) { - this.algorithmName = algorithmName; - this.iterations = DEFAULT_ITERATIONS; - } - - /** - * Creates an {@code algorithmName}-specific hash of the specified {@code source} with no {@code salt} using a - * single hash iteration. - * - * This is a convenience constructor that merely executesthis( algorithmName, source, null, 1);
.
- *
- * Please see the
- * {@link #SimpleHash(String algorithmName, Object source, Object salt, int numIterations) SimpleHashHash(algorithmName, Object,Object,int)}
- * constructor for the types of Objects that may be passed into this constructor, as well as how to support further
- * types.
- *
- * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
- * performing the hash.
- * @param source the object to be hashed.
- * @throws org.apache.shiro.lang.codec.CodecException
- * if the specified {@code source} cannot be converted into a byte array (byte[]).
- * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
- */
- public SimpleHash(String algorithmName, Object source) throws CodecException, UnknownAlgorithmException {
- //noinspection NullableProblems
- this(algorithmName, source, SimpleByteSource.empty(), DEFAULT_ITERATIONS);
- }
-
- /**
- * Creates an {@code algorithmName}-specific hash of the specified {@code source} using the given {@code salt}
- * using a single hash iteration.
- *
- * It is a convenience constructor that merely executes this( algorithmName, source, salt, 1);
.
- *
- * Please see the
- * {@link #SimpleHash(String algorithmName, Object source, Object salt, int numIterations) SimpleHashHash(algorithmName, Object,Object,int)}
- * constructor for the types of Objects that may be passed into this constructor, as well as how to support further
- * types.
- *
- * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
- * performing the hash.
- * @param source the source object to be hashed.
- * @param salt the salt to use for the hash
- * @throws CodecException if either constructor argument cannot be converted into a byte array.
- * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
- */
- public SimpleHash(String algorithmName, Object source, Object salt) throws CodecException, UnknownAlgorithmException {
- this(algorithmName, source, salt, DEFAULT_ITERATIONS);
- }
-
- /**
- * Creates an {@code algorithmName}-specific hash of the specified {@code source} using the given {@code salt}
- * using a single hash iteration.
- *
- * It is a convenience constructor that merely executes this( algorithmName, source, salt, 1);
.
- *
- * Please see the
- * {@link #SimpleHash(String algorithmName, Object source, Object salt, int numIterations) SimpleHashHash(algorithmName, Object,Object,int)}
- * constructor for the types of Objects that may be passed into this constructor, as well as how to support further
- * types.
- *
- * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
- * performing the hash.
- * @param source the source object to be hashed.
- * @param hashIterations the number of times the {@code source} argument hashed for attack resiliency.
- * @throws CodecException if either constructor argument cannot be converted into a byte array.
- * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
- */
- public SimpleHash(String algorithmName, Object source, int hashIterations) throws CodecException, UnknownAlgorithmException {
- this(algorithmName, source, SimpleByteSource.empty(), hashIterations);
- }
-
- /**
- * Creates an {@code algorithmName}-specific hash of the specified {@code source} using the given
- * {@code salt} a total of {@code hashIterations} times.
- *
- * By default, this class only supports Object method arguments of
- * type {@code byte[]}, {@code char[]}, {@link String}, {@link java.io.File File},
- * {@link java.io.InputStream InputStream} or {@link org.apache.shiro.lang.util.ByteSource ByteSource}. If either
- * argument is anything other than these types a {@link org.apache.shiro.lang.codec.CodecException CodecException}
- * will be thrown.
- *
- * If you want to be able to hash other object types, or use other salt types, you need to override the
- * {@link #toBytes(Object) toBytes(Object)} method to support those specific types. Your other option is to
- * convert your arguments to one of the default supported types first before passing them in to this
- * constructor}.
- *
- * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
- * performing the hash.
- * @param source the source object to be hashed.
- * @param salt the salt to use for the hash
- * @param hashIterations the number of times the {@code source} argument hashed for attack resiliency.
- * @throws CodecException if either Object constructor argument cannot be converted into a byte array.
- * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
- */
- public SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)
- throws CodecException, UnknownAlgorithmException {
- if (!StringUtils.hasText(algorithmName)) {
- throw new NullPointerException("algorithmName argument cannot be null or empty.");
- }
- this.algorithmName = algorithmName;
- this.iterations = Math.max(DEFAULT_ITERATIONS, hashIterations);
- ByteSource saltBytes = convertSaltToBytes(salt);
- this.salt = saltBytes;
- ByteSource sourceBytes = convertSourceToBytes(source);
- hash(sourceBytes, saltBytes, hashIterations);
- }
-
- /**
- * Acquires the specified {@code source} argument's bytes and returns them in the form of a {@code ByteSource} instance.
- *
- * This implementation merely delegates to the convenience {@link #toByteSource(Object)} method for generic
- * conversion. Can be overridden by subclasses for source-specific conversion.
- *
- * @param source the source object to be hashed.
- * @return the source's bytes in the form of a {@code ByteSource} instance.
- * @since 1.2
- */
- protected ByteSource convertSourceToBytes(Object source) {
- return toByteSource(source);
- }
-
- /**
- * Acquires the specified {@code salt} argument's bytes and returns them in the form of a {@code ByteSource} instance.
- *
- * This implementation merely delegates to the convenience {@link #toByteSource(Object)} method for generic
- * conversion. Can be overridden by subclasses for salt-specific conversion.
- *
- * @param salt the salt to be use for the hash.
- * @return the salt's bytes in the form of a {@code ByteSource} instance.
- * @since 1.2
- */
- protected ByteSource convertSaltToBytes(Object salt) {
- return toByteSource(salt);
- }
-
- /**
- * Converts a given object into a {@code ByteSource} instance. Assumes the object can be converted to bytes.
- *
- * @param object the Object to convert into a {@code ByteSource} instance.
- * @return the {@code ByteSource} representation of the specified object's bytes.
- * @since 1.2
- */
- protected ByteSource toByteSource(Object object) {
- if (object instanceof ByteSource) {
- return (ByteSource) object;
- }
- byte[] bytes = toBytes(object);
- return ByteSource.Util.bytes(bytes);
- }
-
- private void hash(ByteSource source, ByteSource salt, int hashIterations) throws CodecException, UnknownAlgorithmException {
- byte[] saltBytes = requireNonNull(salt).getBytes();
- byte[] hashedBytes = hash(source.getBytes(), saltBytes, hashIterations);
- setBytes(hashedBytes);
- }
-
- /**
- * Returns the {@link java.security.MessageDigest MessageDigest} algorithm name to use when performing the hash.
- *
- * @return the {@link java.security.MessageDigest MessageDigest} algorithm name to use when performing the hash.
- */
- @Override
- public String getAlgorithmName() {
- return this.algorithmName;
- }
-
- @Override
- public ByteSource getSalt() {
- return this.salt;
- }
-
- @Override
- public int getIterations() {
- return this.iterations;
- }
-
- @Override
- public boolean matchesPassword(ByteSource plaintextBytes) {
- try {
- SimpleHash otherHash = new SimpleHash(this.getAlgorithmName(), plaintextBytes, this.getSalt(), this.getIterations());
- return this.equals(otherHash);
- } catch (IllegalArgumentException illegalArgumentException) {
- // cannot recreate hash. Do not log password.
- LOG.warn("Cannot recreate a hash using the same parameters.", illegalArgumentException);
- return false;
- }
- }
-
- @Override
- public byte[] getBytes() {
- return this.bytes;
- }
-
- /**
- * Sets the raw bytes stored by this hash instance.
- *
- * The bytes are kept in raw form - they will not be hashed/changed. This is primarily a utility method for
- * constructing a Hash instance when the hashed value is already known.
- *
- * @param alreadyHashedBytes the raw already-hashed bytes to store in this instance.
- */
- @Override
- public void setBytes(byte[] alreadyHashedBytes) {
- this.bytes = alreadyHashedBytes;
- this.hexEncoded = null;
- this.base64Encoded = null;
- }
-
- /**
- * Sets the iterations used to previously compute AN ALREADY GENERATED HASH.
- *
- * This is provided ONLY to reconstitute an already-created Hash instance. It should ONLY ever be
- * invoked when re-constructing a hash instance from an already-hashed value.
- *
- * @param iterations the number of hash iterations used to previously create the hash/digest.
- * @since 1.2
- */
- public void setIterations(int iterations) {
- this.iterations = Math.max(DEFAULT_ITERATIONS, iterations);
- }
-
- /**
- * Sets the salt used to previously compute AN ALREADY GENERATED HASH.
- *
- * This is provided ONLY to reconstitute a Hash instance that has already been computed. It should ONLY
- * ever be invoked when re-constructing a hash instance from an already-hashed value.
- *
- * @param salt the salt used to previously create the hash/digest.
- * @since 1.2
- */
- public void setSalt(ByteSource salt) {
- this.salt = salt;
- }
-
- /**
- * Returns the JDK MessageDigest instance to use for executing the hash.
- *
- * @param algorithmName the algorithm to use for the hash, provided by subclasses.
- * @return the MessageDigest object for the specified {@code algorithm}.
- * @throws UnknownAlgorithmException if the specified algorithm name is not available.
- */
- @Override
- protected MessageDigest getDigest(String algorithmName) throws UnknownAlgorithmException {
- try {
- return MessageDigest.getInstance(algorithmName);
- } catch (NoSuchAlgorithmException e) {
- String msg = "No native '" + algorithmName + "' MessageDigest instance available on the current JVM.";
- throw new UnknownAlgorithmException(msg, e);
- }
- }
-
- /**
- * Hashes the specified byte array without a salt for a single iteration.
- *
- * @param bytes the bytes to hash.
- * @return the hashed bytes.
- * @throws UnknownAlgorithmException if the configured {@link #getAlgorithmName() algorithmName} is not available.
- */
- @Override
- protected byte[] hash(byte[] bytes) throws UnknownAlgorithmException {
- return hash(bytes, null, DEFAULT_ITERATIONS);
- }
-
- /**
- * Hashes the specified byte array using the given {@code salt} for a single iteration.
- *
- * @param bytes the bytes to hash
- * @param salt the salt to use for the initial hash
- * @return the hashed bytes
- * @throws UnknownAlgorithmException if the configured {@link #getAlgorithmName() algorithmName} is not available.
- */
- @Override
- protected byte[] hash(byte[] bytes, byte[] salt) throws UnknownAlgorithmException {
- return hash(bytes, salt, DEFAULT_ITERATIONS);
- }
-
- /**
- * Hashes the specified byte array using the given {@code salt} for the specified number of iterations.
- *
- * @param bytes the bytes to hash
- * @param salt the salt to use for the initial hash
- * @param hashIterations the number of times the the {@code bytes} will be hashed (for attack resiliency).
- * @return the hashed bytes.
- * @throws UnknownAlgorithmException if the {@link #getAlgorithmName() algorithmName} is not available.
- */
- @Override
- protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) throws UnknownAlgorithmException {
- MessageDigest digest = getDigest(getAlgorithmName());
- if (salt.length != 0) {
- digest.reset();
- digest.update(salt);
- }
- byte[] hashed = digest.digest(bytes);
- int iterations = hashIterations - 1; //already hashed once above
- //iterate remaining number:
- for (int i = 0; i < iterations; i++) {
- digest.reset();
- hashed = digest.digest(hashed);
- }
- return hashed;
- }
-
- @Override
- public boolean isEmpty() {
- return this.bytes == null || this.bytes.length == 0;
- }
-
- /**
- * Returns a hex-encoded string of the underlying {@link #getBytes byte array}.
- *
- * This implementation caches the resulting hex string so multiple calls to this method remain efficient.
- * However, calling {@link #setBytes setBytes} will null the cached value, forcing it to be recalculated the
- * next time this method is called.
- *
- * @return a hex-encoded string of the underlying {@link #getBytes byte array}.
- */
- @Override
- public String toHex() {
- if (this.hexEncoded == null) {
- this.hexEncoded = Hex.encodeToString(getBytes());
- }
- return this.hexEncoded;
- }
-
- /**
- * Returns a Base64-encoded string of the underlying {@link #getBytes byte array}.
- *
- * This implementation caches the resulting Base64 string so multiple calls to this method remain efficient.
- * However, calling {@link #setBytes setBytes} will null the cached value, forcing it to be recalculated the
- * next time this method is called.
- *
- * @return a Base64-encoded string of the underlying {@link #getBytes byte array}.
- */
- @Override
- public String toBase64() {
- if (this.base64Encoded == null) {
- //cache result in case this method is called multiple times.
- this.base64Encoded = Base64.encodeToString(getBytes());
- }
- return this.base64Encoded;
- }
-
- /**
- * Simple implementation that merely returns {@link #toHex() toHex()}.
- *
- * @return the {@link #toHex() toHex()} value.
- */
- @Override
- public String toString() {
- return toHex();
- }
-
- /**
- * Returns {@code true} if the specified object is a Hash and its {@link #getBytes byte array} is identical to
- * this Hash's byte array, {@code false} otherwise.
- *
- * @param o the object (Hash) to check for equality.
- * @return {@code true} if the specified object is a Hash and its {@link #getBytes byte array} is identical to
- * this Hash's byte array, {@code false} otherwise.
- */
- @Override
- public boolean equals(Object o) {
- if (o instanceof Hash) {
- Hash other = (Hash) o;
- return MessageDigest.isEqual(getBytes(), other.getBytes());
- }
- return false;
- }
-
- /**
- * Simply returns toHex().hashCode();
- *
- * @return toHex().hashCode()
- */
- @Override
- public int hashCode() {
- if (this.bytes == null || this.bytes.length == 0) {
- return 0;
- }
- return Arrays.hashCode(this.bytes);
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shiro.crypto.hash;
+
+import org.apache.shiro.crypto.UnknownAlgorithmException;
+import org.apache.shiro.lang.codec.Base64;
+import org.apache.shiro.lang.codec.CodecException;
+import org.apache.shiro.lang.codec.Hex;
+import org.apache.shiro.lang.util.ByteSource;
+import org.apache.shiro.lang.util.SimpleByteSource;
+import org.apache.shiro.lang.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A {@code Hash} implementation that allows any {@link java.security.MessageDigest MessageDigest} algorithm name to
+ * be used. This class is a less type-safe variant than the other {@code AbstractHash} subclasses
+ * (e.g. {@link Sha512Hash}, etc.), but it does allow for any algorithm name to be specified in case the other subclass
+ * implementations do not represent an algorithm that you may want to use.
+ *
+ * As of Shiro 1.1, this class effectively replaces the (now-deprecated) {@link AbstractHash} class. It subclasses
+ * {@code AbstractHash} only to retain backwards-compatibility.
+ *
+ * @since 1.1
+ */
+public class SimpleHash extends AbstractHash {
+
+ private static final int DEFAULT_ITERATIONS = 1;
+ private static final long serialVersionUID = -6689895264902387303L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleHash.class);
+
+ /**
+ * The {@link java.security.MessageDigest MessageDigest} algorithm name to use when performing the hash.
+ */
+ private final String algorithmName;
+
+ /**
+ * The hashed data
+ */
+ private byte[] bytes;
+
+ /**
+ * Supplied salt, if any.
+ */
+ private ByteSource salt;
+
+ /**
+ * Number of hash iterations to perform. Defaults to 1 in the constructor.
+ */
+ private int iterations;
+
+ /**
+ * Cached value of the {@link #toHex() toHex()} call so multiple calls won't incur repeated overhead.
+ */
+ private transient String hexEncoded;
+
+ /**
+ * Cached value of the {@link #toBase64() toBase64()} call so multiple calls won't incur repeated overhead.
+ */
+ private transient String base64Encoded;
+
+ /**
+ * Creates an new instance with only its {@code algorithmName} set - no hashing is performed.
+ *
+ * Because all other constructors in this class hash the {@code source} constructor argument, this
+ * constructor is useful in scenarios when you have a byte array that you know is already hashed and
+ * just want to set the bytes in their raw form directly on an instance. After using this constructor,
+ * you can then immediately call {@link #setBytes setBytes} to have a fully-initialized instance.
+ *
+ * N.B.The algorithm identified by the {@code algorithmName} parameter must be available on the JVM. If it
+ * is not, a {@link UnknownAlgorithmException} will be thrown when the hash is performed (not at instantiation).
+ *
+ * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
+ * performing the hash.
+ * @see UnknownAlgorithmException
+ */
+ public SimpleHash(String algorithmName) {
+ this.algorithmName = algorithmName;
+ this.iterations = DEFAULT_ITERATIONS;
+ }
+
+ /**
+ * Creates an {@code algorithmName}-specific hash of the specified {@code source} with no {@code salt} using a
+ * single hash iteration.
+ *
+ * This is a convenience constructor that merely executes this( algorithmName, source, null, 1);
.
+ *
+ * Please see the
+ * {@link #SimpleHash(String algorithmName, Object source, Object salt, int numIterations)
+ * SimpleHashHash(algorithmName, Object,Object,int)}
+ * constructor for the types of Objects that may be passed into this constructor, as well as how to support further
+ * types.
+ *
+ * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
+ * performing the hash.
+ * @param source the object to be hashed.
+ * @throws org.apache.shiro.lang.codec.CodecException if the specified {@code source} cannot be converted
+ * into a byte array (byte[]).
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
+ */
+ public SimpleHash(String algorithmName, Object source) throws CodecException, UnknownAlgorithmException {
+ //noinspection NullableProblems
+ this(algorithmName, source, SimpleByteSource.empty(), DEFAULT_ITERATIONS);
+ }
+
+ /**
+ * Creates an {@code algorithmName}-specific hash of the specified {@code source} using the given {@code salt}
+ * using a single hash iteration.
+ *
+ * It is a convenience constructor that merely executes this( algorithmName, source, salt, 1);
.
+ *
+ * Please see the
+ * {@link #SimpleHash(String algorithmName, Object source, Object salt, int numIterations)
+ * SimpleHashHash(algorithmName, Object,Object,int)}
+ * constructor for the types of Objects that may be passed into this constructor, as well as how to support further
+ * types.
+ *
+ * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
+ * performing the hash.
+ * @param source the source object to be hashed.
+ * @param salt the salt to use for the hash
+ * @throws CodecException if either constructor argument cannot be converted into a byte array.
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
+ */
+ public SimpleHash(String algorithmName, Object source, Object salt) throws CodecException, UnknownAlgorithmException {
+ this(algorithmName, source, salt, DEFAULT_ITERATIONS);
+ }
+
+ /**
+ * Creates an {@code algorithmName}-specific hash of the specified {@code source} using the given {@code salt}
+ * using a single hash iteration.
+ *
+ * It is a convenience constructor that merely executes this( algorithmName, source, salt, 1);
.
+ *
+ * Please see the
+ * {@link #SimpleHash(String algorithmName, Object source, Object salt, int numIterations)
+ * SimpleHashHash(algorithmName, Object,Object,int)}
+ * constructor for the types of Objects that may be passed into this constructor, as well as how to support further
+ * types.
+ *
+ * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
+ * performing the hash.
+ * @param source the source object to be hashed.
+ * @param hashIterations the number of times the {@code source} argument hashed for attack resiliency.
+ * @throws CodecException if either constructor argument cannot be converted into a byte array.
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
+ */
+ public SimpleHash(String algorithmName, Object source, int hashIterations) throws CodecException, UnknownAlgorithmException {
+ this(algorithmName, source, SimpleByteSource.empty(), hashIterations);
+ }
+
+ /**
+ * Creates an {@code algorithmName}-specific hash of the specified {@code source} using the given
+ * {@code salt} a total of {@code hashIterations} times.
+ *
+ * By default, this class only supports Object method arguments of
+ * type {@code byte[]}, {@code char[]}, {@link String}, {@link java.io.File File},
+ * {@link java.io.InputStream InputStream} or {@link org.apache.shiro.lang.util.ByteSource ByteSource}. If either
+ * argument is anything other than these types a {@link org.apache.shiro.lang.codec.CodecException CodecException}
+ * will be thrown.
+ *
+ * If you want to be able to hash other object types, or use other salt types, you need to override the
+ * {@link #toBytes(Object) toBytes(Object)} method to support those specific types. Your other option is to
+ * convert your arguments to one of the default supported types first before passing them in to this
+ * constructor}.
+ *
+ * @param algorithmName the {@link java.security.MessageDigest MessageDigest} algorithm name to use when
+ * performing the hash.
+ * @param source the source object to be hashed.
+ * @param salt the salt to use for the hash
+ * @param hashIterations the number of times the {@code source} argument hashed for attack resiliency.
+ * @throws CodecException if either Object constructor argument cannot be converted into a byte array.
+ * @throws UnknownAlgorithmException if the {@code algorithmName} is not available.
+ */
+ public SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)
+ throws CodecException, UnknownAlgorithmException {
+ if (!StringUtils.hasText(algorithmName)) {
+ throw new NullPointerException("algorithmName argument cannot be null or empty.");
+ }
+ this.algorithmName = algorithmName;
+ this.iterations = Math.max(DEFAULT_ITERATIONS, hashIterations);
+ ByteSource saltBytes = convertSaltToBytes(salt);
+ this.salt = saltBytes;
+ ByteSource sourceBytes = convertSourceToBytes(source);
+ hash(sourceBytes, saltBytes, hashIterations);
+ }
+
+ /**
+ * Acquires the specified {@code source} argument's bytes and returns them in the form of a {@code ByteSource} instance.
+ *
+ * This implementation merely delegates to the convenience {@link #toByteSource(Object)} method for generic
+ * conversion. Can be overridden by subclasses for source-specific conversion.
+ *
+ * @param source the source object to be hashed.
+ * @return the source's bytes in the form of a {@code ByteSource} instance.
+ * @since 1.2
+ */
+ protected ByteSource convertSourceToBytes(Object source) {
+ return toByteSource(source);
+ }
+
+ /**
+ * Acquires the specified {@code salt} argument's bytes and returns them in the form of a {@code ByteSource} instance.
+ *
+ * This implementation merely delegates to the convenience {@link #toByteSource(Object)} method for generic
+ * conversion. Can be overridden by subclasses for salt-specific conversion.
+ *
+ * @param salt the salt to be use for the hash.
+ * @return the salt's bytes in the form of a {@code ByteSource} instance.
+ * @since 1.2
+ */
+ protected ByteSource convertSaltToBytes(Object salt) {
+ return toByteSource(salt);
+ }
+
+ /**
+ * Converts a given object into a {@code ByteSource} instance. Assumes the object can be converted to bytes.
+ *
+ * @param object the Object to convert into a {@code ByteSource} instance.
+ * @return the {@code ByteSource} representation of the specified object's bytes.
+ * @since 1.2
+ */
+ protected ByteSource toByteSource(Object object) {
+ if (object instanceof ByteSource) {
+ return (ByteSource) object;
+ }
+ byte[] bytes = toBytes(object);
+ return ByteSource.Util.bytes(bytes);
+ }
+
+ private void hash(ByteSource source, ByteSource salt, int hashIterations) throws CodecException, UnknownAlgorithmException {
+ byte[] saltBytes = requireNonNull(salt).getBytes();
+ byte[] hashedBytes = hash(source.getBytes(), saltBytes, hashIterations);
+ setBytes(hashedBytes);
+ }
+
+ /**
+ * Returns the {@link java.security.MessageDigest MessageDigest} algorithm name to use when performing the hash.
+ *
+ * @return the {@link java.security.MessageDigest MessageDigest} algorithm name to use when performing the hash.
+ */
+ @Override
+ public String getAlgorithmName() {
+ return this.algorithmName;
+ }
+
+ @Override
+ public ByteSource getSalt() {
+ return this.salt;
+ }
+
+ @Override
+ public int getIterations() {
+ return this.iterations;
+ }
+
+ @Override
+ public boolean matchesPassword(ByteSource plaintextBytes) {
+ try {
+ SimpleHash otherHash = new SimpleHash(this.getAlgorithmName(), plaintextBytes, this.getSalt(), this.getIterations());
+ return this.equals(otherHash);
+ } catch (IllegalArgumentException illegalArgumentException) {
+ // cannot recreate hash. Do not log password.
+ LOG.warn("Cannot recreate a hash using the same parameters.", illegalArgumentException);
+ return false;
+ }
+ }
+
+ @Override
+ public byte[] getBytes() {
+ return this.bytes;
+ }
+
+ /**
+ * Sets the raw bytes stored by this hash instance.
+ *
+ * The bytes are kept in raw form - they will not be hashed/changed. This is primarily a utility method for
+ * constructing a Hash instance when the hashed value is already known.
+ *
+ * @param alreadyHashedBytes the raw already-hashed bytes to store in this instance.
+ */
+ @Override
+ public void setBytes(byte[] alreadyHashedBytes) {
+ this.bytes = alreadyHashedBytes;
+ this.hexEncoded = null;
+ this.base64Encoded = null;
+ }
+
+ /**
+ * Sets the iterations used to previously compute AN ALREADY GENERATED HASH.
+ *
+ * This is provided ONLY to reconstitute an already-created Hash instance. It should ONLY ever be
+ * invoked when re-constructing a hash instance from an already-hashed value.
+ *
+ * @param iterations the number of hash iterations used to previously create the hash/digest.
+ * @since 1.2
+ */
+ public void setIterations(int iterations) {
+ this.iterations = Math.max(DEFAULT_ITERATIONS, iterations);
+ }
+
+ /**
+ * Sets the salt used to previously compute AN ALREADY GENERATED HASH.
+ *
+ * This is provided ONLY to reconstitute a Hash instance that has already been computed. It should ONLY
+ * ever be invoked when re-constructing a hash instance from an already-hashed value.
+ *
+ * @param salt the salt used to previously create the hash/digest.
+ * @since 1.2
+ */
+ public void setSalt(ByteSource salt) {
+ this.salt = salt;
+ }
+
+ /**
+ * Returns the JDK MessageDigest instance to use for executing the hash.
+ *
+ * @param algorithmName the algorithm to use for the hash, provided by subclasses.
+ * @return the MessageDigest object for the specified {@code algorithm}.
+ * @throws UnknownAlgorithmException if the specified algorithm name is not available.
+ */
+ @Override
+ protected MessageDigest getDigest(String algorithmName) throws UnknownAlgorithmException {
+ try {
+ return MessageDigest.getInstance(algorithmName);
+ } catch (NoSuchAlgorithmException e) {
+ String msg = "No native '" + algorithmName + "' MessageDigest instance available on the current JVM.";
+ throw new UnknownAlgorithmException(msg, e);
+ }
+ }
+
+ /**
+ * Hashes the specified byte array without a salt for a single iteration.
+ *
+ * @param bytes the bytes to hash.
+ * @return the hashed bytes.
+ * @throws UnknownAlgorithmException if the configured {@link #getAlgorithmName() algorithmName} is not available.
+ */
+ @Override
+ protected byte[] hash(byte[] bytes) throws UnknownAlgorithmException {
+ return hash(bytes, null, DEFAULT_ITERATIONS);
+ }
+
+ /**
+ * Hashes the specified byte array using the given {@code salt} for a single iteration.
+ *
+ * @param bytes the bytes to hash
+ * @param salt the salt to use for the initial hash
+ * @return the hashed bytes
+ * @throws UnknownAlgorithmException if the configured {@link #getAlgorithmName() algorithmName} is not available.
+ */
+ @Override
+ protected byte[] hash(byte[] bytes, byte[] salt) throws UnknownAlgorithmException {
+ return hash(bytes, salt, DEFAULT_ITERATIONS);
+ }
+
+ /**
+ * Hashes the specified byte array using the given {@code salt} for the specified number of iterations.
+ *
+ * @param bytes the bytes to hash
+ * @param salt the salt to use for the initial hash
+ * @param hashIterations the number of times the the {@code bytes} will be hashed (for attack resiliency).
+ * @return the hashed bytes.
+ * @throws UnknownAlgorithmException if the {@link #getAlgorithmName() algorithmName} is not available.
+ */
+ @Override
+ protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) throws UnknownAlgorithmException {
+ MessageDigest digest = getDigest(getAlgorithmName());
+ if (salt.length != 0) {
+ digest.reset();
+ digest.update(salt);
+ }
+ byte[] hashed = digest.digest(bytes);
+ //already hashed once above
+ int iterations = hashIterations - 1;
+ //iterate remaining number:
+ for (int i = 0; i < iterations; i++) {
+ digest.reset();
+ hashed = digest.digest(hashed);
+ }
+ return hashed;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.bytes == null || this.bytes.length == 0;
+ }
+
+ /**
+ * Returns a hex-encoded string of the underlying {@link #getBytes byte array}.
+ *
+ * This implementation caches the resulting hex string so multiple calls to this method remain efficient.
+ * However, calling {@link #setBytes setBytes} will null the cached value, forcing it to be recalculated the
+ * next time this method is called.
+ *
+ * @return a hex-encoded string of the underlying {@link #getBytes byte array}.
+ */
+ @Override
+ public String toHex() {
+ if (this.hexEncoded == null) {
+ this.hexEncoded = Hex.encodeToString(getBytes());
+ }
+ return this.hexEncoded;
+ }
+
+ /**
+ * Returns a Base64-encoded string of the underlying {@link #getBytes byte array}.
+ *
+ * This implementation caches the resulting Base64 string so multiple calls to this method remain efficient.
+ * However, calling {@link #setBytes setBytes} will null the cached value, forcing it to be recalculated the
+ * next time this method is called.
+ *
+ * @return a Base64-encoded string of the underlying {@link #getBytes byte array}.
+ */
+ @Override
+ public String toBase64() {
+ if (this.base64Encoded == null) {
+ //cache result in case this method is called multiple times.
+ this.base64Encoded = Base64.encodeToString(getBytes());
+ }
+ return this.base64Encoded;
+ }
+
+ /**
+ * Simple implementation that merely returns {@link #toHex() toHex()}.
+ *
+ * @return the {@link #toHex() toHex()} value.
+ */
+ @Override
+ public String toString() {
+ return toHex();
+ }
+
+ /**
+ * Returns {@code true} if the specified object is a Hash and its {@link #getBytes byte array} is identical to
+ * this Hash's byte array, {@code false} otherwise.
+ *
+ * @param o the object (Hash) to check for equality.
+ * @return {@code true} if the specified object is a Hash and its {@link #getBytes byte array} is identical to
+ * this Hash's byte array, {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Hash) {
+ Hash other = (Hash) o;
+ return MessageDigest.isEqual(getBytes(), other.getBytes());
+ }
+ return false;
+ }
+
+ /**
+ * Simply returns toHex().hashCode();
+ *
+ * @return toHex().hashCode()
+ */
+ @Override
+ public int hashCode() {
+ if (this.bytes == null || this.bytes.length == 0) {
+ return 0;
+ }
+ return Arrays.hashCode(this.bytes);
+ }
+}
diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashProvider.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashProvider.java
index 5b4a44df2c..e0772b9491 100644
--- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashProvider.java
+++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashProvider.java
@@ -36,15 +36,16 @@
/**
* Creates a hash provider for salt (+pepper) and Hash-based KDFs, i.e. where the algorithm name
* is a SHA algorithm or similar.
+ *
* @since 2.0
*/
public class SimpleHashProvider implements HashSpi {
- private static final SetFor more information, see Pepper (cryptography) on Wikipedia.
+ *For more information, see + * Pepper (cryptography) on Wikipedia.
*/ public static final String PARAMETER_SECRET_SALT = "SimpleHash.secretSalt"; diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashRequest.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashRequest.java index ffd2989d28..302b8b4eb1 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashRequest.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/SimpleHashRequest.java @@ -34,18 +34,28 @@ */ public class SimpleHashRequest implements HashRequest { - private final ByteSource source; //cannot be null - this is the source to hash. - private final ByteSource salt; //null = no salt specified - private final String algorithmName; //null = let the HashService decide. + /** + * cannot be null - this is the source to hash. + */ + private final ByteSource source; + /** + * can be null = no salt specified + */ + private final ByteSource salt; + /** + * can be null = let the HashService decide. + */ + private final String algorithmName; private final MapMessageDigest
mechanism.
+ */
+package org.apache.shiro.crypto.hash.format;
diff --git a/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/DefaultHashServiceTest.groovy b/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/DefaultHashServiceTest.groovy
index 93e4cca6ad..2d8ea5b94e 100644
--- a/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/DefaultHashServiceTest.groovy
+++ b/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/DefaultHashServiceTest.groovy
@@ -51,7 +51,7 @@ class DefaultHashServiceTest {
@Test
void testRequestWithEmptySource() {
- def source = ByteSource.Util.bytes((byte[])null)
+ def source = ByteSource.Util.bytes((byte[]) null)
def request = new HashRequest.Builder().setSource(source).build()
def service = createSha256Service()
assertNull service.computeHash(request)
diff --git a/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/format/Shiro1CryptFormatTest.groovy b/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/format/Shiro1CryptFormatTest.groovy
index 7ac441e3a6..7a82d3d6e0 100644
--- a/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/format/Shiro1CryptFormatTest.groovy
+++ b/crypto/hash/src/test/groovy/org/apache/shiro/crypto/hash/format/Shiro1CryptFormatTest.groovy
@@ -51,7 +51,7 @@ class Shiro1CryptFormatTest {
String formatted = format.format(hash);
String expected =
- Shiro1CryptFormat.MCF_PREFIX + alg + '$' + iterations + '$' + salt.toBase64() + '$' + hash.toBase64()
+ Shiro1CryptFormat.MCF_PREFIX + alg + '$' + iterations + '$' + salt.toBase64() + '$' + hash.toBase64()
assertNotNull formatted
assertEquals expected, formatted
diff --git a/crypto/pom.xml b/crypto/pom.xml
index 28cda20fb4..566402c660 100644
--- a/crypto/pom.xml
+++ b/crypto/pom.xml
@@ -17,7 +17,8 @@
~ specific language governing permissions and limitations
~ under the License.
-->
-The default value is {@value DEFAULT_ALGORITHM_NAME} when this parameter is not specified.
*/ public static final String PARAMETER_ALGORITHM_NAME = "Argon2.algorithmName"; + + /** + * Argon2 algorithm version. + */ public static final String PARAMETER_ALGORITHM_VERSION = "Argon2.version"; /** @@ -187,8 +217,19 @@ public static final class Parameters { */ public static final String PARAMETER_SALT = "Argon2.salt"; + /** + * Argon2 parameter iterations. + */ public static final String PARAMETER_ITERATIONS = "Argon2.iterations"; + + /** + * Argon2 parameter memory kib. + */ public static final String PARAMETER_MEMORY_KIB = "Argon2.memoryKib"; + + /** + * Argon2 parameter parallelism. + */ public static final String PARAMETER_PARALLELISM = "Argon2.parallelism"; /** diff --git a/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/package-info.java b/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/package-info.java new file mode 100644 index 0000000000..1cc5c85153 --- /dev/null +++ b/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/package-info.java @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.shiro.crypto.support.hashes.argon2; diff --git a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptHash.java b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptHash.java index f73b40a560..c77c7c1175 100644 --- a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptHash.java +++ b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptHash.java @@ -41,23 +41,23 @@ */ class BCryptHash extends AbstractCryptHash { - private static final long serialVersionUID = 6957869292324606101L; - - private static final Logger LOG = LoggerFactory.getLogger(AbstractCryptHash.class); - public static final String DEFAULT_ALGORITHM_NAME = "2y"; public static final int DEFAULT_COST = 10; public static final int SALT_LENGTH = 16; + private static final long serialVersionUID = 6957869292324606101L; + + private static final Logger LOG = LoggerFactory.getLogger(AbstractCryptHash.class); + private static final Set* Unix stores password hashes computed with crypt in the /etc/passwd file using radix-64 encoding called B64. It uses a - * mostly-alphanumeric set of characters, plus . and /. Its 64-character set is "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". + * mostly-alphanumeric set of characters, plus . and /. + * Its 64-character set is "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". * Padding is not used. ** * @since 2.0 */ +@SuppressWarnings({"checkstyle:MagicNumber", "checkstyle:BooleanExpressionComplexity", + "checkstyle:NPathComplexity", "checkstyle:CyclomaticComplexity"}) interface OpenBSDBase64 { @@ -46,9 +49,11 @@ interface OpenBSDBase64 { byte[] encode(byte[] rawBytes); /** - * From a UTF-8 encoded string representing radix64 encoded data as byte array, decodes the raw bytes from it. + * From a UTF-8 encoded string representing radix64 encoded data as byte array, + * decodes the raw bytes from it. * - * @param utf8EncodedRadix64String from a string get it with
"m0CrhHm10qJ3lXRY.5zDGO".getBytes(StandardCharsets.UTF8)
+ * @param utf8EncodedRadix64String from a string get it with
+ * "m0CrhHm10qJ3lXRY.5zDGO".getBytes(StandardCharsets.UTF8)
* @return the raw bytes encoded by this utf-8 radix4 string
*/
byte[] decode(byte[] utf8EncodedRadix64String);
@@ -70,7 +75,7 @@ class Default implements OpenBSDBase64 {
26, 27, -1, -1, -1, -1, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53};
- private static final byte[] MAP = new byte[]{
+ private static final byte[] MAP = new byte[] {
'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
@@ -172,6 +177,7 @@ private static byte[] encode(final byte[] in, final byte[] map) {
out[index++] = map[((in[end] & 0x03) << 4) | ((in[end + 1] & 0xff) >> 4)];
out[index] = map[((in[end + 1] & 0x0f) << 2)];
break;
+ default:
}
return out;
}
diff --git a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/package-info.java b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/package-info.java
new file mode 100644
index 0000000000..b7ff699798
--- /dev/null
+++ b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shiro.crypto.support.hashes.bcrypt;
diff --git a/event/pom.xml b/event/pom.xml
index 090e6a3cf2..2652390688 100644
--- a/event/pom.xml
+++ b/event/pom.xml
@@ -17,7 +17,8 @@
~ specific language governing permissions and limitations
~ under the License.
-->
-* This design (and its constituent helper components) was largely influenced by * Guava's EventBus * concept, although no code was shared/imported (even though Guava is Apache 2.0 licensed and could have * been used). - * + *
* This implementation is thread-safe and may be used concurrently.
*
* @since 1.3
*/
public class DefaultEventBus implements EventBus {
- private static final Logger log = LoggerFactory.getLogger(DefaultEventBus.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultEventBus.class);
- private static final String EVENT_LISTENER_ERROR_MSG = "Event listener processing failed. Listeners should " +
- "generally handle exceptions directly and not propagate to the event bus.";
+ private static final String EVENT_LISTENER_ERROR_MSG = "Event listener processing failed. Listeners should "
+ + "generally handle exceptions directly and not propagate to the event bus.";
//this is stateless, we can retain a static final reference:
private static final EventListenerComparator EVENT_LISTENER_COMPARATOR = new EventListenerComparator();
@@ -103,7 +102,8 @@ public class DefaultEventBus implements EventBus {
private final Lock registryWriteLock;
public DefaultEventBus() {
- this.registry = new LinkedHashMap
* The {@code onEvent(B b)} method will be invoked on the subscriber and the
* {@code onEvent(A a)} method will not be invoked. This is to prevent multiple dispatching of a single event
* to the same consumer.
diff --git a/event/src/main/java/org/apache/shiro/event/support/EventListener.java b/event/src/main/java/org/apache/shiro/event/support/EventListener.java
index 683c51d72e..53821688d4 100644
--- a/event/src/main/java/org/apache/shiro/event/support/EventListener.java
+++ b/event/src/main/java/org/apache/shiro/event/support/EventListener.java
@@ -34,13 +34,13 @@
*
* @see SingleArgumentMethodEventListener
* @see AnnotationEventListenerResolver
- *
* @since 1.3
*/
public interface EventListener {
/**
* Returns {@code true} if the listener instance can process the specified event object, {@code false} otherwise.
+ *
* @param event the event object to test
* @return {@code true} if the listener instance can process the specified event object, {@code false} otherwise.
*/
diff --git a/event/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java b/event/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java
index 92bb595cdf..06e15ddaee 100644
--- a/event/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java
+++ b/event/src/main/java/org/apache/shiro/event/support/EventListenerComparator.java
@@ -52,12 +52,13 @@ public int compare(EventListener a, EventListener b) {
return 0;
} else {
if (a instanceof TypedEventListener) {
- TypedEventListener ta = (TypedEventListener)a;
+ TypedEventListener ta = (TypedEventListener) a;
if (b instanceof TypedEventListener) {
- TypedEventListener tb = (TypedEventListener)b;
+ TypedEventListener tb = (TypedEventListener) b;
return EVENT_CLASS_COMPARATOR.compare(ta.getEventType(), tb.getEventType());
} else {
- return -1; //TypedEventListeners are 'less than' (higher priority) than non typed
+ //TypedEventListeners are 'less than' (higher priority) than non typed
+ return -1;
}
} else {
if (b instanceof TypedEventListener) {
diff --git a/event/src/main/java/org/apache/shiro/event/support/package-info.java b/event/src/main/java/org/apache/shiro/event/support/package-info.java
new file mode 100644
index 0000000000..d67797c80d
--- /dev/null
+++ b/event/src/main/java/org/apache/shiro/event/support/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.shiro.event.support;
diff --git a/event/src/test/groovy/org/apache/shiro/event/support/SingleArgumentMethodEventListenerTest.groovy b/event/src/test/groovy/org/apache/shiro/event/support/SingleArgumentMethodEventListenerTest.groovy
index 44d3f251ec..e930941591 100644
--- a/event/src/test/groovy/org/apache/shiro/event/support/SingleArgumentMethodEventListenerTest.groovy
+++ b/event/src/test/groovy/org/apache/shiro/event/support/SingleArgumentMethodEventListenerTest.groovy
@@ -100,5 +100,4 @@ class SingleArgumentMethodEventListenerTest {
}
-
}
diff --git a/integration-tests/guice3/pom.xml b/integration-tests/guice3/pom.xml
index 1bac8e1b49..584f05728c 100644
--- a/integration-tests/guice3/pom.xml
+++ b/integration-tests/guice3/pom.xml
@@ -17,88 +17,89 @@
~ specific language governing permissions and limitations
~ under the License.
-->
-
-
-
+
+
* Mainly for internal use within the framework; consider Jakarta's Commons Lang
* >= 2.0 for a more comprehensive suite of assertion utilities.
* Call {@link #isTrue(boolean)} if you wish to
* throw {@link IllegalArgumentException} on an assertion failure.
* Simple utility class for String operations useful across the framework.
@@ -29,9 +37,8 @@
*
* @since 0.9
*/
-public class StringUtils {
-
- //TODO - complete JavaDoc
+@SuppressWarnings("checkstyle:CyclomaticComplexity")
+public final class StringUtils {
/**
* Constant representing the empty string, equal to ""
@@ -48,6 +55,9 @@ public class StringUtils {
*/
public static final char DEFAULT_QUOTE_CHAR = '"';
+ private StringUtils() {
+ }
+
/**
* Check whether the given String has actual text.
* More specifically, returns This is equivalent of calling {@link #split(String, char, char, char, boolean, boolean)} with
* {@code line, DEFAULT_DELIMITER_CHAR, DEFAULT_QUOTE_CHAR, DEFAULT_QUOTE_CHAR, false, true}.
-
- #{of:printStackTrace(requestScope['javax.servlet.error.exception'])}
-
+
+#{of:printStackTrace(requestScope['javax.servlet.error.exception'])}
+ toBytes( new String(chars), {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING} );
@@ -58,7 +59,7 @@ public static byte[] toBytes(char[] chars) {
/**
* Converts the specified character array into a byte array using the specified character encoding.
*
- * This is a convenience method equivalent to calling the {@link #toBytes(String,String)} method with a
+ * This is a convenience method equivalent to calling the {@link #toBytes(String, String)} method with a
* a wrapping String and the specified encoding, i.e.
*
* toBytes( new String(chars), encoding );
@@ -97,8 +98,8 @@ public static byte[] toBytes(String source, String encoding) throws CodecExcepti
try {
return source.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
- String msg = "Unable to convert source [" + source + "] to byte array using " +
- "encoding '" + encoding + "'";
+ String msg = "Unable to convert source [" + source + "] to byte array using "
+ + "encoding '" + encoding + "'";
throw new CodecException(msg, e);
}
}
@@ -149,7 +150,8 @@ public static char[] toChars(byte[] bytes) {
/**
* Converts the specified byte array to a character array using the specified character encoding.
*
- * Effectively calls {@link #toString(byte[], String) toString(bytes,encoding)}.{@link String#toCharArray() toCharArray()};
+ * Effectively calls {@link #toString(byte[], String) toString(bytes,encoding)}
+ * .{@link String#toCharArray() toCharArray()};
*
* @param bytes the byte array to convert to a String
* @param encoding the character encoding used to encode the bytes.
@@ -177,12 +179,12 @@ public static char[] toChars(byte[] bytes, String encoding) throws CodecExceptio
*
* @param o the object to test to see if it can be easily converted to a byte array
* @return {@code true} if the specified object can be easily converted to bytes by instances of this class,
- * {@code false} otherwise.
+ * {@code false} otherwise.
* @since 1.0
*/
protected boolean isByteSource(Object o) {
- return o instanceof byte[] || o instanceof char[] || o instanceof String ||
- o instanceof ByteSource || o instanceof File || o instanceof InputStream;
+ return o instanceof byte[] || o instanceof char[] || o instanceof String
+ || o instanceof ByteSource || o instanceof File || o instanceof InputStream;
}
/**
@@ -272,9 +274,9 @@ protected byte[] toBytes(InputStream in) {
if (in == null) {
throw new IllegalArgumentException("InputStream argument cannot be null.");
}
- final int BUFFER_SIZE = 512;
- ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
- byte[] buffer = new byte[BUFFER_SIZE];
+ final int bufferSize = 512;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(bufferSize);
+ byte[] buffer = new byte[bufferSize];
int bytesRead;
try {
while ((bytesRead = in.read(buffer)) != -1) {
@@ -304,13 +306,13 @@ protected byte[] toBytes(InputStream in) {
* @return a byte array representation of the Object argument.
*/
protected byte[] objectToBytes(Object o) {
- String msg = "The " + getClass().getName() + " implementation only supports conversion to " +
- "byte[] if the source is of type byte[], char[], String, " + ByteSource.class.getName() +
- " File or InputStream. The instance provided as a method " +
- "argument is of type [" + o.getClass().getName() + "]. If you would like to convert " +
- "this argument type to a byte[], you can 1) convert the argument to one of the supported types " +
- "yourself and then use that as the method argument or 2) subclass " + getClass().getName() +
- "and override the objectToBytes(Object o) method.";
+ String msg = "The " + getClass().getName() + " implementation only supports conversion to "
+ + "byte[] if the source is of type byte[], char[], String, " + ByteSource.class.getName()
+ + " File or InputStream. The instance provided as a method "
+ + "argument is of type [" + o.getClass().getName() + "]. If you would like to convert "
+ + "this argument type to a byte[], you can 1) convert the argument to one of the supported types "
+ + "yourself and then use that as the method argument or 2) subclass " + getClass().getName()
+ + "and override the objectToBytes(Object o) method.";
throw new CodecException(msg);
}
diff --git a/lang/src/main/java/org/apache/shiro/lang/codec/H64.java b/lang/src/main/java/org/apache/shiro/lang/codec/H64.java
index fd30aa1dda..c9a5914e50 100644
--- a/lang/src/main/java/org/apache/shiro/lang/codec/H64.java
+++ b/lang/src/main/java/org/apache/shiro/lang/codec/H64.java
@@ -45,25 +45,41 @@
*
* @since 1.2
*/
-public class H64 {
+@SuppressWarnings("checkstyle:MagicNumber")
+public final class H64 {
- private static final char[] itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+ private static final byte FF = (byte) 0xff;
+
+ private static final char[] ITOA_64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+
+ private H64() {
+
+ }
private static short toShort(byte b) {
- return (short) (b & 0xff);
+ return (short) (b & FF);
}
private static int toInt(byte[] bytes, int offset, int numBytes) {
if (numBytes < 1 || numBytes > 4) {
throw new IllegalArgumentException("numBytes must be between 1 and 4.");
}
- int val = toShort(bytes[offset]); //1st byte
- for (int i = 1; i < numBytes; i++) { //any remaining bytes:
+ //1st byte
+ int val = toShort(bytes[offset]);
+ for (int i = 1; i < numBytes; i++) {
+ //any remaining bytes:
short s = toShort(bytes[offset + i]);
switch (i) {
- case 1: val |= s << 8; break;
- case 2: val |= s << 16; break;
- case 3: val |= s << 24; break;
+ case 1:
+ val |= s << (2 << 2);
+ break;
+ case 2:
+ val |= s << ((2 << 2) * 2);
+ break;
+ case 3:
+ val |= s << ((2 << 2) * 3);
+ break;
+ default:
}
}
return val;
@@ -94,7 +110,7 @@ private static void append(Appendable buf, char c) {
*/
private static void encodeAndAppend(int value, Appendable buf, int numChars) {
for (int i = 0; i < numChars; i++) {
- append(buf, itoa64[value & 0x3f]);
+ append(buf, ITOA_64[value & 0x3f]);
value >>= 6;
}
}
@@ -106,16 +122,20 @@ private static void encodeAndAppend(int value, Appendable buf, int numChars) {
* @return
*/
public static String encodeToString(byte[] bytes) {
- if (bytes == null || bytes.length == 0) return null;
+ if (bytes == null || bytes.length == 0) {
+ return null;
+ }
StringBuilder buf = new StringBuilder();
int length = bytes.length;
int remainder = length % 3;
- int i = 0; //starting byte
- int last3ByteIndex = length - remainder; //last byte whose index is a multiple of 3
+ //starting byte
+ int i = 0;
+ //last byte whose index is a multiple of 3
+ int last3ByteIndex = length - remainder;
- for(; i < last3ByteIndex; i += 3) {
+ for (; i < last3ByteIndex; i += 3) {
int twentyFourBit = toInt(bytes, i, 3);
encodeAndAppend(twentyFourBit, buf, 4);
}
diff --git a/lang/src/main/java/org/apache/shiro/lang/codec/Hex.java b/lang/src/main/java/org/apache/shiro/lang/codec/Hex.java
index 00e4e0ad30..0e2cfd6450 100644
--- a/lang/src/main/java/org/apache/shiro/lang/codec/Hex.java
+++ b/lang/src/main/java/org/apache/shiro/lang/codec/Hex.java
@@ -18,6 +18,7 @@
*/
package org.apache.shiro.lang.codec;
+
/**
* Hexadecimal encoder and decoder.
*
@@ -31,7 +32,8 @@
* @see Wikipedia: Hexadecimal
* @since 0.9
*/
-public class Hex {
+@SuppressWarnings("checkstyle:MagicNumber")
+public final class Hex {
/**
* Used to build output as Hex
@@ -41,6 +43,10 @@ public class Hex {
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
+ private Hex() {
+
+ }
+
/**
* Encodes the specified byte array to a character array and then returns that character array
* as a String.
@@ -85,7 +91,7 @@ public static char[] encode(byte[] data) {
*
* @param array An array of character bytes containing hexadecimal digits
* @return A byte array containing binary data decoded from
- * the supplied byte array (representing characters).
+ * the supplied byte array (representing characters).
* @throws IllegalArgumentException Thrown if an odd number of characters is supplied
* to this function
* @see #decode(char[])
@@ -116,10 +122,11 @@ public static byte[] decode(String hex) {
*
* @param data An array of characters containing hexadecimal digits
* @return A byte array containing binary data decoded from
- * the supplied char array.
+ * the supplied char array.
* @throws IllegalArgumentException if an odd number or illegal of characters
* is supplied
*/
+ @SuppressWarnings("magicNumber")
public static byte[] decode(char[] data) throws IllegalArgumentException {
int len = data.length;
@@ -151,7 +158,7 @@ public static byte[] decode(char[] data) throws IllegalArgumentException {
* @throws IllegalArgumentException if ch is an illegal hex character
*/
protected static int toDigit(char ch, int index) throws IllegalArgumentException {
- int digit = Character.digit(ch, 16);
+ int digit = Character.digit(ch, 2 << 3);
if (digit == -1) {
throw new IllegalArgumentException("Illegal hexadecimal character " + ch + " at index " + index);
}
diff --git a/lang/src/main/java/org/apache/shiro/lang/io/ClassResolvingObjectInputStream.java b/lang/src/main/java/org/apache/shiro/lang/io/ClassResolvingObjectInputStream.java
index 941e389de8..1f7f0c73df 100644
--- a/lang/src/main/java/org/apache/shiro/lang/io/ClassResolvingObjectInputStream.java
+++ b/lang/src/main/java/org/apache/shiro/lang/io/ClassResolvingObjectInputStream.java
@@ -29,8 +29,8 @@
/**
* Enables correct ClassLoader lookup in various environments (e.g. JEE Servers, etc.).
*
- * @since 1.2
* @see SHIRO-334
+ * @since 1.2
*/
public class ClassResolvingObjectInputStream extends ObjectInputStream {
@@ -39,12 +39,12 @@ public ClassResolvingObjectInputStream(InputStream inputStream) throws IOExcepti
}
/**
- * Resolves an {@link ObjectStreamClass} by delegating to Shiro's
+ * Resolves an {@link ObjectStreamClass} by delegating to Shiro's
* {@link ClassUtils#forName(String)} utility method, which is known to work in all ClassLoader environments.
- *
+ *
* @param osc the ObjectStreamClass to resolve the class name.
* @return the discovered class
- * @throws IOException never - declaration retained for subclass consistency
+ * @throws IOException never - declaration retained for subclass consistency
* @throws ClassNotFoundException if the class could not be found in any known ClassLoader
*/
@Override
diff --git a/lang/src/main/java/org/apache/shiro/lang/io/DefaultSerializer.java b/lang/src/main/java/org/apache/shiro/lang/io/DefaultSerializer.java
index a48a176cae..a06f7a1421 100644
--- a/lang/src/main/java/org/apache/shiro/lang/io/DefaultSerializer.java
+++ b/lang/src/main/java/org/apache/shiro/lang/io/DefaultSerializer.java
@@ -18,11 +18,18 @@
*/
package org.apache.shiro.lang.io;
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
/**
* Serializer implementation that uses the default JVM serialization mechanism (Object Input/Output Streams).
*
+ * @param source
into a byte[] array by using the
* {@link java.beans.XMLEncoder XMLEncoder} to encode the object out to a
* {@link java.io.ByteArrayOutputStream ByteArrayOutputStream}, where the resulting byte[] array is returned.
+ *
* @param source the Object to convert into a byte[] array.
* @return the byte[] array representation of the XML encoded output.
*/
@@ -64,6 +65,7 @@ public byte[] serialize(Object source) {
* {@link java.io.ByteArrayInputStream ByteArrayInputStream} to wrap the argument and then decode this
* stream via an {@link java.beans.XMLDecoder XMLDecoder}, where the
* {@link java.beans.XMLDecoder#readObject() readObject} call results in the original Object to return.
+ *
* @param serialized the byte[] array representation of the XML encoded output.
* @return the original source Object in reconstituted form.
*/
diff --git a/lang/src/main/java/org/apache/shiro/lang/package-info.java b/lang/src/main/java/org/apache/shiro/lang/package-info.java
new file mode 100644
index 0000000000..76a9d3bec3
--- /dev/null
+++ b/lang/src/main/java/org/apache/shiro/lang/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * Shiro lang package-info.
+ */
+package org.apache.shiro.lang;
diff --git a/lang/src/main/java/org/apache/shiro/lang/util/Assert.java b/lang/src/main/java/org/apache/shiro/lang/util/Assert.java
index c96f3fb624..7bb651e8c7 100644
--- a/lang/src/main/java/org/apache/shiro/lang/util/Assert.java
+++ b/lang/src/main/java/org/apache/shiro/lang/util/Assert.java
@@ -44,7 +44,7 @@
*
* Assert.notNull(clazz, "The class must not be null");
* Assert.isTrue(i > 0, "The value must be greater than zero");
- *
+ * IllegalArgumentException
* if the test result is false
.
* Assert.isTrue(i > 0, "The value must be greater than zero");
+ *
* @param expression a boolean expression
- * @param message the exception message to use if the assertion fails
+ * @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if expression is false
*/
public static void isTrue(boolean expression, String message) {
@@ -72,6 +73,7 @@ public static void isTrue(boolean expression, String message) {
* Assert a boolean expression, throwing IllegalArgumentException
* if the test result is false
.
* Assert.isTrue(i > 0);
+ *
* @param expression a boolean expression
* @throws IllegalArgumentException if expression is false
*/
@@ -82,7 +84,8 @@ public static void isTrue(boolean expression) {
/**
* Assert that an object is null
.
* Assert.isNull(value, "The value must be null");
- * @param object the object to check
+ *
+ * @param object the object to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object is not null
*/
@@ -95,6 +98,7 @@ public static void isNull(Object object, String message) {
/**
* Assert that an object is null
.
* Assert.isNull(value);
+ *
* @param object the object to check
* @throws IllegalArgumentException if the object is not null
*/
@@ -105,7 +109,8 @@ public static void isNull(Object object) {
/**
* Assert that an object is not null
.
* Assert.notNull(clazz, "The class must not be null");
- * @param object the object to check
+ *
+ * @param object the object to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object is null
*/
@@ -118,6 +123,7 @@ public static void notNull(Object object, String message) {
/**
* Assert that an object is not null
.
* Assert.notNull(clazz);
+ *
* @param object the object to check
* @throws IllegalArgumentException if the object is null
*/
@@ -129,7 +135,8 @@ public static void notNull(Object object) {
* Assert that the given String is not empty; that is,
* it must not be null
and not the empty String.
* Assert.hasLength(name, "Name must not be empty");
- * @param text the String to check
+ *
+ * @param text the String to check
* @param message the exception message to use if the assertion fails
* @see StringUtils#hasLength
*/
@@ -143,6 +150,7 @@ public static void hasLength(String text, String message) {
* Assert that the given String is not empty; that is,
* it must not be null
and not the empty String.
* Assert.hasLength(name);
+ *
* @param text the String to check
* @see StringUtils#hasLength
*/
@@ -155,7 +163,8 @@ public static void hasLength(String text) {
* Assert that the given String has valid text content; that is, it must not
* be null
and must contain at least one non-whitespace character.
* Assert.hasText(name, "'name' must not be empty");
- * @param text the String to check
+ *
+ * @param text the String to check
* @param message the exception message to use if the assertion fails
* @see StringUtils#hasText
*/
@@ -169,6 +178,7 @@ public static void hasText(String text, String message) {
* Assert that the given String has valid text content; that is, it must not
* be null
and must contain at least one non-whitespace character.
* Assert.hasText(name, "'name' must not be empty");
+ *
* @param text the String to check
* @see StringUtils#hasText
*/
@@ -180,13 +190,14 @@ public static void hasText(String text) {
/**
* Assert that the given text does not contain the given substring.
* Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");
+ *
* @param textToSearch the text to search
- * @param substring the substring to find within the text
- * @param message the exception message to use if the assertion fails
+ * @param substring the substring to find within the text
+ * @param message the exception message to use if the assertion fails
*/
public static void doesNotContain(String textToSearch, String substring, String message) {
- if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
- textToSearch.indexOf(substring) != -1) {
+ if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring)
+ && textToSearch.contains(substring)) {
throw new IllegalArgumentException(message);
}
}
@@ -194,8 +205,9 @@ public static void doesNotContain(String textToSearch, String substring, String
/**
* Assert that the given text does not contain the given substring.
* Assert.doesNotContain(name, "rod");
+ *
* @param textToSearch the text to search
- * @param substring the substring to find within the text
+ * @param substring the substring to find within the text
*/
public static void doesNotContain(String textToSearch, String substring) {
doesNotContain(textToSearch, substring,
@@ -207,7 +219,8 @@ public static void doesNotContain(String textToSearch, String substring) {
* Assert that an array has elements; that is, it must not be
* null
and must have at least one element.
* Assert.notEmpty(array, "The array must have elements");
- * @param array the array to check
+ *
+ * @param array the array to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object array is null
or has no elements
*/
@@ -221,6 +234,7 @@ public static void notEmpty(Object[] array, String message) {
* Assert that an array has elements; that is, it must not be
* null
and must have at least one element.
* Assert.notEmpty(array);
+ *
* @param array the array to check
* @throws IllegalArgumentException if the object array is null
or has no elements
*/
@@ -232,7 +246,8 @@ public static void notEmpty(Object[] array) {
* Assert that an array has no null elements.
* Note: Does not complain if the array is empty!
* Assert.noNullElements(array, "The array must have non-null elements");
- * @param array the array to check
+ *
+ * @param array the array to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the object array contains a null
element
*/
@@ -250,6 +265,7 @@ public static void noNullElements(Object[] array, String message) {
* Assert that an array has no null elements.
* Note: Does not complain if the array is empty!
* Assert.noNullElements(array);
+ *
* @param array the array to check
* @throws IllegalArgumentException if the object array contains a null
element
*/
@@ -261,8 +277,9 @@ public static void noNullElements(Object[] array) {
* Assert that a collection has elements; that is, it must not be
* null
and must have at least one element.
* Assert.notEmpty(collection, "Collection must have elements");
+ *
* @param collection the collection to check
- * @param message the exception message to use if the assertion fails
+ * @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the collection is null
or has no elements
*/
public static void notEmpty(Collection collection, String message) {
@@ -275,6 +292,7 @@ public static void notEmpty(Collection collection, String message) {
* Assert that a collection has elements; that is, it must not be
* null
and must have at least one element.
* Assert.notEmpty(collection, "Collection must have elements");
+ *
* @param collection the collection to check
* @throws IllegalArgumentException if the collection is null
or has no elements
*/
@@ -287,7 +305,8 @@ public static void notEmpty(Collection collection) {
* Assert that a Map has entries; that is, it must not be null
* and must have at least one entry.
* Assert.notEmpty(map, "Map must have entries");
- * @param map the map to check
+ *
+ * @param map the map to check
* @param message the exception message to use if the assertion fails
* @throws IllegalArgumentException if the map is null
or has no entries
*/
@@ -301,6 +320,7 @@ public static void notEmpty(Map map, String message) {
* Assert that a Map has entries; that is, it must not be null
* and must have at least one entry.
* Assert.notEmpty(map);
+ *
* @param map the map to check
* @throws IllegalArgumentException if the map is null
or has no entries
*/
@@ -312,8 +332,9 @@ public static void notEmpty(Map map) {
/**
* Assert that the provided object is an instance of the provided class.
* Assert.instanceOf(Foo.class, foo);
+ *
* @param clazz the required class
- * @param obj the object to check
+ * @param obj the object to check
* @throws IllegalArgumentException if the object is not an instance of clazz
* @see Class#isInstance
*/
@@ -324,29 +345,31 @@ public static void isInstanceOf(Class clazz, Object obj) {
/**
* Assert that the provided object is an instance of the provided class.
* Assert.instanceOf(Foo.class, foo);
- * @param type the type to check against
- * @param obj the object to check
+ *
+ * @param type the type to check against
+ * @param obj the object to check
* @param message a message which will be prepended to the message produced by
- * the function itself, and which may be used to provide context. It should
- * normally end in a ": " or ". " so that the function generate message looks
- * ok when prepended to it.
+ * the function itself, and which may be used to provide context. It should
+ * normally end in a ": " or ". " so that the function generate message looks
+ * ok when prepended to it.
* @throws IllegalArgumentException if the object is not an instance of clazz
* @see Class#isInstance
*/
public static void isInstanceOf(Class type, Object obj, String message) {
notNull(type, "Type to check against must not be null");
if (!type.isInstance(obj)) {
- throw new IllegalArgumentException(message +
- "Object of class [" + (obj != null ? obj.getClass().getName() : "null") +
- "] must be an instance of " + type);
+ throw new IllegalArgumentException(message
+ + "Object of class [" + (obj != null ? obj.getClass().getName() : "null")
+ + "] must be an instance of " + type);
}
}
/**
* Assert that superType.isAssignableFrom(subType)
is true
.
* Assert.isAssignable(Number.class, myClass);
+ *
* @param superType the super type to check
- * @param subType the sub type to check
+ * @param subType the sub type to check
* @throws IllegalArgumentException if the classes are not assignable
*/
public static void isAssignable(Class superType, Class subType) {
@@ -356,12 +379,13 @@ public static void isAssignable(Class superType, Class subType) {
/**
* Assert that superType.isAssignableFrom(subType)
is true
.
* Assert.isAssignable(Number.class, myClass);
+ *
* @param superType the super type to check against
- * @param subType the sub type to check
- * @param message a message which will be prepended to the message produced by
- * the function itself, and which may be used to provide context. It should
- * normally end in a ": " or ". " so that the function generate message looks
- * ok when prepended to it.
+ * @param subType the sub type to check
+ * @param message a message which will be prepended to the message produced by
+ * the function itself, and which may be used to provide context. It should
+ * normally end in a ": " or ". " so that the function generate message looks
+ * ok when prepended to it.
* @throws IllegalArgumentException if the classes are not assignable
*/
public static void isAssignable(Class superType, Class subType, String message) {
@@ -377,8 +401,9 @@ public static void isAssignable(Class superType, Class subType, String message)
* if the test result is false
. Call isTrue if you wish to
* throw IllegalArgumentException on an assertion failure.
* Assert.state(id == null, "The id property must not already be initialized");
+ *
* @param expression a boolean expression
- * @param message the exception message to use if the assertion fails
+ * @param message the exception message to use if the assertion fails
* @throws IllegalStateException if expression is false
*/
public static void state(boolean expression, String message) {
@@ -393,6 +418,7 @@ public static void state(boolean expression, String message) {
* Assert.state(id == null);
+ *
* @param expression a boolean expression
* @throws IllegalStateException if the supplied expression is false
*/
diff --git a/lang/src/main/java/org/apache/shiro/lang/util/ByteSource.java b/lang/src/main/java/org/apache/shiro/lang/util/ByteSource.java
index f9a1331cda..c75d074bee 100644
--- a/lang/src/main/java/org/apache/shiro/lang/util/ByteSource.java
+++ b/lang/src/main/java/org/apache/shiro/lang/util/ByteSource.java
@@ -41,7 +41,7 @@ public interface ByteSource {
* underlying wrapped byte array.
*
* @return the Hex-formatted String representation of the
- * underlying wrapped byte array.
+ * underlying wrapped byte array.
*/
String toHex();
@@ -50,7 +50,7 @@ public interface ByteSource {
* underlying wrapped byte array.
*
* @return the Base 64-formatted String representation of the
- * underlying wrapped byte array.
+ * underlying wrapped byte array.
*/
String toBase64();
@@ -59,7 +59,7 @@ public interface ByteSource {
* otherwise.
*
* @return {@code true} if the underlying wrapped byte array is null or empty (zero length), {@code false}
- * otherwise.
+ * otherwise.
* @since 1.2
*/
boolean isEmpty();
@@ -70,7 +70,10 @@ public interface ByteSource {
*
* @since 1.2
*/
- public static final class Util {
+ final class Util {
+
+ private Util() {
+ }
/**
* Returns a new {@code ByteSource} instance representing the specified byte array.
@@ -138,12 +141,13 @@ public static ByteSource bytes(InputStream stream) {
* Returns {@code true} if the specified object can be easily represented as a {@code ByteSource} using
* the {@link ByteSource.Util}'s default heuristics, {@code false} otherwise.
*
- * This implementation merely returns {@link SimpleByteSource}.{@link SimpleByteSource#isCompatible(Object) isCompatible(source)}.
+ * This implementation merely returns {@link SimpleByteSource}
+ * .{@link SimpleByteSource#isCompatible(Object) isCompatible(source)}.
*
* @param source the object to test to see if it can be easily converted to ByteSource instances using default
* heuristics.
* @return {@code true} if the specified object can be easily represented as a {@code ByteSource} using
- * the {@link ByteSource.Util}'s default heuristics, {@code false} otherwise.
+ * the {@link ByteSource.Util}'s default heuristics, {@code false} otherwise.
*/
public static boolean isCompatible(Object source) {
return SimpleByteSource.isCompatible(source);
@@ -164,9 +168,9 @@ public static ByteSource bytes(Object source) throws IllegalArgumentException {
return null;
}
if (!isCompatible(source)) {
- String msg = "Unable to heuristically acquire bytes for object of type [" +
- source.getClass().getName() + "]. If this type is indeed a byte-backed data type, you might " +
- "want to write your own ByteSource implementation to extract its bytes explicitly.";
+ String msg = "Unable to heuristically acquire bytes for object of type ["
+ + source.getClass().getName() + "]. If this type is indeed a byte-backed data type, you might "
+ + "want to write your own ByteSource implementation to extract its bytes explicitly.";
throw new IllegalArgumentException(msg);
}
if (source instanceof byte[]) {
@@ -182,9 +186,9 @@ public static ByteSource bytes(Object source) throws IllegalArgumentException {
} else if (source instanceof InputStream) {
return bytes((InputStream) source);
} else {
- throw new IllegalStateException("Encountered unexpected byte source. This is a bug - please notify " +
- "the Shiro developer list asap (the isCompatible implementation does not reflect this " +
- "method's implementation).");
+ throw new IllegalStateException("Encountered unexpected byte source. This is a bug - please notify "
+ + "the Shiro developer list asap (the isCompatible implementation does not reflect this "
+ + "method's implementation).");
}
}
}
diff --git a/lang/src/main/java/org/apache/shiro/lang/util/ByteSourceWrapper.java b/lang/src/main/java/org/apache/shiro/lang/util/ByteSourceWrapper.java
index 5a0a6c0ba9..bd9270e296 100644
--- a/lang/src/main/java/org/apache/shiro/lang/util/ByteSourceWrapper.java
+++ b/lang/src/main/java/org/apache/shiro/lang/util/ByteSourceWrapper.java
@@ -19,8 +19,6 @@
package org.apache.shiro.lang.util;
-import org.apache.shiro.lang.util.ByteSource;
-
import java.io.Closeable;
import java.io.IOException;
@@ -28,8 +26,8 @@
* To use try-with-resources idiom, this class supports wrapping existing ByteSource
* object or byte array. At end of try block, it gets zeroed out automatically.
*/
-public class ByteSourceWrapper implements Closeable {
- private byte[] bytes;
+public final class ByteSourceWrapper implements Closeable {
+ private final byte[] bytes;
private ByteSourceWrapper(byte[] bytes) {
this.bytes = bytes;
diff --git a/lang/src/main/java/org/apache/shiro/lang/util/ByteUtils.java b/lang/src/main/java/org/apache/shiro/lang/util/ByteUtils.java
index df64f99cca..97bc594c65 100644
--- a/lang/src/main/java/org/apache/shiro/lang/util/ByteUtils.java
+++ b/lang/src/main/java/org/apache/shiro/lang/util/ByteUtils.java
@@ -20,22 +20,23 @@
public final class ByteUtils {
- private ByteUtils() {
- // private utility class
- }
+ private ByteUtils() {
+ // private utility class
+ }
- /**
- * For security, sensitive information in array should be zeroed-out at end of use (SHIRO-349).
- * @param value An array holding sensitive data
- */
- public static void wipe(Object value) {
- if (value instanceof byte[]) {
- byte[] array = (byte[]) value;
- Arrays.fill(array, (byte) 0);
- } else if (value instanceof char[]) {
- char[] array = (char[]) value;
- Arrays.fill(array, '\u0000');
+ /**
+ * For security, sensitive information in array should be zeroed-out at end of use (SHIRO-349).
+ *
+ * @param value An array holding sensitive data
+ */
+ public static void wipe(Object value) {
+ if (value instanceof byte[]) {
+ byte[] array = (byte[]) value;
+ Arrays.fill(array, (byte) 0);
+ } else if (value instanceof char[]) {
+ char[] array = (char[]) value;
+ Arrays.fill(array, '\u0000');
+ }
}
- }
}
diff --git a/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java b/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java
index dfefacf4c2..10d2705e24 100644
--- a/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java
+++ b/lang/src/main/java/org/apache/shiro/lang/util/ClassUtils.java
@@ -36,34 +36,32 @@
*
* @since 0.1
*/
-public class ClassUtils {
-
- //TODO - complete JavaDoc
+public final class ClassUtils {
/**
* Private internal log instance.
*/
- private static final Logger log = LoggerFactory.getLogger(ClassUtils.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtils.class);
/**
* SHIRO-767: add a map to mapping primitive data type
*/
- private static final HashMapnull
if the resource cannot be found from any
- * of the three mentioned ClassLoaders.
+ * of the three mentioned ClassLoaders.
* @since 0.9
*/
public static InputStream getResourceAsStream(String name) {
@@ -111,24 +113,24 @@ public static InputStream getResourceAsStream(String name) {
InputStream is = THREAD_CL_ACCESSOR.getResourceStream(name);
if (is == null) {
- if (log.isTraceEnabled()) {
- log.trace("Resource [" + name + "] was not found via the thread context ClassLoader. Trying the " +
- "current ClassLoader...");
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("Resource [" + name + "] was not found via the thread context ClassLoader. Trying the "
+ + "current ClassLoader...");
}
is = CLASS_CL_ACCESSOR.getResourceStream(name);
}
if (is == null) {
- if (log.isTraceEnabled()) {
- log.trace("Resource [" + name + "] was not found via the current class loader. Trying the " +
- "system/application ClassLoader...");
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("Resource [" + name + "] was not found via the current class loader. Trying the "
+ + "system/application ClassLoader...");
}
is = SYSTEM_CL_ACCESSOR.getResourceStream(name);
}
- if (is == null && log.isTraceEnabled()) {
- log.trace("Resource [" + name + "] was not found via the thread context, current, or " +
- "system/application ClassLoaders. All heuristics have been exhausted. Returning null.");
+ if (is == null && LOGGER.isTraceEnabled()) {
+ LOGGER.trace("Resource [" + name + "] was not found via the thread context, current, or "
+ + "system/application ClassLoaders. All heuristics have been exhausted. Returning null.");
}
return is;
@@ -151,29 +153,29 @@ public static Class forName(String fqcn) throws UnknownClassException {
Class clazz = THREAD_CL_ACCESSOR.loadClass(fqcn);
if (clazz == null) {
- if (log.isTraceEnabled()) {
- log.trace("Unable to load class named [" + fqcn +
- "] from the thread context ClassLoader. Trying the current ClassLoader...");
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("Unable to load class named [" + fqcn
+ + "] from the thread context ClassLoader. Trying the current ClassLoader...");
}
clazz = CLASS_CL_ACCESSOR.loadClass(fqcn);
}
if (clazz == null) {
- if (log.isTraceEnabled()) {
- log.trace("Unable to load class named [" + fqcn + "] from the current ClassLoader. " +
- "Trying the system/application ClassLoader...");
+ if (LOGGER.isTraceEnabled()) {
+ LOGGER.trace("Unable to load class named [" + fqcn + "] from the current ClassLoader. "
+ + "Trying the system/application ClassLoader...");
}
clazz = SYSTEM_CL_ACCESSOR.loadClass(fqcn);
}
if (clazz == null) {
//SHIRO-767: support for getting primitive data type,such as int,double...
- clazz = primClasses.get(fqcn);
+ clazz = PRIM_CLASSES.get(fqcn);
}
if (clazz == null) {
- String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or " +
- "system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.";
+ String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or "
+ + "system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.";
throw new UnknownClassException(msg);
}
@@ -237,7 +239,6 @@ public static Object instantiate(Constructor ctor, Object... args) {
}
/**
- *
* @param type
* @param annotation
* @return
@@ -262,15 +263,16 @@ public static ListSoftHashMap
is a memory-constrained map that stores its values in
* {@link SoftReference SoftReference}s. (Contrast this with the JDK's
- * {@link WeakHashMap WeakHashMap}, which uses weak references for its keys, which is of little value if you
+ * {@link java.util.WeakHashMap WeakHashMap}, which uses weak references for its keys, which is of little value if you
* want the cache to auto-resize itself based on memory constraints).
*
* Having the values wrapped by soft references allows the cache to automatically reduce its size based on memory
@@ -42,6 +49,8 @@
*
* This implementation is thread-safe and usable in concurrent environments.
*
+ * @param true
if the string not null
,
@@ -63,7 +73,7 @@ public class StringUtils {
*
* @param str the String to check (may be null
)
* @return true
if the String is not null
, its length is
- * greater than 0, and it does not contain whitespace only
+ * greater than 0, and it does not contain whitespace only
* @see java.lang.Character#isWhitespace
*/
public static boolean hasText(String str) {
@@ -242,7 +252,7 @@ public static String[] tokenizeToStringArray(String str, String delimiters) {
* (only applies to tokens that are empty after trimming; StringTokenizer
* will not consider subsequent delimiters as token in the first place).
* @return an array of the tokens (null
if the input String
- * was null
)
+ * was null
)
* @see java.util.StringTokenizer
* @see java.lang.String#trim()
*/
@@ -275,7 +285,7 @@ public static String[] tokenizeToStringArray(
*
* @param collection the Collection to copy
* @return the String array (null
if the passed-in
- * Collection was null
)
+ * Collection was null
)
*/
@SuppressWarnings({"unchecked"})
public static String[] toStringArray(Collection collection) {
@@ -295,8 +305,8 @@ public static String[] splitKeyValue(String aLine) throws ParseException {
//fallback to checking for an equals sign
split = line.split("=", 2);
if (split.length != 2) {
- String msg = "Unable to determine Key/Value pair from line [" + line + "]. There is no space from " +
- "which the split location could be determined.";
+ String msg = "Unable to determine Key/Value pair from line [" + line + "]. There is no space from "
+ + "which the split location could be determined.";
throw new ParseException(msg, 0);
}
@@ -326,10 +336,10 @@ public static String[] splitKeyValue(String aLine) throws ParseException {
* Splits a string using the {@link #DEFAULT_DELIMITER_CHAR} (which is {@value #DEFAULT_DELIMITER_CHAR}).
* This method also recognizes quoting using the {@link #DEFAULT_QUOTE_CHAR}
* (which is {@value #DEFAULT_QUOTE_CHAR}), but does not retain them.
- *
+ *
*