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/workflows/codeql.yml b/.github/workflows/codeql.yml index 3e013005c9..52f81d7f2d 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - name: Checkout repository + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 88e7d12cfd..ed008be6cb 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.12.x', '1.11.x', '1.10.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/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. --> - + org.apache.shiro diff --git a/cache/src/main/java/org/apache/shiro/cache/Cache.java b/cache/src/main/java/org/apache/shiro/cache/Cache.java index 2b6f887f29..cea5e03d8c 100644 --- a/cache/src/main/java/org/apache/shiro/cache/Cache.java +++ b/cache/src/main/java/org/apache/shiro/cache/Cache.java @@ -29,6 +29,8 @@ * cache framework's cache instance (e.g. JCache, Ehcache, JCS, OSCache, JBossCache, TerraCotta, Coherence, * GigaSpaces, etc., etc.), allowing a Shiro user to configure any cache mechanism they choose. * + * @param K + * @param V * @since 0.2 */ public interface Cache { @@ -41,7 +43,7 @@ public interface Cache { * @return the cached object or {@code null} if there is no entry for the specified {@code key} * @throws CacheException if there is a problem accessing the underlying cache system */ - public V get(K key) throws CacheException; + V get(K key) throws CacheException; /** * Adds a Cache entry. @@ -51,7 +53,7 @@ public interface Cache { * @return the previous value associated with the given {@code key} or {@code null} if there was previous value * @throws CacheException if there is a problem accessing the underlying cache system */ - public V put(K key, V value) throws CacheException; + V put(K key, V value) throws CacheException; /** * Remove the cache entry corresponding to the specified key. @@ -60,33 +62,33 @@ public interface Cache { * @return the previous value associated with the given {@code key} or {@code null} if there was previous value * @throws CacheException if there is a problem accessing the underlying cache system */ - public V remove(K key) throws CacheException; + V remove(K key) throws CacheException; /** * Clear all entries from the cache. * * @throws CacheException if there is a problem accessing the underlying cache system */ - public void clear() throws CacheException; + void clear() throws CacheException; /** * Returns the number of entries in the cache. * * @return the number of entries in the cache. */ - public int size(); + int size(); /** * Returns a view of all the keys for entries contained in this cache. * * @return a view of all the keys for entries contained in this cache. */ - public Set keys(); + Set keys(); /** * Returns a view of all of the values contained in this cache. * * @return a view of all of the values contained in this cache. */ - public Collection values(); + Collection values(); } diff --git a/cache/src/main/java/org/apache/shiro/cache/CacheException.java b/cache/src/main/java/org/apache/shiro/cache/CacheException.java index e998dfed28..b91cdfa347 100644 --- a/cache/src/main/java/org/apache/shiro/cache/CacheException.java +++ b/cache/src/main/java/org/apache/shiro/cache/CacheException.java @@ -26,8 +26,7 @@ * * @since 0.2 */ -public class CacheException extends ShiroException -{ +public class CacheException extends ShiroException { /** * Creates a new 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 Cache getCache(String name) throws CacheException; + Cache getCache(String name) throws CacheException; } diff --git a/cache/src/main/java/org/apache/shiro/cache/MapCache.java b/cache/src/main/java/org/apache/shiro/cache/MapCache.java index 06dfde9105..23a4e1641a 100644 --- a/cache/src/main/java/org/apache/shiro/cache/MapCache.java +++ b/cache/src/main/java/org/apache/shiro/cache/MapCache.java @@ -27,6 +27,8 @@ * A MapCache is a {@link Cache Cache} implementation that uses a backing {@link Map} instance to store * and retrieve cached data. * + * @param K + * @param V * @since 1.0 */ public class MapCache implements Cache { diff --git a/config/core/pom.xml b/config/core/pom.xml index c41b941265..4f9e031d5d 100644 --- a/config/core/pom.xml +++ b/config/core/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.apache.shiro diff --git a/config/core/src/main/java/org/apache/shiro/config/ConfigurationException.java b/config/core/src/main/java/org/apache/shiro/config/ConfigurationException.java index 2ae352bb95..1fdb5a7bb0 100644 --- a/config/core/src/main/java/org/apache/shiro/config/ConfigurationException.java +++ b/config/core/src/main/java/org/apache/shiro/config/ConfigurationException.java @@ -26,8 +26,7 @@ * * @since 0.9 */ -public class ConfigurationException extends ShiroException -{ +public class ConfigurationException extends ShiroException { /** * Creates a new ConfigurationException. diff --git a/config/core/src/main/java/org/apache/shiro/config/Ini.java b/config/core/src/main/java/org/apache/shiro/config/Ini.java index a42d4a7df4..b854c5e7b4 100644 --- a/config/core/src/main/java/org/apache/shiro/config/Ini.java +++ b/config/core/src/main/java/org/apache/shiro/config/Ini.java @@ -44,19 +44,41 @@ * * @since 1.0 */ -public class Ini implements Map { +@SuppressWarnings({"checkstyle:MethodCount", "checkstyle:CyclomaticComplexity"}) +public final class Ini implements Map { - private static transient final Logger log = LoggerFactory.getLogger(Ini.class); + /** + * empty string means the first unnamed section + */ + public static final String DEFAULT_SECTION_NAME = ""; - public static final String DEFAULT_SECTION_NAME = ""; //empty string means the first unnamed section + /** + * default charset name. + */ public static final String DEFAULT_CHARSET_NAME = "UTF-8"; + /** + * comment pound. + */ public static final String COMMENT_POUND = "#"; + + /** + * comment semicolon. + */ public static final String COMMENT_SEMICOLON = ";"; + + /** + * section prefix + */ public static final String SECTION_PREFIX = "["; + /** + * section suffix + */ public static final String SECTION_SUFFIX = "]"; - protected static final char ESCAPE_TOKEN = '\\'; + private static final char ESCAPE_TOKEN = '\\'; + + private static final Logger LOGGER = LoggerFactory.getLogger(Ini.class); private final Map sections; @@ -88,7 +110,7 @@ public Ini(Ini defaults) { * are all empty, {@code false} otherwise. * * @return {@code true} if no sections have been configured, or if there are sections, but the sections themselves - * are all empty, {@code false} otherwise. + * are all empty, {@code false} otherwise. */ public boolean isEmpty() { Collection
sections = this.sections.values(); @@ -107,7 +129,7 @@ public boolean isEmpty() { * no sections. * * @return the names of all sections managed by this {@code Ini} instance or an empty collection if there are - * no sections. + * no sections. */ public Set getSectionNames() { return Collections.unmodifiableSet(sections.keySet()); @@ -118,7 +140,7 @@ public Set getSectionNames() { * no sections. * * @return the sections managed by this {@code Ini} instance or an empty collection if there are - * no sections. + * no sections. */ public Collection
getSections() { return Collections.unmodifiableCollection(sections.values()); @@ -165,7 +187,7 @@ public Section removeSection(String sectionName) { private static String cleanName(String sectionName) { String name = StringUtils.clean(sectionName); if (name == null) { - log.trace("Specified name was null or empty. Defaulting to the default section (name = \"\")"); + LOGGER.trace("Specified name was null or empty. Defaulting to the default section (name = \"\")"); name = DEFAULT_SECTION_NAME; } return name; @@ -209,7 +231,7 @@ public String getSectionProperty(String sectionName, String propertyName) { * @param propertyName the name of the property to add * @param defaultValue the default value to return if the section or property do not exist. * @return the value of the specified section property, or the {@code defaultValue} if the section or - * property do not exist. + * property do not exist. */ public String getSectionProperty(String sectionName, String propertyName, String defaultValue) { String value = getSectionProperty(sectionName, propertyName); @@ -297,7 +319,7 @@ public void load(Reader reader) { try { scanner.close(); } catch (Exception e) { - log.debug("Unable to cleanly close the InputStream scanner. Non-critical - ignoring.", e); + LOGGER.debug("Unable to cleanly close the InputStream scanner. Non-critical - ignoring.", e); } } } @@ -315,7 +337,7 @@ public void load(Reader reader) { * [section2] * key2 = value2 * - * + *

* To be merged: *

      * [section1]
@@ -324,7 +346,7 @@ public void load(Reader reader) {
      * [section2]
      * key2 = new value
      *  
- * + *

* Result: *

      * [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> entrySet() {
      * An {@code Ini.Section} is String-key-to-String-value Map, identifiable by a
      * {@link #getName() name} unique within an {@link Ini} instance.
      */
-    public static class Section implements Map {
+    public static final class Section implements Map {
         private final String name;
         private final Map props;
 
@@ -518,17 +540,13 @@ private Section(String name, String sectionContent) {
                 throw new NullPointerException("name");
             }
             this.name = name;
-            Map props;
-            if (StringUtils.hasText(sectionContent) ) {
+            Map props;
+            if (StringUtils.hasText(sectionContent)) {
                 props = toMapProps(sectionContent);
             } else {
-                props = new LinkedHashMap();
-            }
-            if ( props != null ) {
-                this.props = props;
-            } else {
-                this.props = new LinkedHashMap();
+                props = new LinkedHashMap<>();
             }
+            this.props = props;
         }
 
         private Section(Section defaults) {
@@ -573,21 +591,21 @@ protected static String[] splitKeyValue(String keyValueLine) {
             StringBuilder keyBuffer = new StringBuilder();
             StringBuilder valueBuffer = new StringBuilder();
 
-            boolean buildingKey = true; //we'll build the value next:
+            //we'll build the value next:
+            boolean buildingKey = true;
 
             for (int i = 0; i < line.length(); i++) {
                 char c = line.charAt(i);
 
                 if (buildingKey) {
-                    if (isKeyValueSeparatorChar(c) && !isCharEscaped(line, i) && !isCharEscaped(line, i-1)) {
-                        buildingKey = false;//now start building the value
-                    } else if (!isCharEscaped(line, i)){
+                    if (isKeyValueSeparatorChar(c) && !isCharEscaped(line, i) && !isCharEscaped(line, i - 1)) {
+                        //now start building the value
+                        buildingKey = false;
+                    } else if (!isCharEscaped(line, i)) {
                         keyBuffer.append(c);
                     }
                 } else {
-                    if (valueBuffer.length() == 0 && isKeyValueSeparatorChar(c) && !isCharEscaped(line, i)) {
-                        //swallow the separator chars before we start building the value
-                    } else {
+                    if (valueBuffer.length() != 0 || !isKeyValueSeparatorChar(c) || isCharEscaped(line, i)) {
                         valueBuffer.append(c);
                     }
                 }
@@ -601,9 +619,9 @@ protected static String[] splitKeyValue(String keyValueLine) {
                 throw new IllegalArgumentException(msg);
             }
 
-            log.trace("Discovered key/value pair: {} = {}", key, value);
+            LOGGER.trace("Discovered key/value pair: {} = {}", key, value);
 
-            return new String[]{key, value};
+            return new String[] {key, value};
         }
 
         private static Map toMapProps(String content) {
diff --git a/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy b/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
index ab1cddf9bd..c913285b82 100644
--- a/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
+++ b/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
@@ -36,8 +36,8 @@ public class IniTest {
     @Test
     public void testNoSections() {
         String test =
-            "prop1 = value1" + NL +
-                    "prop2 = value2";
+                "prop1 = value1" + NL +
+                        "prop2 = value2";
 
         Ini ini = new Ini();
         ini.load(test);
diff --git a/config/ogdl/pom.xml b/config/ogdl/pom.xml
index dceb2065e1..c853df9154 100644
--- a/config/ogdl/pom.xml
+++ b/config/ogdl/pom.xml
@@ -17,7 +17,8 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-
+
 
     
         org.apache.shiro
@@ -29,7 +30,8 @@
     shiro-config-ogdl
     Apache Shiro :: Configuration :: OGDL
     Support for Shiro's Object Graph Definition Language (mostly used in Ini configuration) where
-        declared name/value pairs are interpreted to create an object graph
+        declared name/value pairs are interpreted to create an object graph
+    
     bundle
     
         config.ogdl
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/CommonsInterpolator.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/CommonsInterpolator.java
index bd0c42b267..5b4da74a46 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/CommonsInterpolator.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/CommonsInterpolator.java
@@ -55,7 +55,7 @@
  */
 public class CommonsInterpolator implements Interpolator {
 
-    final private ConfigurationInterpolator interpolator;
+    private final ConfigurationInterpolator interpolator;
 
     public CommonsInterpolator() {
         this.interpolator = new ConfigurationInterpolator();
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/Interpolator.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/Interpolator.java
index 879e61f879..84f517ce97 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/Interpolator.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/Interpolator.java
@@ -28,6 +28,7 @@ public interface Interpolator {
 
     /**
      * Interpolates 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..06950105ec 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 registeredEventSubscribers;
+    private final Map registeredEventSubscribers;
 
     /**
      * @since 1.4
      */
     private final BeanUtilsBean beanUtilsBean;
 
-    //@since 1.3
-    private Map createDefaultObjectMap() {
-        Map map = new LinkedHashMap();
-        map.put(EVENT_BUS_NAME, new DefaultEventBus());
-        return map;
-    }
-
     private Function alternateObjectSupplier = name -> null;
 
     public ReflectionBuilder() {
@@ -133,9 +127,9 @@ public ReflectionBuilder(Map defaults) {
         beanUtilsBean = new BeanUtilsBean(new ConvertUtilsBean() {
             @Override
             public Object convert(String value, Class clazz) {
-                if (clazz.isEnum()){
+                if (clazz.isEnum()) {
                     return Enum.valueOf(clazz, value);
-                }else{
+                } else {
                     return super.convert(value, clazz);
                 }
             }
@@ -146,12 +140,12 @@ public Object convert(String value, Class clazz) {
         this.interpolator = createInterpolator();
 
         this.objects = createDefaultObjectMap();
-        this.registeredEventSubscribers = new LinkedHashMap();
+        this.registeredEventSubscribers = new LinkedHashMap<>();
         apply(defaults);
     }
 
     private void apply(Map objects) {
-        if(!isEmpty(objects)) {
+        if (!isEmpty(objects)) {
             this.objects.putAll(objects);
         }
         EventBus found = findEventBus(this.objects);
@@ -159,6 +153,13 @@ private void apply(Map objects) {
         enableEvents(found);
     }
 
+    //@since 1.3
+    private Map createDefaultObjectMap() {
+        Map map = new LinkedHashMap();
+        map.put(EVENT_BUS_NAME, new DefaultEventBus());
+        return map;
+    }
+
     public Map getObjects() {
         return objects;
     }
@@ -183,7 +184,7 @@ private void enableEvents(EventBus eventBus) {
 
         this.eventBus = eventBus;
 
-        for(Map.Entry entry : this.objects.entrySet()) {
+        for (Map.Entry entry : this.objects.entrySet()) {
             enableEventsIfNecessary(entry.getValue(), entry.getKey());
         }
     }
@@ -213,6 +214,7 @@ private boolean isEventSubscriber(Object bean, String name) {
 
     /**
      * Plug in another way to get objects into configuration, ex: CDI
+     *
      * @param alternateObjectSupplier not null (empty lambda ok)
      * @since 2.0
      */
@@ -221,7 +223,7 @@ public void setAlternateObjectSupplier(Function alternateObjectSuppli
     }
 
     //@since 1.3
-    protected EventBus findEventBus(Map objects) {
+    protected EventBus findEventBus(Map objects) {
 
         if (isEmpty(objects)) {
             return null;
@@ -229,14 +231,14 @@ protected EventBus findEventBus(Map objects) {
 
         //prefer a named object first:
         Object value = objects.get(EVENT_BUS_NAME);
-        if (value != null && value instanceof EventBus) {
-            return (EventBus)value;
+        if (value instanceof EventBus) {
+            return (EventBus) value;
         }
 
         //couldn't find a named 'eventBus' EventBus object.  Try to find the first typed value we can:
-        for( Object v : objects.values()) {
+        for (Object v : objects.values()) {
             if (v instanceof EventBus) {
-                return (EventBus)v;
+                return (EventBus) v;
             }
         }
 
@@ -245,7 +247,7 @@ protected EventBus findEventBus(Map objects) {
 
     private boolean applyEventBusIfNecessary(Object value) {
         if (value instanceof EventBusAware) {
-            ((EventBusAware)value).setEventBus(this.eventBus);
+            ((EventBusAware) value).setEventBus(this.eventBus);
             return true;
         }
         return false;
@@ -294,9 +296,11 @@ private String parseBeanId(String lhs) {
                 String rhs = interpolator.interpolate(entry.getValue());
 
                 String beanId = parseBeanId(lhs);
-                if (beanId != null) { //a beanId could be parsed, so the line is a bean instance definition
+                //a beanId could be parsed, so the line is a bean instance definition
+                if (beanId != null) {
                     processor.add(new InstantiationStatement(beanId, rhs));
-                } else { //the line must be a property configuration
+                    //the line must be a property configuration
+                } else {
                     processor.add(new AssignmentStatement(lhs, rhs));
                 }
             }
@@ -319,19 +323,21 @@ public void destroy() {
         final Map immutableObjects = Collections.unmodifiableMap(objects);
 
         //destroy objects in the opposite order they were initialized:
-        List> entries = new ArrayList>(objects.entrySet());
+        List> entries = new ArrayList>(objects.entrySet());
         Collections.reverse(entries);
 
-        for(Map.Entry entry: entries) {
+        for (Map.Entry entry : entries) {
             String id = entry.getKey();
             Object bean = entry.getValue();
 
             //don't destroy the eventbus until the end - we need it to still be 'alive' while publishing destroy events:
-            if (bean != this.eventBus) { //memory equality check (not .equals) on purpose
+            //memory equality check (not .equals) on purpose
+            if (bean != this.eventBus) {
                 LifecycleUtils.destroy(bean);
                 BeanEvent event = new DestroyedBeanEvent(id, bean, immutableObjects);
                 eventBus.publish(event);
-                this.eventBus.unregister(bean); //bean is now destroyed - it should not receive any other events
+                //bean is now destroyed - it should not receive any other events
+                this.eventBus.unregister(bean);
             }
         }
         //only now destroy the event bus:
@@ -342,11 +348,12 @@ protected void createNewInstance(Map objects, String name, Strin
 
         Object currentInstance = objects.get(name);
         if (currentInstance != null) {
-            log.info("An instance with name '{}' already exists.  " +
-                    "Redefining this object as a new instance of type {}", name, value);
+            LOGGER.info("An instance with name '{}' already exists.  "
+                    + "Redefining this object as a new instance of type {}", name, value);
         }
 
-        Object instance;//name with no property, assume right hand side of equals sign is the class name:
+        //name with no property, assume right hand side of equals sign is the class name:
+        Object instance;
         try {
             instance = ClassUtils.newInstance(value);
             if (instance instanceof Nameable) {
@@ -378,8 +385,8 @@ protected void applyProperty(String key, String value, Map objects) {
             }
 
         } else {
-            throw new IllegalArgumentException("All property keys must contain a '.' character. " +
-                    "(e.g. myBean.property = value)  These should already be separated out by buildObjects().");
+            throw new IllegalArgumentException("All property keys must contain a '.' character. "
+                    + "(e.g. myBean.property = value)  These should already be separated out by buildObjects().");
         }
     }
 
@@ -391,9 +398,9 @@ protected void applyGlobalProperty(Map objects, String property, String value) {
                     applyProperty(instance, property, value);
                 }
             } catch (Exception e) {
-                String msg = "Error retrieving property descriptor for instance " +
-                        "of type [" + instance.getClass().getName() + "] " +
-                        "while setting property [" + property + "]";
+                String msg = "Error retrieving property descriptor for instance "
+                        + "of type [" + instance.getClass().getName() + "] "
+                        + "while setting property [" + property + "]";
                 throw new ConfigurationException(msg, e);
             }
         }
@@ -402,14 +409,14 @@ protected void applyGlobalProperty(Map objects, String property, String value) {
     protected void applySingleProperty(Map objects, String name, String property, String value) {
         Object instance = objects.get(name);
         if (property.equals("class")) {
-            throw new IllegalArgumentException("Property keys should not contain 'class' properties since these " +
-                    "should already be separated out by buildObjects().");
+            throw new IllegalArgumentException("Property keys should not contain 'class' properties since these "
+                    + "should already be separated out by buildObjects().");
 
         } else if (instance == null) {
-            String msg = "Configuration error.  Specified object [" + name + "] with property [" +
-                    property + "] without first defining that object's class.  Please first " +
-                    "specify the class property first, e.g. myObject = fully_qualified_class_name " +
-                    "and then define additional properties.";
+            String msg = "Configuration error.  Specified object [" + name + "] with property ["
+                    + property + "] without first defining that object's class.  Please first "
+                    + "specify the class property first, e.g. myObject = fully_qualified_class_name "
+                    + "and then define additional properties.";
             throw new IllegalArgumentException(msg);
 
         } else {
@@ -428,9 +435,9 @@ protected String getId(String referenceToken) {
     protected Object getReferencedObject(String id) {
         Object o = objects != null && !objects.isEmpty() ? objects.get(id) : null;
         if (o == null) {
-            String msg = "The object with id [" + id + "] has not yet been defined and therefore cannot be " +
-                    "referenced.  Please ensure objects are defined in the order in which they should be " +
-                    "created and made available for future reference.";
+            String msg = "The object with id [" + id + "] has not yet been defined and therefore cannot be "
+                    + "referenced.  Please ensure objects are defined in the order in which they should be "
+                    + "created and made available for future reference.";
             throw new UnresolveableReferenceException(msg);
         }
         return o;
@@ -445,7 +452,7 @@ protected String unescapeIfNecessary(String value) {
 
     protected Object resolveReference(String reference) {
         String id = getId(reference);
-        log.debug("Encountered object reference '{}'.  Looking up object with id '{}'", reference, id);
+        LOGGER.debug("Encountered object reference '{}'.  Looking up object with id '{}'", reference, id);
         final Object referencedObject = getReferencedObject(id);
         if (referencedObject instanceof Factory) {
             return ((Factory) referencedObject).getInstance();
@@ -460,8 +467,8 @@ protected boolean isTypedProperty(Object object, String propertyName, Class claz
         try {
             PropertyDescriptor descriptor = beanUtilsBean.getPropertyUtils().getPropertyDescriptor(object, propertyName);
             if (descriptor == null) {
-                String msg = "Property '" + propertyName + "' does not exist for object of " +
-                        "type " + object.getClass().getName() + ".";
+                String msg = "Property '" + propertyName + "' does not exist for object of "
+                        + "type " + object.getClass().getName() + ".";
                 throw new ConfigurationException(msg);
             }
             Class propertyClazz = descriptor.getPropertyType();
@@ -485,7 +492,7 @@ protected Set toSet(String sValue) {
         if (tokens.length == 1 && isReference(tokens[0])) {
             Object reference = resolveReference(tokens[0]);
             if (reference instanceof Set) {
-                return (Set)reference;
+                return (Set) reference;
             }
         }
 
@@ -511,7 +518,7 @@ protected Set toSet(String sValue) {
         if (tokens.length == 1 && isReference(tokens[0])) {
             Object reference = resolveReference(tokens[0]);
             if (reference instanceof Map) {
-                return (Map)reference;
+                return (Map) reference;
             }
         }
 
@@ -519,9 +526,9 @@ protected Set toSet(String sValue) {
         for (String token : tokens) {
             String[] kvPair = StringUtils.split(token, MAP_KEY_VALUE_DELIMITER);
             if (kvPair == null || kvPair.length != 2) {
-                String msg = "Map property value [" + sValue + "] contained key-value pair token [" +
-                        token + "] that does not properly split to a single key and pair.  This must be the " +
-                        "case for all map entries.";
+                String msg = "Map property value [" + sValue + "] contained key-value pair token ["
+                        + token + "] that does not properly split to a single key and pair.  This must be the "
+                        + "case for all map entries.";
                 throw new ConfigurationException(msg);
             }
             mapTokens.put(kvPair[0], kvPair[1]);
@@ -549,7 +556,7 @@ protected Collection toCollection(String sValue) {
         if (tokens.length == 1 && isReference(tokens[0])) {
             Object reference = resolveReference(tokens[0]);
             if (reference instanceof Collection) {
-                return (Collection)reference;
+                return (Collection) reference;
             }
         }
 
@@ -572,7 +579,7 @@ protected List toList(String sValue) {
         if (tokens.length == 1 && isReference(tokens[0])) {
             Object reference = resolveReference(tokens[0]);
             if (reference instanceof List) {
-                return (List)reference;
+                return (List) reference;
             }
         }
 
@@ -615,11 +622,10 @@ protected String checkForNullOrEmptyLiteral(String stringValue) {
             return null;
         }
         //check if the value is the actual literal string 'null' (expected to be wrapped in quotes):
-        if (stringValue.equals("\"null\"")) {
+        if ("\"null\"".equals(stringValue)) {
             return NULL_VALUE_TOKEN;
-        }
-        //or the actual literal string of two quotes '""' (expected to be wrapped in quotes):
-        else if (stringValue.equals("\"\"\"\"")) {
+            //or the actual literal string of two quotes '""' (expected to be wrapped in quotes):
+        } else if ("\"\"\"\"".equals(stringValue)) {
             return EMPTY_STRING_VALUE_TOKEN;
         } else {
             return stringValue;
@@ -641,11 +647,11 @@ protected void applyProperty(Object object, String propertyPath, Object value) {
             //find the end of the map reference:
             mapEnd = propertyPath.indexOf(MAP_PROPERTY_END_TOKEN, mapBegin);
             //find the token in between the [ and the ] (the map/array key or index):
-            keyString = propertyPath.substring(mapBegin+1, mapEnd);
+            keyString = propertyPath.substring(mapBegin + 1, mapEnd);
 
             //find out if there is more path reference to follow.  If not, we're at a terminal of the OGNL expression
-            if (propertyPath.length() > (mapEnd+1)) {
-                remaining = propertyPath.substring(mapEnd+1);
+            if (propertyPath.length() > (mapEnd + 1)) {
+                remaining = propertyPath.substring(mapEnd + 1);
                 if (remaining.startsWith(".")) {
                     remaining = StringUtils.clean(remaining.substring(1));
                 }
@@ -660,7 +666,7 @@ protected void applyProperty(Object object, String propertyPath, Object value) {
             } else {
                 //we're assigning a map or array entry.  Check to see which we should call:
                 if (isTypedProperty(object, mapPropertyPath, Map.class)) {
-                    Map map = (Map)getProperty(object, mapPropertyPath);
+                    Map map = (Map) getProperty(object, mapPropertyPath);
                     Object mapKey = resolveValue(keyString);
                     //noinspection unchecked
                     map.put(mapKey, value);
@@ -675,7 +681,7 @@ protected void applyProperty(Object object, String propertyPath, Object value) {
             //recursively call this method with the remaining property path
             Object referencedValue = null;
             if (isTypedProperty(object, mapPropertyPath, Map.class)) {
-                Map map = (Map)getProperty(object, mapPropertyPath);
+                Map map = (Map) getProperty(object, mapPropertyPath);
                 Object mapKey = resolveValue(keyString);
                 referencedValue = map.get(mapKey);
             } else {
@@ -685,8 +691,8 @@ protected void applyProperty(Object object, String propertyPath, Object value) {
             }
 
             if (referencedValue == null) {
-                throw new ConfigurationException("Referenced map/array value '" + mapPropertyPath + "[" +
-                keyString + "]' does not exist.");
+                throw new ConfigurationException("Referenced map/array value '" + mapPropertyPath + "["
+                        + keyString + "]' does not exist.");
             }
 
             applyProperty(referencedValue, remaining, value);
@@ -695,18 +701,18 @@ protected void applyProperty(Object object, String propertyPath, Object value) {
 
     private void setProperty(Object object, String propertyPath, Object value) {
         try {
-            if (log.isTraceEnabled()) {
-                log.trace("Applying property [{}] value [{}] on object of type [{}]",
-                        new Object[]{propertyPath, value, object.getClass().getName()});
+            if (LOGGER.isTraceEnabled()) {
+                LOGGER.trace("Applying property [{}] value [{}] on object of type [{}]",
+                        new Object[] {propertyPath, value, object.getClass().getName()});
             }
             beanUtilsBean.setProperty(object, propertyPath, value);
         } catch (Exception e) {
-            String msg = "Unable to set property '" + propertyPath + "' with value [" + value + "] on object " +
-                    "of type " + (object != null ? object.getClass().getName() : null) + ".  If " +
-                    "'" + value + "' is a reference to another (previously defined) object, prefix it with " +
-                    "'" + OBJECT_REFERENCE_BEGIN_TOKEN + "' to indicate that the referenced " +
-                    "object should be used as the actual value.  " +
-                    "For example, " + OBJECT_REFERENCE_BEGIN_TOKEN + value;
+            String msg = "Unable to set property '" + propertyPath + "' with value [" + value + "] on object "
+                    + "of type " + (object != null ? object.getClass().getName() : null) + ".  If "
+                    + "'" + value + "' is a reference to another (previously defined) object, prefix it with "
+                    + "'" + OBJECT_REFERENCE_BEGIN_TOKEN + "' to indicate that the referenced "
+                    + "object should be used as the actual value.  "
+                    + "For example, " + OBJECT_REFERENCE_BEGIN_TOKEN + value;
             throw new ConfigurationException(msg, e);
         }
     }
@@ -782,31 +788,32 @@ private Interpolator createInterpolator() {
 
     /**
      * Sets the {@link Interpolator} used when evaluating the right side of the expressions.
+     *
      * @since 1.4
      */
     public void setInterpolator(Interpolator interpolator) {
         this.interpolator = interpolator;
     }
 
-    private class BeanConfigurationProcessor {
+    private final class BeanConfigurationProcessor {
 
         private final List statements = new ArrayList();
         private final List beanConfigurations = new ArrayList();
 
         public void add(Statement statement) {
-
-            statements.add(statement); //we execute bean configuration statements in the order they are declared.
+            //we execute bean configuration statements in the order they are declared.
+            statements.add(statement);
 
             if (statement instanceof InstantiationStatement) {
-                InstantiationStatement is = (InstantiationStatement)statement;
+                InstantiationStatement is = (InstantiationStatement) statement;
                 beanConfigurations.add(new BeanConfiguration(is));
             } else {
-                AssignmentStatement as = (AssignmentStatement)statement;
+                AssignmentStatement as = (AssignmentStatement) statement;
                 //statements always apply to the most recently defined bean configuration with the same name, so we
                 //have to traverse the configuration list starting at the end (most recent elements are appended):
                 boolean addedToConfig = false;
                 String beanName = as.getRootBeanName();
-                for( int i = beanConfigurations.size()-1; i >= 0; i--) {
+                for (int i = beanConfigurations.size() - 1; i >= 0; i--) {
                     BeanConfiguration mostRecent = beanConfigurations.get(i);
                     String mostRecentBeanName = mostRecent.getBeanName();
                     if (beanName.equals(mostRecentBeanName)) {
@@ -828,17 +835,18 @@ public void add(Statement statement) {
 
         public void execute() {
 
-            for( Statement statement : statements) {
+            for (Statement statement : statements) {
 
                 statement.execute();
 
                 BeanConfiguration bd = statement.getBeanConfiguration();
 
-                if (bd.isExecuted()) { //bean is fully configured, no more statements to execute for it:
+                //bean is fully configured, no more statements to execute for it:
+                if (bd.isExecuted()) {
 
                     //bean configured overrides the 'eventBus' bean - replace the existing eventBus with the one configured:
                     if (bd.getBeanName().equals(EVENT_BUS_NAME)) {
-                        EventBus eventBus = (EventBus)bd.getBean();
+                        EventBus eventBus = (EventBus) bd.getBean();
                         enableEvents(eventBus);
                     }
 
@@ -863,7 +871,7 @@ public void execute() {
         }
     }
 
-    private class BeanConfiguration {
+    private final class BeanConfiguration {
 
         private final InstantiationStatement instantiationStatement;
         private final List assignments = new ArrayList();
@@ -886,7 +894,12 @@ public String getBeanName() {
             return this.beanName;
         }
 
-        public boolean isGlobalConfig() { //BeanConfiguration instance representing the global 'shiro.' properties
+        /**
+         * BeanConfiguration instance representing the global 'shiro.' properties
+         *
+         * @return boolean
+         */
+        public boolean isGlobalConfig() {
             // (we should remove this concept).
             return GLOBAL_PROPERTY_PREFIX.equals(getBeanName());
         }
@@ -912,6 +925,7 @@ public Object getBean() {
 
         /**
          * Returns true if all configuration statements have been executed.
+         *
          * @return true if all configuration statements have been executed.
          */
         public boolean isExecuted() {
@@ -983,7 +997,7 @@ public boolean isExecuted() {
         }
     }
 
-    private class InstantiationStatement extends Statement {
+    private final class InstantiationStatement extends Statement {
 
         private InstantiationStatement(String lhs, String rhs) {
             super(lhs, rhs);
@@ -1008,7 +1022,7 @@ protected Object doExecute() {
         }
     }
 
-    private class AssignmentStatement extends Statement {
+    private final class AssignmentStatement extends Statement {
 
         private final String rootBeanName;
 
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/ConfiguredBeanEvent.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/ConfiguredBeanEvent.java
index 2a196a58e4..619620e6a2 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/ConfiguredBeanEvent.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/ConfiguredBeanEvent.java
@@ -24,11 +24,11 @@
  * Event triggered when a configured bean has been instantiated and fully configured but right before the bean has been
  * initialized.
  *
- * @since 1.3
  * @see InstantiatedBeanEvent
  * @see org.apache.shiro.lang.util.Initializable Initializable
  * @see InitializedBeanEvent
  * @see DestroyedBeanEvent
+ * @since 1.3
  */
 public class ConfiguredBeanEvent extends BeanEvent {
 
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/DestroyedBeanEvent.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/DestroyedBeanEvent.java
index f4924cb68a..090d985bbe 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/DestroyedBeanEvent.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/DestroyedBeanEvent.java
@@ -23,11 +23,11 @@
 /**
  * Event triggered when a configured bean has been destroyed.
  *
- * @since 1.3
  * @see org.apache.shiro.lang.util.Destroyable Destroyable
  * @see InstantiatedBeanEvent
  * @see ConfiguredBeanEvent
  * @see InitializedBeanEvent
+ * @since 1.3
  */
 public class DestroyedBeanEvent extends BeanEvent {
 
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InitializedBeanEvent.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InitializedBeanEvent.java
index 44a8dfc930..98d180ba08 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InitializedBeanEvent.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InitializedBeanEvent.java
@@ -23,11 +23,11 @@
 /**
  * Event triggered when a configured bean has been instantiated, fully configured and initialized.
  *
- * @since 1.3
  * @see org.apache.shiro.lang.util.Initializable Initializable
  * @see InstantiatedBeanEvent
  * @see ConfiguredBeanEvent
  * @see DestroyedBeanEvent
+ * @since 1.3
  */
 public class InitializedBeanEvent extends BeanEvent {
 
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InstantiatedBeanEvent.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InstantiatedBeanEvent.java
index b6eec57088..372bf6162d 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InstantiatedBeanEvent.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/InstantiatedBeanEvent.java
@@ -23,11 +23,11 @@
 /**
  * Event triggered when a configured bean has been instantiated but before it is configured or initialized.
  *
- * @since 1.3
  * @see ConfiguredBeanEvent
  * @see InitializedBeanEvent
  * @see DestroyedBeanEvent
  * @see org.apache.shiro.lang.util.Initializable Initializable
+ * @since 1.3
  */
 public class InstantiatedBeanEvent extends BeanEvent {
 
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/LoggingBeanEventListener.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/LoggingBeanEventListener.java
index 24c709954d..3b9ada4546 100644
--- a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/LoggingBeanEventListener.java
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/LoggingBeanEventListener.java
@@ -29,7 +29,7 @@
  */
 public class LoggingBeanEventListener {
 
-    private static final Logger logger = LoggerFactory.getLogger(LoggingBeanEventListener.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingBeanEventListener.class);
     private static final String SUFFIX = BeanEvent.class.getSimpleName();
 
     @Subscribe
@@ -37,6 +37,6 @@ public void onEvent(BeanEvent e) {
         String className = e.getClass().getSimpleName();
         int i = className.lastIndexOf(SUFFIX);
         String subclassPrefix = i > 0 ? className.substring(0, i) : className;
-        logger.trace("{} bean '{}' [{}]", new Object[]{subclassPrefix, e.getBeanName(), e.getBean()});
+        LOGGER.trace("{} bean '{}' [{}]", subclassPrefix, e.getBeanName(), e.getBean());
     }
 }
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/package-info.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/package-info.java
new file mode 100644
index 0000000000..e7f1312175
--- /dev/null
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/event/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.config.ogdl.event;
diff --git a/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/package-info.java b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/package-info.java
new file mode 100644
index 0000000000..daf21d2eb5
--- /dev/null
+++ b/config/ogdl/src/main/java/org/apache/shiro/config/ogdl/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.config.ogdl;
diff --git a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/CompositeBean.groovy b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/CompositeBean.groovy
index ff4d5bb171..0ae0632afb 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/CompositeBean.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/CompositeBean.groovy
@@ -34,7 +34,7 @@ class CompositeBean {
     Map compositeBeanMap;
     CompositeBean[] compositeBeanArray;
 
-    public CompositeBean(){}
+    public CompositeBean() {}
 
     public CompositeBean(String name) {
         this.name = name
diff --git a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/InitializableBean.groovy b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/InitializableBean.groovy
index 05b35f0899..cc5d8f3d3d 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/InitializableBean.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/InitializableBean.groovy
@@ -28,7 +28,7 @@ class InitializableBean implements Initializable {
 
     private volatile boolean initialized = false;
 
-    public InitializableBean(){}
+    public InitializableBean() {}
 
     public void init() throws ShiroException {
         initialized = true;
diff --git a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/RecordingBeanListener.groovy b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/RecordingBeanListener.groovy
index afb4aa6d5e..b2e8281024 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/RecordingBeanListener.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/RecordingBeanListener.groovy
@@ -32,31 +32,36 @@ public class RecordingBeanListener {
     private List destroyedEvents = new ArrayList();
     private List unhandledEvents = new ArrayList();
 
-    @SuppressWarnings("UnusedDeclaration") //used via reflection
+    @SuppressWarnings("UnusedDeclaration")
+    //used via reflection
     @Subscribe
     public void onUnhandledBeanEvent(BeanEvent beanEvent) {
         this.unhandledEvents.add(beanEvent);
     }
 
-    @SuppressWarnings("UnusedDeclaration") //used via reflection
+    @SuppressWarnings("UnusedDeclaration")
+    //used via reflection
     @Subscribe
     public void onInstantiatedBeanEvent(InstantiatedBeanEvent beanEvent) {
         this.instantiateEvents.add(beanEvent);
     }
 
-    @SuppressWarnings("UnusedDeclaration") //used via reflection
+    @SuppressWarnings("UnusedDeclaration")
+    //used via reflection
     @Subscribe
     public void onConfiguredBeanEvent(ConfiguredBeanEvent beanEvent) {
         this.configuredEvents.add(beanEvent);
     }
 
-    @SuppressWarnings("UnusedDeclaration") //used via reflection
+    @SuppressWarnings("UnusedDeclaration")
+    //used via reflection
     @Subscribe
     public void onInitializedBeanEvent(InitializedBeanEvent beanEvent) {
         this.initializedEvents.add(beanEvent);
     }
 
-    @SuppressWarnings("UnusedDeclaration") //used via reflection
+    @SuppressWarnings("UnusedDeclaration")
+    //used via reflection
     @Subscribe
     public void onDestroyedBeanEvent(DestroyedBeanEvent beanEvent) {
         this.destroyedEvents.add(beanEvent);
diff --git a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/ReflectionBuilderTest.groovy b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/ReflectionBuilderTest.groovy
index 2e8e0ec376..86af2eea35 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/ReflectionBuilderTest.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/ReflectionBuilderTest.groovy
@@ -134,7 +134,7 @@ class ReflectionBuilderTest {
 
     @Test
     void testWithConfiguredNullValue() {
-        Map defaults = new LinkedHashMap();
+        Map defaults = new LinkedHashMap();
         CompositeBean cBean = new CompositeBean();
         cBean.setSimpleBean(new SimpleBean());
         defaults.put("compositeBean", cBean);
@@ -296,7 +296,7 @@ class ReflectionBuilderTest {
         def set = [new SimpleBean('foo'), new SimpleBean('bar')] as Set
 
         def defs = [
-                compositeBean: 'org.apache.shiro.config.ogdl.CompositeBean',
+                compositeBean                : 'org.apache.shiro.config.ogdl.CompositeBean',
                 'compositeBean.simpleBeanSet': '$set'
         ]
 
@@ -337,7 +337,7 @@ class ReflectionBuilderTest {
         List list = [new SimpleBean('foo'), new SimpleBean('bar')] as List
 
         def defs = [
-                compositeBean: 'org.apache.shiro.config.ogdl.CompositeBean',
+                compositeBean                 : 'org.apache.shiro.config.ogdl.CompositeBean',
                 'compositeBean.simpleBeanList': '$list'
         ]
 
@@ -378,7 +378,7 @@ class ReflectionBuilderTest {
         def c = [new SimpleBean('foo'), new SimpleBean('bar')]
 
         def defs = [
-                compositeBean: 'org.apache.shiro.config.ogdl.CompositeBean',
+                compositeBean                       : 'org.apache.shiro.config.ogdl.CompositeBean',
                 'compositeBean.simpleBeanCollection': '$collection'
         ]
 
@@ -391,7 +391,7 @@ class ReflectionBuilderTest {
         assertNotNull(simpleBeans);
         assertSame c, simpleBeans
         assertEquals(2, simpleBeans.size());
-        def i  = simpleBeans.iterator()
+        def i = simpleBeans.iterator()
         assertEquals 'foo', i.next().name
         assertEquals 'bar', i.next().name
     }
@@ -463,7 +463,7 @@ class ReflectionBuilderTest {
         def map = ['foo': new SimpleBean('foo'), 'bar': new SimpleBean('bar')]
 
         def defs = [
-                compositeBean: 'org.apache.shiro.config.ogdl.CompositeBean',
+                compositeBean                : 'org.apache.shiro.config.ogdl.CompositeBean',
                 'compositeBean.simpleBeanMap': '$map'
         ]
 
@@ -718,8 +718,8 @@ class ReflectionBuilderTest {
     }
 
     void checkType(String instanceName, List events, String name, Class expectedType) {
-        for(BeanEvent event: events) {
-            if(event.getBeanName().equals(name)) {
+        for (BeanEvent event : events) {
+            if (event.getBeanName().equals(name)) {
                 assertTrue(
                         expectedType.isInstance(event.getBean()),
                         "Notification for bean " + name + " did not provide an instance of " + expectedType
diff --git a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/SimpleBean.groovy b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/SimpleBean.groovy
index 8fd9b7f346..b15ffb40df 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/SimpleBean.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/SimpleBean.groovy
@@ -26,10 +26,11 @@ class SimpleBean {
     byte[] byteArrayProp;
     List simpleBeans;
     List stringList;
-    Map mapProp = new LinkedHashMap();
+    Map mapProp = new LinkedHashMap();
     SimpleEnum simpleEnum;
 
-    public SimpleBean(){}
+    public SimpleBean() {}
+
     public SimpleBean(String name) {
         this.name = name
     }
diff --git a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/event/BeanEventTest.groovy b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/event/BeanEventTest.groovy
index d784d97dcb..196c86ebf8 100644
--- a/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/event/BeanEventTest.groovy
+++ b/config/ogdl/src/test/groovy/org/apache/shiro/config/ogdl/event/BeanEventTest.groovy
@@ -31,7 +31,7 @@ class BeanEventTest {
     @Test
     void testDefault() {
 
-        def m = [foo: 'bar'] as Map
+        def m = [foo: 'bar'] as Map
         Object o = new Object()
         BeanEvent evt = new MyBeanEvent('baz', o, m)
 
diff --git a/config/pom.xml b/config/pom.xml
index 7b885c4d79..681049c197 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -17,7 +17,8 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-
+
 
     4.0.0
 
diff --git a/core/pom.xml b/core/pom.xml
index a81cbf4712..57c0e5b30d 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -17,7 +17,8 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-
+
 
     
         org.apache.shiro
@@ -36,7 +37,7 @@
     
         
             
-             
+            
                 org.apache.maven.plugins
                 maven-jar-plugin
                 
diff --git a/core/src/main/java/org/apache/shiro/SecurityUtils.java b/core/src/main/java/org/apache/shiro/SecurityUtils.java
index 058ccf4c5c..71ee87a5db 100644
--- a/core/src/main/java/org/apache/shiro/SecurityUtils.java
+++ b/core/src/main/java/org/apache/shiro/SecurityUtils.java
@@ -107,9 +107,8 @@ public static void setSecurityManager(SecurityManager securityManager) {
      * to calling code in an application. If it is not, it is likely due to a Shiro configuration problem.
      *
      * @return the SecurityManager accessible to the calling code.
-     * @throws UnavailableSecurityManagerException
-     *          if there is no {@code SecurityManager} instance available to the
-     *          calling code, which typically indicates an invalid application configuration.
+     * @throws UnavailableSecurityManagerException if there is no {@code SecurityManager} instance available to the
+     *                                             calling code, which typically indicates an invalid application configuration.
      */
     public static SecurityManager getSecurityManager() throws UnavailableSecurityManagerException {
         SecurityManager securityManager = ThreadContext.getSecurityManager();
@@ -117,9 +116,9 @@ public static SecurityManager getSecurityManager() throws UnavailableSecurityMan
             securityManager = SecurityUtils.securityManager;
         }
         if (securityManager == null) {
-            String msg = "No SecurityManager accessible to the calling code, either bound to the " +
-                    ThreadContext.class.getName() + " or as a vm static singleton.  This is an invalid application " +
-                    "configuration.";
+            String msg = "No SecurityManager accessible to the calling code, either bound to the "
+                    + ThreadContext.class.getName() + " or as a vm static singleton.  This is an invalid application "
+                    + "configuration.";
             throw new UnavailableSecurityManagerException(msg);
         }
         return securityManager;
diff --git a/core/src/main/java/org/apache/shiro/aop/AnnotationHandler.java b/core/src/main/java/org/apache/shiro/aop/AnnotationHandler.java
index 706c56e8c3..d1c567674a 100644
--- a/core/src/main/java/org/apache/shiro/aop/AnnotationHandler.java
+++ b/core/src/main/java/org/apache/shiro/aop/AnnotationHandler.java
@@ -49,7 +49,8 @@ public AnnotationHandler(Class annotationClass) {
     /**
      * Returns the {@link org.apache.shiro.subject.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/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 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 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 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 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(Collection listen * attempts. * * @return the {@link AuthenticationListener AuthenticationListener}s that should be notified during authentication - * attempts. + * attempts. */ @SuppressWarnings({"UnusedDeclaration"}) public Collection getAuthenticationListeners() { @@ -191,14 +191,14 @@ public final AuthenticationInfo authenticate(AuthenticationToken token) throws A throw new IllegalArgumentException("Method argument (authentication token) cannot be null."); } - log.trace("Authentication attempt received for token [{}]", token); + LOGGER.trace("Authentication attempt received for token [{}]", token); AuthenticationInfo info; try { info = doAuthenticate(token); if (info == null) { - String msg = "No account information found for authentication token [" + token + "] by this " + - "Authenticator instance. Please check that it is configured correctly."; + String msg = "No account information found for authentication token [" + token + "] by this " + + "Authenticator instance. Please check that it is configured correctly."; throw new AuthenticationException(msg); } } catch (Throwable t) { @@ -209,20 +209,21 @@ public final AuthenticationInfo authenticate(AuthenticationToken token) throws A if (ae == null) { //Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more //severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate: - String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + - "error? (Typical or expected login exceptions should extend from AuthenticationException)."; + String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + + "error? (Typical or expected login exceptions should extend from AuthenticationException)."; ae = new AuthenticationException(msg, t); - if (log.isWarnEnabled()) - log.warn(msg, t); + if (LOGGER.isWarnEnabled()) { + LOGGER.warn(msg, t); + } } try { notifyFailure(token, ae); } catch (Throwable t2) { - if (log.isWarnEnabled()) { - String msg = "Unable to send notification for failed authentication attempt - listener error?. " + - "Please check your AuthenticationListener implementation(s). Logging sending exception " + - "and propagating original AuthenticationException instead..."; - log.warn(msg, t2); + if (LOGGER.isWarnEnabled()) { + String msg = "Unable to send notification for failed authentication attempt - listener error?. " + + "Please check your AuthenticationListener implementation(s). Logging sending exception " + + "and propagating original AuthenticationException instead..."; + LOGGER.warn(msg, t2); } } @@ -230,7 +231,7 @@ public final AuthenticationInfo authenticate(AuthenticationToken token) throws A throw ae; } - log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info); + LOGGER.debug("Authentication successful for token [{}]. Returned account [{}]", token, info); notifySuccess(token, info); @@ -251,7 +252,7 @@ public final AuthenticationInfo authenticate(AuthenticationToken token) throws A * * @param token the authentication token encapsulating the user's login information. * @return an {@code AuthenticationInfo} object encapsulating the user's account information - * important to Shiro. + * important to Shiro. * @throws AuthenticationException if there is a problem logging in the user. */ protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token) diff --git a/core/src/main/java/org/apache/shiro/authc/AuthenticationException.java b/core/src/main/java/org/apache/shiro/authc/AuthenticationException.java index 18ee77062c..6f4f497fee 100644 --- a/core/src/main/java/org/apache/shiro/authc/AuthenticationException.java +++ b/core/src/main/java/org/apache/shiro/authc/AuthenticationException.java @@ -26,8 +26,7 @@ * * @since 0.1 */ -public class AuthenticationException extends ShiroException -{ +public class AuthenticationException extends ShiroException { /** * Creates a new AuthenticationException. diff --git a/core/src/main/java/org/apache/shiro/authc/AuthenticationInfo.java b/core/src/main/java/org/apache/shiro/authc/AuthenticationInfo.java index 3c20f0a0f7..5184c1a5f7 100644 --- a/core/src/main/java/org/apache/shiro/authc/AuthenticationInfo.java +++ b/core/src/main/java/org/apache/shiro/authc/AuthenticationInfo.java @@ -46,8 +46,9 @@ * preferences. *

*

Please note: Since Shiro sometimes logs authentication operations, please ensure your AuthenticationInfo's - * 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 + * 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.

* diff --git a/core/src/main/java/org/apache/shiro/authc/Authenticator.java b/core/src/main/java/org/apache/shiro/authc/Authenticator.java index ca4df4236d..0bcd93bf71 100644 --- a/core/src/main/java/org/apache/shiro/authc/Authenticator.java +++ b/core/src/main/java/org/apache/shiro/authc/Authenticator.java @@ -62,6 +62,6 @@ public interface Authenticator { * @see ConcurrentAccessException * @see UnknownAccountException */ - public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) + AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException; } diff --git a/core/src/main/java/org/apache/shiro/authc/BearerToken.java b/core/src/main/java/org/apache/shiro/authc/BearerToken.java index 51fe909003..2a193e010e 100644 --- a/core/src/main/java/org/apache/shiro/authc/BearerToken.java +++ b/core/src/main/java/org/apache/shiro/authc/BearerToken.java @@ -20,13 +20,13 @@ /** - * A {@link AuthenticationToken} that contains an a Bearer token or API key, typically received via an HTTP {@code Authorization} header. This - * class also implements the {@link org.apache.shiro.authc.HostAuthenticationToken HostAuthenticationToken} interface to retain the host name - * or IP address location from where the authentication attempt is occurring. + * A {@link AuthenticationToken} that contains a Bearer token or API key, typically received via an HTTP + * {@code Authorization} header. This class also implements the + * {@link org.apache.shiro.authc.HostAuthenticationToken HostAuthenticationToken} interface to + * retain the host name or IP address location from where the authentication attempt is occurring. * * @see RFC 2617 * @see OAuth2 Authorization Request Header Field - * * @since 1.5 */ public class BearerToken implements HostAuthenticationToken { diff --git a/core/src/main/java/org/apache/shiro/authc/HostAuthenticationToken.java b/core/src/main/java/org/apache/shiro/authc/HostAuthenticationToken.java index 475b9f70f5..599b318b41 100644 --- a/core/src/main/java/org/apache/shiro/authc/HostAuthenticationToken.java +++ b/core/src/main/java/org/apache/shiro/authc/HostAuthenticationToken.java @@ -36,9 +36,9 @@ public interface HostAuthenticationToken extends AuthenticationToken { * {@code ServletRequest.getRemoteHost()} value. * * @return the fully qualified name of the client from where the - * authentication attempt originates or the String representation - * of the client's IP address is hostname resolution is not - * available or disabled. + * authentication attempt originates or the String representation + * of the client's IP address is hostname resolution is not + * available or disabled. */ String getHost(); } diff --git a/core/src/main/java/org/apache/shiro/authc/LogoutAware.java b/core/src/main/java/org/apache/shiro/authc/LogoutAware.java index d686bfcd3d..30196fa70f 100644 --- a/core/src/main/java/org/apache/shiro/authc/LogoutAware.java +++ b/core/src/main/java/org/apache/shiro/authc/LogoutAware.java @@ -37,5 +37,5 @@ public interface LogoutAware { * * @param principals the identifying principals of the Subject logging out. */ - public void onLogout(PrincipalCollection principals); + void onLogout(PrincipalCollection principals); } diff --git a/core/src/main/java/org/apache/shiro/authc/RememberMeAuthenticationToken.java b/core/src/main/java/org/apache/shiro/authc/RememberMeAuthenticationToken.java index 88da10dd57..28aaff1cdd 100644 --- a/core/src/main/java/org/apache/shiro/authc/RememberMeAuthenticationToken.java +++ b/core/src/main/java/org/apache/shiro/authc/RememberMeAuthenticationToken.java @@ -36,7 +36,7 @@ public interface RememberMeAuthenticationToken extends AuthenticationToken { * across sessions, {@code false} otherwise. * * @return {@code true} if the submitting user wishes their identity (principal(s)) to be remembered - * across sessions, {@code false} otherwise. + * across sessions, {@code false} otherwise. */ boolean isRememberMe(); diff --git a/core/src/main/java/org/apache/shiro/authc/SaltedAuthenticationInfo.java b/core/src/main/java/org/apache/shiro/authc/SaltedAuthenticationInfo.java index f490385c05..003f022645 100644 --- a/core/src/main/java/org/apache/shiro/authc/SaltedAuthenticationInfo.java +++ b/core/src/main/java/org/apache/shiro/authc/SaltedAuthenticationInfo.java @@ -1,48 +1,47 @@ -/* - * 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.authc; - -import org.apache.shiro.lang.util.ByteSource; - -/** - * Interface representing account information that may use a salt when hashing credentials. This interface - * exists primarily to support environments that hash user credentials (e.g. passwords). - *

- * Salts should typically be generated from a secure pseudo-random number generator so they are effectively - * impossible to guess. The salt value should be safely stored along side the account information to ensure - * it is maintained along with the account's credentials. - *

- * This interface exists as a way for Shiro to acquire that salt so it can correctly perform - * {@link org.apache.shiro.authc.credential.CredentialsMatcher credentials matching} during login attempts. - * See the {@link org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher} JavaDoc for - * more information on hashing credentials with salts. - * - * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher - * - * @since 1.1 - */ -public interface SaltedAuthenticationInfo extends AuthenticationInfo { - - /** - * Returns the salt used to salt the account's credentials or {@code null} if no salt was used. - * - * @return the salt used to salt the account's credentials or {@code null} if no salt was used. - */ - ByteSource getCredentialsSalt(); -} +/* + * 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.authc; + +import org.apache.shiro.lang.util.ByteSource; + +/** + * Interface representing account information that may use a salt when hashing credentials. This interface + * exists primarily to support environments that hash user credentials (e.g. passwords). + *

+ * Salts should typically be generated from a secure pseudo-random number generator so they are effectively + * impossible to guess. The salt value should be safely stored along side the account information to ensure + * it is maintained along with the account's credentials. + *

+ * This interface exists as a way for Shiro to acquire that salt so it can correctly perform + * {@link org.apache.shiro.authc.credential.CredentialsMatcher credentials matching} during login attempts. + * See the {@link org.apache.shiro.authc.credential.HashedCredentialsMatcher HashedCredentialsMatcher} JavaDoc for + * more information on hashing credentials with salts. + * + * @see org.apache.shiro.authc.credential.HashedCredentialsMatcher + * @since 1.1 + */ +public interface SaltedAuthenticationInfo extends AuthenticationInfo { + + /** + * Returns the salt used to salt the account's credentials or {@code null} if no salt was used. + * + * @return the salt used to salt the account's credentials or {@code null} if no salt was used. + */ + ByteSource getCredentialsSalt(); +} diff --git a/core/src/main/java/org/apache/shiro/authc/SimpleAccount.java b/core/src/main/java/org/apache/shiro/authc/SimpleAccount.java index e65e07c87f..d173ebd73b 100644 --- a/core/src/main/java/org/apache/shiro/authc/SimpleAccount.java +++ b/core/src/main/java/org/apache/shiro/authc/SimpleAccount.java @@ -81,7 +81,8 @@ public SimpleAccount() { * @param realmName the name of the realm that accesses this account data */ public SimpleAccount(Object principal, Object credentials, String realmName) { - this(principal instanceof PrincipalCollection ? (PrincipalCollection) principal : new SimplePrincipalCollection(principal, realmName), credentials); + this(principal instanceof PrincipalCollection + ? (PrincipalCollection) principal : new SimplePrincipalCollection(principal, realmName), credentials); } /** @@ -96,7 +97,8 @@ public SimpleAccount(Object principal, Object credentials, String realmName) { * @since 1.1 */ public SimpleAccount(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName) { - this(principal instanceof PrincipalCollection ? (PrincipalCollection) principal : new SimplePrincipalCollection(principal, realmName), + this(principal instanceof PrincipalCollection ? (PrincipalCollection) principal + : new SimplePrincipalCollection(principal, realmName), hashedCredentials, credentialsSalt); } @@ -162,7 +164,8 @@ public SimpleAccount(PrincipalCollection principals, Object credentials, Set roleNames, Set permissions) { + public SimpleAccount(Object principal, Object credentials, String realmName, + Set roleNames, Set permissions) { this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principal, realmName), credentials); this.authzInfo = new SimpleAuthorizationInfo(roleNames); this.authzInfo.setObjectPermissions(permissions); @@ -179,7 +182,9 @@ public SimpleAccount(Object principal, Object credentials, String realmName, Set * @param roleNames the names of the roles assigned to this account. * @param permissions the permissions assigned to this account directly (not those assigned to any of the realms). */ - public SimpleAccount(Collection principals, Object credentials, String realmName, Set roleNames, Set permissions) { + + public SimpleAccount(Collection principals, Object credentials, String realmName, + Set roleNames, Set permissions) { this.authcInfo = new SimpleAuthenticationInfo(new SimplePrincipalCollection(principals, realmName), credentials); this.authzInfo = new SimpleAuthorizationInfo(roleNames); this.authzInfo.setObjectPermissions(permissions); @@ -253,7 +258,7 @@ public void setCredentials(Object credentials) { * was used or credentials were not hashed at all. * * @return the salt used to hash this Account's credentials (e.g. for password hashing), or {@code null} if no salt - * was used or credentials were not hashed at all. + * was used or credentials were not hashed at all. * @since 1.1 */ public ByteSource getCredentialsSalt() { @@ -467,7 +472,7 @@ public int hashCode() { * * @param o the object to test for equality. * @return 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 +496,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() { *

(Shiro's default Authenticator allows null hosts to support localhost and proxy server environments).

* * @return the host from where the authentication attempt occurs, or null if it is unknown or - * explicitly omitted. + * explicitly omitted. * @since 1.0 */ public String getHost() { @@ -305,7 +305,7 @@ public void setHost(String host) { * across sessions, false otherwise. Unless overridden, this value is false by default. * * @return true if the submitting user wishes their identity (principal(s)) to be remembered - * across sessions, false otherwise (false by default). + * across sessions, false otherwise (false by default). * @since 0.9 */ public boolean isRememberMe() { @@ -352,7 +352,7 @@ public void clear() { * that might be widely viewable). * * @return the String representation of the UsernamePasswordToken, omitting - * the password. + * the password. */ public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/core/src/main/java/org/apache/shiro/authc/credential/AllowAllCredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/AllowAllCredentialsMatcher.java index f16638fb2b..9984068570 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/AllowAllCredentialsMatcher.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/AllowAllCredentialsMatcher.java @@ -33,8 +33,8 @@ public class AllowAllCredentialsMatcher implements CredentialsMatcher { /** * Returns 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..87c663079c 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").

*

Real World Case Study

* In April 2010, some public Atlassian Jira and Confluence - * installations (Apache Software Foundation, Codehaus, etc) were the target of account attacks and user accounts + * installations (Apache Software Foundation, Codehaus, etc.) were the target of account attacks and user accounts * were compromised. The reason? Jira and Confluence at the time did not salt user passwords and attackers were * able to use dictionary attacks to compromise user accounts (Atlassian has since * @@ -71,7 +71,7 @@ * {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) getSalt(AuthenticationToken)} method. This however * could constitute a security hole since ideally salts should never be obtained based on what a user can submit. * User-submitted salt mechanisms are much more susceptible to dictionary attacks and SHOULD NOT be - * used in secure systems. Instead salts should ideally be a secure randomly-generated number that is generated when + * used in secure systems. Instead, salts should ideally be a secure randomly-generated number that is generated when * the user account is created. The secure number should never be disseminated to the user and always kept private * by the application. *

Shiro 1.1

@@ -136,19 +136,21 @@ public HashedCredentialsMatcher() { this.hashAlgorithm = null; this.hashSalted = false; this.hashIterations = 1; - this.storedCredentialsHexEncoded = true; //false means Base64-encoded + //false means Base64-encoded + this.storedCredentialsHexEncoded = true; } /** * Creates an instance using the specified {@link #getHashAlgorithmName() hashAlgorithmName} to hash submitted * credentials. + * * @param hashAlgorithmName the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} * to use when performing hashes for credentials matching. * @since 1.1 */ public HashedCredentialsMatcher(String hashAlgorithmName) { this(); - if (!StringUtils.hasText(hashAlgorithmName) ) { + if (!StringUtils.hasText(hashAlgorithmName)) { throw new IllegalArgumentException("hashAlgorithmName cannot be null or empty."); } this.hashAlgorithm = hashAlgorithmName; @@ -159,7 +161,7 @@ public HashedCredentialsMatcher(String hashAlgorithmName) { * when performing hashes for credentials matching. * * @return the {@code Hash} {@link org.apache.shiro.crypto.hash.Hash#getAlgorithmName() algorithmName} to use - * when performing hashes for credentials matching. + * when performing hashes for credentials matching. * @since 1.1 */ public String getHashAlgorithmName() { @@ -187,7 +189,7 @@ public void setHashAlgorithmName(String hashAlgorithmName) { * easier. * * @return {@code true} if the system's stored credential hash is Hex encoded, {@code false} if it - * is Base64 encoded. Default is {@code true} + * is Base64 encoded. Default is {@code true} */ public boolean isStoredCredentialsHexEncoded() { return storedCredentialsHexEncoded; @@ -219,19 +221,20 @@ public void setStoredCredentialsHexEncoded(boolean storedCredentialsHexEncoded) * The default value is {@code false}. * * @return {@code true} if a submitted {@code AuthenticationToken}'s credentials should be salted when hashing, - * {@code false} if it should not be salted. + * {@code false} if it should not be salted. * @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo} - * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its - * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method returns a non-null value. - * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return - * {@code SaltedAuthenticationInfo} instances, but it is highly recommended that {@code Realm} implementations - * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} - * instances as soon as possible. - *

- * This is because salts should always be obtained from the stored account information and - * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for - * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user - * are almost impossible to break. This method will be removed in Shiro 2.0. + * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its + * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method + * returns a non-null value. + * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return + * {@code SaltedAuthenticationInfo} instances, but it is highly recommended that {@code Realm} implementations + * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} + * instances as soon as possible. + *

+ * This is because salts should always be obtained from the stored account information and + * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for + * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user + * are almost impossible to break. This method will be removed in Shiro 2.0. */ @Deprecated public boolean isHashSalted() { @@ -239,25 +242,27 @@ public boolean isHashSalted() { } /** - * Sets whether or not to salt a submitted {@code AuthenticationToken}'s credentials when hashing. + * Sets whether to salt a submitted {@code AuthenticationToken}'s credentials when hashing. *

- * If enabled, the salt used will be obtained via the {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) getCredentialsSalt} method. + * If enabled, the salt used will be obtained via the + * {@link #getSalt(org.apache.shiro.authc.AuthenticationToken) getCredentialsSalt} method. *

* The default value is {@code false}. * - * @param hashSalted whether or not to salt a submitted {@code AuthenticationToken}'s credentials when hashing. + * @param hashSalted whether to salt a submitted {@code AuthenticationToken}'s credentials when hashing. * @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo} - * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its - * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method returns a non-null value. - * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return - * {@code SaltedAuthenticationInfo} instances, but it is highly recommended that {@code Realm} implementations - * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} - * instances as soon as possible. - *

- * This is because salts should always be obtained from the stored account information and - * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for - * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user - * are almost impossible to break. This method will be removed in Shiro 2.0. + * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its + * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} + * method returns a non-null value. + * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return + * {@code SaltedAuthenticationInfo} instances, but it is highly recommended that {@code Realm} implementations + * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} + * instances as soon as possible. + *

+ * This is because salts should always be obtained from the stored account information and + * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for + * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user + * are almost impossible to break. This method will be removed in Shiro 2.0. */ @Deprecated public void setHashSalted(boolean hashSalted) { @@ -271,7 +276,7 @@ public void setHashSalted(boolean hashSalted) { * Unless overridden, the default value is {@code 1}, meaning a normal hash execution will occur. * * @return the number of times a submitted {@code AuthenticationToken}'s credentials will be hashed before - * comparing to the credentials stored in the system. + * comparing to the credentials stored in the system. */ public int getHashIterations() { return hashIterations; @@ -300,22 +305,23 @@ public void setHashIterations(int hashIterations) { * Returns a salt value used to hash the token's credentials. *

* This default implementation merely returns {@code token.getPrincipal()}, effectively using the user's - * identity (username, user id, etc) as the salt, a most common technique. If you wish to provide the + * identity (username, user id, etc.) as the salt, a most common technique. If you wish to provide the * authentication token's salt another way, you may override this method. * * @param token the AuthenticationToken submitted during the authentication attempt. * @return a salt value to use to hash the authentication token's credentials. * @deprecated since Shiro 1.1. Hash salting is now expected to be based on if the {@link AuthenticationInfo} - * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its - * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method returns a non-null value. - * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return - * {@code SaltedAuthenticationInfo} instances, but it is highly recommended that {@code Realm} implementations - * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} - * instances as soon as possible.

- * This is because salts should always be obtained from the stored account information and - * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for - * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user - * are almost impossible to break. This method will be removed in Shiro 2.0. + * returned from the {@code Realm} is a {@link SaltedAuthenticationInfo} instance and its + * {@link org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt() getCredentialsSalt()} method + * returns a non-null value. + * This method and the 1.0 behavior still exists for backwards compatibility if the {@code Realm} does not return + * {@code SaltedAuthenticationInfo} instances, but it is highly recommended that {@code Realm} implementations + * that support hashed credentials start returning {@link SaltedAuthenticationInfo SaltedAuthenticationInfo} + * instances as soon as possible.

+ * This is because salts should always be obtained from the stored account information and + * never be interpreted based on user/Subject-entered data. User-entered data is easier to compromise for + * attackers, whereas account-unique (and secure randomly-generated) salts never disseminated to the end-user + * are almost impossible to break. This method will be removed in Shiro 2.0. */ @Deprecated protected Object getSalt(AuthenticationToken token) { @@ -372,7 +378,7 @@ protected Object getCredentials(AuthenticationInfo info) { * @param token the {@code AuthenticationToken} submitted during the authentication attempt. * @param info the {@code AuthenticationInfo} stored in the system matching the token principal * @return {@code true} if the provided token credentials hash match to the stored account credentials hash, - * {@code false} otherwise + * {@code false} otherwise * @since 1.1 */ @Override @@ -424,8 +430,8 @@ protected Object hashProvidedCredentials(AuthenticationToken token, Authenticati private String assertHashAlgorithmName() throws IllegalStateException { String hashAlgorithmName = getHashAlgorithmName(); if (hashAlgorithmName == null) { - String msg = "Required 'hashAlgorithmName' property has not been set. This is required to execute " + - "the hashing algorithm."; + String msg = "Required 'hashAlgorithmName' property has not been set. This is required to execute " + + "the hashing algorithm."; throw new IllegalStateException(msg); } return hashAlgorithmName; @@ -449,7 +455,8 @@ protected Hash hashProvidedCredentials(Object credentials, Object salt, int hash /** * Returns a new, uninitialized instance, without its byte array set. Used as a utility method in the - * {@link SimpleCredentialsMatcher#getCredentials(org.apache.shiro.authc.AuthenticationInfo) getCredentials(AuthenticationInfo)} implementation. + * {@link SimpleCredentialsMatcher#getCredentials(org.apache.shiro.authc.AuthenticationInfo) + * getCredentials(AuthenticationInfo)} implementation. * * @return a new, uninitialized instance, without its byte array set. */ diff --git a/core/src/main/java/org/apache/shiro/authc/credential/HashingPasswordService.java b/core/src/main/java/org/apache/shiro/authc/credential/HashingPasswordService.java index bdde4f90dc..f333aee8b8 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/HashingPasswordService.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/HashingPasswordService.java @@ -79,13 +79,13 @@ public interface HashingPasswordService extends PasswordService { * as they can be cleared/nulled-out after use. Any argument type supported by * {@link ByteSource.Util#isCompatible(Object)} is valid. * - * @param plaintext a raw/plaintext password submitted by an end user/Subject. - * @param savedPasswordHash the previously hashed password known to be associated with an account. - * This value is expected to have been previously generated from the - * {@link #hashPassword(Object) hashPassword} method (typically - * when the account is created or the account's password is reset). + * @param plaintext a raw/plaintext password submitted by an end user/Subject. + * @param savedPasswordHash the previously hashed password known to be associated with an account. + * This value is expected to have been previously generated from the + * {@link #hashPassword(Object) hashPassword} method (typically + * when the account is created or the account's password is reset). * @return {@code true} if the {@code plaintext} password matches the existing {@code savedPasswordHash}, - * {@code false} otherwise. + * {@code false} otherwise. */ boolean passwordsMatch(Object plaintext, Hash savedPasswordHash); } diff --git a/core/src/main/java/org/apache/shiro/authc/credential/PasswordMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/PasswordMatcher.java index dd60a850b4..240fc0eac8 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/PasswordMatcher.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/PasswordMatcher.java @@ -50,11 +50,11 @@ public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo assertStoredCredentialsType(storedCredentials); if (storedCredentials instanceof Hash) { - Hash hashedPassword = (Hash)storedCredentials; + Hash hashedPassword = (Hash) storedCredentials; return hashedPassword.matchesPassword(ByteSource.Util.bytes(submittedPassword)); } //otherwise they are a String (asserted in the 'assertStoredCredentialsType' method call above): - String formatted = (String)storedCredentials; + String formatted = (String) storedCredentials; return service.passwordsMatch(submittedPassword, formatted); } @@ -76,8 +76,8 @@ private void assertStoredCredentialsType(Object credentials) { return; } - String msg = "Stored account credentials are expected to be either a " + - Hash.class.getName() + " instance or a formatted hash String."; + String msg = "Stored account credentials are expected to be either a " + + Hash.class.getName() + " instance or a formatted hash String."; throw new IllegalArgumentException(msg); } @@ -85,7 +85,7 @@ protected Object getStoredPassword(AuthenticationInfo storedAccountInfo) { Object stored = storedAccountInfo != null ? storedAccountInfo.getCredentials() : null; //fix for https://issues.apache.org/jira/browse/SHIRO-363 if (stored instanceof char[]) { - stored = new String((char[])stored); + stored = new String((char[]) stored); } return stored; } diff --git a/core/src/main/java/org/apache/shiro/authc/credential/PasswordService.java b/core/src/main/java/org/apache/shiro/authc/credential/PasswordService.java index 60cc9b79ec..6cc125a4d1 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/PasswordService.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/PasswordService.java @@ -140,7 +140,7 @@ public interface PasswordService { * {@link #encryptPassword(Object) encryptPassword} method (typically * when the account is created or the account's password is reset). * @return {@code true} if the {@code submittedPlaintext} password matches the existing {@code saved} password, - * {@code false} otherwise. + * {@code false} otherwise. * @see ByteSource.Util#isCompatible(Object) */ boolean passwordsMatch(Object submittedPlaintext, String encrypted); diff --git a/core/src/main/java/org/apache/shiro/authc/credential/Sha256CredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/Sha256CredentialsMatcher.java index be84edc955..76bd73765a 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/Sha256CredentialsMatcher.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/Sha256CredentialsMatcher.java @@ -18,8 +18,6 @@ */ package org.apache.shiro.authc.credential; -import org.apache.shiro.crypto.hash.AbstractHash; -import org.apache.shiro.crypto.hash.Hash; import org.apache.shiro.crypto.hash.Sha256Hash; @@ -29,7 +27,7 @@ * * @since 0.9 * @deprecated since 1.1 - use the HashedCredentialsMatcher directly and set its - * {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property. + * {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property. */ public class Sha256CredentialsMatcher extends HashedCredentialsMatcher { diff --git a/core/src/main/java/org/apache/shiro/authc/credential/Sha384CredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/Sha384CredentialsMatcher.java index ec4757853a..8b736a16eb 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/Sha384CredentialsMatcher.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/Sha384CredentialsMatcher.java @@ -18,8 +18,6 @@ */ package org.apache.shiro.authc.credential; -import org.apache.shiro.crypto.hash.AbstractHash; -import org.apache.shiro.crypto.hash.Hash; import org.apache.shiro.crypto.hash.Sha384Hash; @@ -29,7 +27,7 @@ * * @since 0.9 * @deprecated since 1.1 - use the HashedCredentialsMatcher directly and set its - * {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property. + * {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property. */ public class Sha384CredentialsMatcher extends HashedCredentialsMatcher { diff --git a/core/src/main/java/org/apache/shiro/authc/credential/Sha512CredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/Sha512CredentialsMatcher.java index 5989b23d24..797317ef70 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/Sha512CredentialsMatcher.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/Sha512CredentialsMatcher.java @@ -18,8 +18,6 @@ */ package org.apache.shiro.authc.credential; -import org.apache.shiro.crypto.hash.AbstractHash; -import org.apache.shiro.crypto.hash.Hash; import org.apache.shiro.crypto.hash.Sha512Hash; @@ -29,7 +27,7 @@ * * @since 0.9 * @deprecated since 1.1 - use the HashedCredentialsMatcher directly and set its - * {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property. + * {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property. */ public class Sha512CredentialsMatcher extends HashedCredentialsMatcher { diff --git a/core/src/main/java/org/apache/shiro/authc/credential/SimpleCredentialsMatcher.java b/core/src/main/java/org/apache/shiro/authc/credential/SimpleCredentialsMatcher.java index c8132c990d..b3a09ab5bf 100644 --- a/core/src/main/java/org/apache/shiro/authc/credential/SimpleCredentialsMatcher.java +++ b/core/src/main/java/org/apache/shiro/authc/credential/SimpleCredentialsMatcher.java @@ -41,7 +41,7 @@ */ public class SimpleCredentialsMatcher extends CodecSupport implements CredentialsMatcher { - private static final Logger log = LoggerFactory.getLogger(SimpleCredentialsMatcher.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleCredentialsMatcher.class); /** * Returns the {@code token}'s credentials. @@ -92,15 +92,15 @@ protected Object getCredentials(AuthenticationInfo info) { * @return {@code true} if the {@code tokenCredentials} are equal to the {@code accountCredentials}. */ protected boolean equals(Object tokenCredentials, Object accountCredentials) { - if (log.isDebugEnabled()) { - log.debug("Performing credentials equality check for tokenCredentials of type [" + - tokenCredentials.getClass().getName() + " and accountCredentials of type [" + - accountCredentials.getClass().getName() + "]"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Performing credentials equality check for tokenCredentials of type [" + + tokenCredentials.getClass().getName() + " and accountCredentials of type [" + + accountCredentials.getClass().getName() + "]"); } if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) { - if (log.isDebugEnabled()) { - log.debug("Both credentials arguments can be easily converted to byte arrays. Performing " + - "array equals comparison"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Both credentials arguments can be easily converted to byte arrays. Performing " + + "array equals comparison"); } byte[] tokenBytes = toBytes(tokenCredentials); byte[] accountBytes = toBytes(accountCredentials); @@ -115,13 +115,13 @@ protected boolean equals(Object tokenCredentials, Object accountCredentials) { * (via {@link #getCredentials(AuthenticationToken) getCredentials(token)}) * and then the {@code account}'s credentials * (via {@link #getCredentials(org.apache.shiro.authc.AuthenticationInfo) getCredentials(account)}) and then passes both of - * them to the {@link #equals(Object,Object) equals(tokenCredentials, accountCredentials)} method for equality + * them to the {@link #equals(Object, Object) equals(tokenCredentials, accountCredentials)} method for equality * comparison. * * @param token the {@code AuthenticationToken} submitted during the authentication attempt. * @param info the {@code AuthenticationInfo} stored in the system matching the token principal. * @return {@code true} if the provided token credentials are equal to the stored account credentials, - * {@code false} otherwise + * {@code false} otherwise */ public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { Object tokenCredentials = getCredentials(token); diff --git a/core/src/main/java/org/apache/shiro/authc/pam/AbstractAuthenticationStrategy.java b/core/src/main/java/org/apache/shiro/authc/pam/AbstractAuthenticationStrategy.java index 55b7a20522..718578f954 100644 --- a/core/src/main/java/org/apache/shiro/authc/pam/AbstractAuthenticationStrategy.java +++ b/core/src/main/java/org/apache/shiro/authc/pam/AbstractAuthenticationStrategy.java @@ -18,7 +18,11 @@ */ package org.apache.shiro.authc.pam; -import org.apache.shiro.authc.*; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.MergableAuthenticationInfo; +import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.realm.Realm; import java.util.Collection; @@ -33,17 +37,20 @@ public abstract class AbstractAuthenticationStrategy implements AuthenticationStrategy { /** - * Simply returns new {@link org.apache.shiro.authc.SimpleAuthenticationInfo SimpleAuthenticationInfo}();, which supports + * Simply returns new {@link org.apache.shiro.authc.SimpleAuthenticationInfo SimpleAuthenticationInfo}();, + * which supports * aggregating account data across realms. */ - public AuthenticationInfo beforeAllAttempts(Collection realms, AuthenticationToken token) throws AuthenticationException { + public AuthenticationInfo beforeAllAttempts(Collection realms, AuthenticationToken token) + throws AuthenticationException { return new SimpleAuthenticationInfo(); } /** * Simply returns the aggregate method argument, without modification. */ - public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException { + public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) + throws AuthenticationException { return aggregate; } @@ -51,7 +58,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,19 +87,20 @@ 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."); } } /** * Simply returns the aggregate argument without modification. Can be overridden for custom behavior. */ - public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException { + public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) + throws AuthenticationException { return aggregate; } } 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..8d200a85dc 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,22 +40,26 @@ */ 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); /** * 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 + * Realm {@link org.apache.shiro.realm.Realm#supports(org.apache.shiro.authc.AuthenticationToken) supports} + * the given * token argument. If it does not, this method throws an * {@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,28 +76,29 @@ public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, * realm did in fact authenticate successfully * */ - public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo info, AuthenticationInfo aggregate, Throwable t) + public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, + AuthenticationInfo info, AuthenticationInfo aggregate, Throwable t) throws AuthenticationException { if (t != null) { if (t instanceof AuthenticationException) { //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..c1928d583c 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. */ - public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException { + 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..0231b6212b 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,7 +56,8 @@ 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. */ - AuthenticationInfo beforeAllAttempts(Collection realms, AuthenticationToken token) throws AuthenticationException; + AuthenticationInfo beforeAllAttempts(Collection realms, AuthenticationToken token) + throws AuthenticationException; /** * Method invoked by the ModularAuthenticator just prior to the realm being consulted for account data, @@ -70,12 +71,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. + * 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. + * 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; + AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) + throws AuthenticationException; /** * Method invoked by the ModularAuthenticator just after the given realm has been consulted for authentication, @@ -89,13 +91,16 @@ public interface AuthenticationStrategy { * @param token the {@code AuthenticationToken} submitted for the subject attempting system log-in. * @param singleRealmInfo the info returned from a single realm. * @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. + * @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; /** @@ -103,7 +108,8 @@ AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, Authenti * for account data, allowing post-processing after all realms have completed. * *

Returns the final AuthenticationInfo object that will be returned from the Authenticator to the authenticate() caller. - * This is most likely the aggregate AuthenticationInfo object that has been populated by many realms, but the actual return value is + * This is most likely the aggregate AuthenticationInfo object that has been populated by many realms, + * but the actual return value is * always up to the implementation. * * @param token the {@code AuthenticationToken} submitted for the subject attempting system log-in. 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..2845edf30d 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,39 +39,37 @@ 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. */ - public AuthenticationInfo beforeAllAttempts(Collection realms, AuthenticationToken token) throws AuthenticationException { + public AuthenticationInfo beforeAllAttempts(Collection realms, AuthenticationToken token) + throws AuthenticationException { return null; } - /** - * 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. */ - public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException { + public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) + throws AuthenticationException { if (getStopAfterFirstSuccess() && aggregate != null && !isEmpty(aggregate.getPrincipals())) { throw new ShortCircuitIterationException(); } 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 { Collection realms = getRealms(); if (CollectionUtils.isEmpty(realms)) { - String msg = "Configuration error: No realms have been configured! One or more realms must be " + - "present to execute an authentication attempt."; + String msg = "Configuration error: No realms have been configured! One or more realms must be " + + "present to execute an authentication attempt."; throw new IllegalStateException(msg); } } @@ -172,15 +174,15 @@ protected void assertRealmsConfigured() throws IllegalStateException { */ protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { if (!realm.supports(token)) { - String msg = "Realm [" + realm + "] does not support authentication token [" + - token + "]. Please ensure that the appropriate Realm implementation is " + - "configured correctly or that the realm accepts AuthenticationTokens of this type."; + String msg = "Realm [" + realm + "] does not support authentication token [" + + token + "]. Please ensure that the appropriate Realm implementation is " + + "configured correctly or that the realm accepts AuthenticationTokens of this type."; throw new UnsupportedTokenException(msg); } AuthenticationInfo info = realm.getAuthenticationInfo(token); if (info == null) { - String msg = "Realm [" + realm + "] was unable to find account data for the " + - "submitted AuthenticationToken [" + token + "]."; + String msg = "Realm [" + realm + "] was unable to find account data for the " + + "submitted AuthenticationToken [" + token + "]."; throw new UnknownAccountException(msg); } return info; @@ -193,7 +195,7 @@ protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, Authentica * @param realms the multiple realms configured on this Authenticator instance. * @param token the submitted AuthenticationToken representing the subject's (user's) log-in principals and credentials. * @return an aggregated AuthenticationInfo instance representing account data across all the successfully - * consulted realms. + * consulted realms. */ protected AuthenticationInfo doMultiRealmAuthentication(Collection realms, AuthenticationToken token) { @@ -201,8 +203,8 @@ protected AuthenticationInfo doMultiRealmAuthentication(Collection realms AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token); - if (log.isTraceEnabled()) { - log.trace("Iterating through {} realms for PAM authentication", realms.size()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Iterating through {} realms for PAM authentication", realms.size()); } for (Realm realm : realms) { @@ -210,14 +212,14 @@ protected AuthenticationInfo doMultiRealmAuthentication(Collection realms try { aggregate = strategy.beforeAttempt(realm, token, aggregate); } catch (ShortCircuitIterationException shortCircuitSignal) { - // Break from continuing with subsequent realms on receiving + // Break from continuing with subsequent realms on receiving // short circuit signal from strategy break; } if (realm.supports(token)) { - log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm); + LOGGER.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm); AuthenticationInfo info = null; Throwable t = null; @@ -225,16 +227,16 @@ protected AuthenticationInfo doMultiRealmAuthentication(Collection realms info = realm.getAuthenticationInfo(token); } catch (Throwable throwable) { t = throwable; - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:"; - log.debug(msg, t); + LOGGER.debug(msg, t); } } aggregate = strategy.afterAttempt(realm, token, info, aggregate, t); } else { - log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token); + LOGGER.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token); } } diff --git a/core/src/main/java/org/apache/shiro/authc/pam/ShortCircuitIterationException.java b/core/src/main/java/org/apache/shiro/authc/pam/ShortCircuitIterationException.java index 0522b24bdf..4f9d6fa948 100644 --- a/core/src/main/java/org/apache/shiro/authc/pam/ShortCircuitIterationException.java +++ b/core/src/main/java/org/apache/shiro/authc/pam/ShortCircuitIterationException.java @@ -20,13 +20,12 @@ import org.apache.shiro.authc.AuthenticationException; - /** * Exception thrown during the authentication process using - * {@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 + * {@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..9245dc3366 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 permissions); @@ -122,7 +122,7 @@ public interface Authorizer { * @param subjectPrincipal the application-specific subject/user identifier. * @param permissions the String representations of the Permissions that are being checked. * @return true if the user has all of the specified permissions, false otherwise. - * @see #isPermittedAll(PrincipalCollection,Collection) + * @see #isPermittedAll(PrincipalCollection, Collection) * @since 0.9 */ boolean isPermittedAll(PrincipalCollection subjectPrincipal, String... permissions); @@ -151,8 +151,7 @@ public interface Authorizer { * * @param subjectPrincipal the application-specific subject/user identifier. * @param permission the String representation of the Permission to check. - * @throws AuthorizationException - * if the user does not have the permission. + * @throws AuthorizationException if the user does not have the permission. * @since 0.9 */ void checkPermission(PrincipalCollection subjectPrincipal, String permission) throws AuthorizationException; @@ -164,8 +163,7 @@ public interface Authorizer { * * @param subjectPrincipal the application-specific subject/user identifier. * @param permission the Permission to check. - * @throws AuthorizationException - * if the user does not have the permission. + * @throws AuthorizationException if the user does not have the permission. */ void checkPermission(PrincipalCollection subjectPrincipal, Permission permission) throws AuthorizationException; @@ -173,7 +171,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. @@ -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 roleIdentifiers); @@ -242,8 +240,7 @@ public interface Authorizer { * * @param subjectPrincipal the application-specific subject/user identifier. * @param roleIdentifier the application-specific role identifier (usually a role id or role name ). - * @throws AuthorizationException - * if the user does not have the role. + * @throws AuthorizationException if the user does not have the role. */ void checkRole(PrincipalCollection subjectPrincipal, String roleIdentifier) throws AuthorizationException; @@ -253,26 +250,22 @@ 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). - * @throws AuthorizationException - * if the user does not have all of the specified roles. + * @throws AuthorizationException if the user does not have all of the specified roles. */ void checkRoles(PrincipalCollection subjectPrincipal, Collection roleIdentifiers) throws AuthorizationException; /** * Same as {@link #checkRoles(org.apache.shiro.subject.PrincipalCollection, java.util.Collection) - * checkRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers)} but doesn't require a collection - * as an argument. - * Asserts the corresponding Subject/user has all of the specified roles by returning quietly if they do or + * checkRoles(PrincipalCollection subjectPrincipal, + * Collection<String> roleIdentifiers)} but doesn't require a collection as an argument. + * Asserts the corresponding Subject/user has all the specified roles by returning quietly if they do or * throwing an {@link AuthorizationException} if they do not. * * @param subjectPrincipal the application-specific subject/user identifier. * @param roleIdentifiers the application-specific role identifiers to check (usually role ids or role names). - * @throws AuthorizationException - * if the user does not have all of the specified roles. - * - * @since 1.1.0 + * @throws AuthorizationException if the user does not have all the specified roles. + * @since 1.1.0 */ void checkRoles(PrincipalCollection subjectPrincipal, String... roleIdentifiers) throws AuthorizationException; - -} +} diff --git a/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java b/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java index 4a120246b5..a038a230ba 100644 --- a/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java +++ b/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java @@ -95,7 +95,7 @@ public void setRealms(Collection realms) { * if all realm instances will each configure their own permission resolver. * * @return the PermissionResolver to be used on all configured realms, or nullPermissionResolver interface. If you do not want this to occur, the realms must * configure themselves individually (or be configured individually). * - * @param permissionResolver the permissionResolver to set on all of the wrapped realms that implement the - * {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} interface. + * @param permissionResolver the permissionResolver to set on all the wrapped realms that implement the + * {@link org.apache.shiro.authz.permission.PermissionResolverAware PermissionResolverAware} + * interface. */ public void setPermissionResolver(PermissionResolver permissionResolver) { this.permissionResolver = permissionResolver; @@ -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,7 +149,7 @@ 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 nullRolePermissionResolver interface. If you do not want this to occur, the realms must * configure themselves individually (or be configured individually). * - * @param rolePermissionResolver the rolePermissionResolver to set on all of the wrapped realms that implement the - * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} interface. + * @param rolePermissionResolver the rolePermissionResolver to set on all the wrapped realms that implement the + * {@link org.apache.shiro.authz.permission.RolePermissionResolverAware RolePermissionResolverAware} + * interface. */ public void setRolePermissionResolver(RolePermissionResolver rolePermissionResolver) { this.rolePermissionResolver = rolePermissionResolver; @@ -173,10 +176,12 @@ 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. + * {@link #setRolePermissionResolver(org.apache.shiro.authz.permission.RolePermissionResolver) setRolePermissionResolver} + * method. *

* It is also called after setting one or more realms via the {@link #setRealms setRealms} method to allow these * newly available realms to be given the RolePermissionResolver already in use. @@ -205,8 +210,8 @@ protected void applyRolePermissionResolverToRealms() { protected void assertRealmsConfigured() throws IllegalStateException { Collection realms = getRealms(); if (realms == null || realms.isEmpty()) { - String msg = "Configuration error: No realms have been configured! One or more realms must be " + - "present to execute an authorization operation."; + String msg = "Configuration error: No realms have been configured! One or more realms must be " + + "present to execute an authorization operation."; throw new IllegalStateException(msg); } } @@ -219,7 +224,9 @@ protected void assertRealmsConfigured() throws IllegalStateException { public boolean isPermitted(PrincipalCollection principals, String permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { - if (!(realm instanceof Authorizer)) continue; + if (!(realm instanceof Authorizer)) { + continue; + } if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } @@ -235,7 +242,9 @@ public boolean isPermitted(PrincipalCollection principals, String permission) { public boolean isPermitted(PrincipalCollection principals, Permission permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { - if (!(realm instanceof Authorizer)) continue; + if (!(realm instanceof Authorizer)) { + continue; + } if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } @@ -353,7 +362,8 @@ public void checkPermissions(PrincipalCollection principals, String... permissio * all the given Permissions, throws * an UnauthorizedException otherwise returns quietly. */ - public void checkPermissions(PrincipalCollection principals, Collection permissions) throws AuthorizationException { + public void checkPermissions(PrincipalCollection principals, Collection permissions) + throws AuthorizationException { assertRealmsConfigured(); if (permissions != null) { for (Permission permission : permissions) { @@ -370,7 +380,9 @@ public void checkPermissions(PrincipalCollection principals, Collection roles) throws AuthorizationException { //SHIRO-234 - roles.toArray() -> roles.toArray(new String[roles.size()]) - if (roles != null && !roles.isEmpty()) checkRoles(principals, roles.toArray(new String[roles.size()])); + if (roles != null && !roles.isEmpty()) { + checkRoles(principals, roles.toArray(new String[roles.size()])); + } } /** diff --git a/core/src/main/java/org/apache/shiro/authz/Permission.java b/core/src/main/java/org/apache/shiro/authz/Permission.java index 23c42c775a..eb680fc340 100644 --- a/core/src/main/java/org/apache/shiro/authz/Permission.java +++ b/core/src/main/java/org/apache/shiro/authz/Permission.java @@ -79,7 +79,7 @@ public interface Permission { * * @param p the permission to check for behavior/functionality comparison. * @return {@code true} if this current instance implies all the functionality and/or resource access - * described by the specified {@code Permission} argument, {@code false} otherwise. + * described by the specified {@code Permission} argument, {@code false} otherwise. */ boolean implies(Permission p); } diff --git a/core/src/main/java/org/apache/shiro/authz/SimpleAuthorizationInfo.java b/core/src/main/java/org/apache/shiro/authz/SimpleAuthorizationInfo.java index 70ebef972f..6fe99ff554 100644 --- a/core/src/main/java/org/apache/shiro/authz/SimpleAuthorizationInfo.java +++ b/core/src/main/java/org/apache/shiro/authz/SimpleAuthorizationInfo.java @@ -54,6 +54,7 @@ public SimpleAuthorizationInfo() { /** * Creates a new instance with the specified roles and no permissions. + * * @param roles the roles assigned to the realm account. */ public SimpleAuthorizationInfo(Set roles) { @@ -66,6 +67,7 @@ public Set getRoles() { /** * Sets the roles assigned to the account. + * * @param roles the roles assigned to the account. */ public void setRoles(Set roles) { @@ -75,6 +77,7 @@ public void setRoles(Set roles) { /** * Adds (assigns) a role to those associated with the account. If the account doesn't yet have any roles, a * new roles collection (a Set) will be created automatically. + * * @param role the role to add to those associated with the account. */ public void addRole(String role) { @@ -87,6 +90,7 @@ public void addRole(String role) { /** * Adds (assigns) multiple roles to those associated with the account. If the account doesn't yet have any roles, a * new roles collection (a Set) will be created automatically. + * * @param roles the roles to add to those associated with the account. */ public void addRoles(Collection roles) { @@ -114,6 +118,7 @@ public void setStringPermissions(Set stringPermissions) { /** * Adds (assigns) a permission to those directly associated with the account. If the account doesn't yet have any * direct permissions, a new permission collection (a Set<String>) will be created automatically. + * * @param permission the permission to add to those directly assigned to the account. */ public void addStringPermission(String permission) { @@ -126,6 +131,7 @@ public void addStringPermission(String permission) { /** * Adds (assigns) multiple permissions to those associated directly with the account. If the account doesn't yet * have any string-based permissions, a new permissions collection (a Set<String>) will be created automatically. + * * @param permissions the permissions to add to those associated directly with the account. */ public void addStringPermissions(Collection permissions) { @@ -153,6 +159,7 @@ public void setObjectPermissions(Set objectPermissions) { /** * Adds (assigns) a permission to those directly associated with the account. If the account doesn't yet have any * direct permissions, a new permission collection (a Set<{@link Permission Permission}>) will be created automatically. + * * @param permission the permission to add to those directly assigned to the account. */ public void addObjectPermission(Permission permission) { @@ -166,6 +173,7 @@ public void addObjectPermission(Permission permission) { * Adds (assigns) multiple permissions to those associated directly with the account. If the account doesn't yet * have any object-based permissions, a new permissions collection (a Set<{@link Permission Permission}>) * will be created automatically. + * * @param permissions the permissions to add to those associated directly with the account. */ public void addObjectPermissions(Collection permissions) { diff --git a/core/src/main/java/org/apache/shiro/authz/SimpleRole.java b/core/src/main/java/org/apache/shiro/authz/SimpleRole.java index 73f65ae3d8..8dcdd876bc 100644 --- a/core/src/main/java/org/apache/shiro/authz/SimpleRole.java +++ b/core/src/main/java/org/apache/shiro/authz/SimpleRole.java @@ -31,7 +31,7 @@ */ public class SimpleRole implements Serializable { - protected String name = null; + protected String name; protected Set permissions; public SimpleRole() { diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java b/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java index cf2977303a..ed08c1a635 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java @@ -1,29 +1,36 @@ -/* - * 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.authz.annotation; - -/** - * An enum for specifying a logical operation that can be used for - * interpreting authorization annotations - * - * @since 1.1.0 - */ -public enum Logical { - AND, OR -} +/* + * 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.authz.annotation; + +/** + * An enum for specifying a logical operation that can be used for + * interpreting authorization annotations + * + * @since 1.1.0 + */ +public enum Logical { + /** + * AND + */ + AND, + /** + * OR + */ + OR +} diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresAuthentication.java b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresAuthentication.java index 7216a03d92..a7e33ee193 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresAuthentication.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresAuthentication.java @@ -30,7 +30,8 @@ * {@link RequiresUser RequiresUser} annotation. *

* This annotation basically ensures that - * {@link org.apache.shiro.subject.Subject subject}.{@link org.apache.shiro.subject.Subject#isAuthenticated() isAuthenticated()} === true + * {@link org.apache.shiro.subject.Subject subject}. + * {@link org.apache.shiro.subject.Subject#isAuthenticated() isAuthenticated()} === true *

* See the {@link RequiresUser RequiresUser} and * {@link org.apache.shiro.authc.RememberMeAuthenticationToken RememberMeAuthenticationToken} JavaDoc for an @@ -38,7 +39,6 @@ * * @see RequiresUser * @see RequiresGuest - * * @since 0.9.0 */ @Target({ElementType.TYPE, ElementType.METHOD}) diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresGuest.java b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresGuest.java index f16241490c..23c441c14f 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresGuest.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresGuest.java @@ -35,7 +35,6 @@ * * @see RequiresAuthentication * @see RequiresUser - * * @since 0.9.0 */ @Target({ElementType.TYPE, ElementType.METHOD}) diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java index 50b5c25b26..b363da9749 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java @@ -54,12 +54,12 @@ * to determine if the user is allowed to invoke the code protected by this annotation. */ String[] value(); - + /** * The logical operation for the permission checks in case multiple roles are specified. AND is the default + * * @since 1.1.0 */ - Logical logical() default Logical.AND; + Logical logical() default Logical.AND; } - diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java index 016cd864cb..afc147847c 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java @@ -25,7 +25,7 @@ import java.lang.annotation.Target; /** - * Requires the currently executing {@link org.apache.shiro.subject.Subject Subject} to have all of the + * Requires the currently executing {@link org.apache.shiro.subject.Subject Subject} to have all of the * specified roles. If they do not have the role(s), the method will not be executed and * an {@link org.apache.shiro.authz.AuthorizationException AuthorizationException} is thrown. *

@@ -61,10 +61,11 @@ * invocation to be allowed. */ String[] value(); - + /** * The logical operation for the permission check in case multiple roles are specified. AND is the default + * * @since 1.1.0 */ - Logical logical() default Logical.AND; + Logical logical() default Logical.AND; } diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresUser.java b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresUser.java index 853056cf2c..20048b8ab4 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/RequiresUser.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/RequiresUser.java @@ -43,7 +43,6 @@ * * @see RequiresAuthentication * @see RequiresGuest - * * @since 0.9.0 */ @Target({ElementType.TYPE, ElementType.METHOD}) diff --git a/core/src/main/java/org/apache/shiro/authz/annotation/package-info.java b/core/src/main/java/org/apache/shiro/authz/annotation/package-info.java index 3fa8d23a7f..df90e4de94 100644 --- a/core/src/main/java/org/apache/shiro/authz/annotation/package-info.java +++ b/core/src/main/java/org/apache/shiro/authz/annotation/package-info.java @@ -19,10 +19,6 @@ /** * Annotations used to restrict which classes, instances, or methods may be accessed or invoked depending on the * caller's access abilities or authentication state. - * - * Since 1.1, all core annotations were extends to accept Target ElementType.TYPE in addition to ElementType.METHOD + * Since 1.1, all core annotations were extends to accept Target ElementType.TYPE in addition to ElementType.METHOD */ package org.apache.shiro.authz.annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; - diff --git a/core/src/main/java/org/apache/shiro/authz/aop/AnnotationsAuthorizingMethodInterceptor.java b/core/src/main/java/org/apache/shiro/authz/aop/AnnotationsAuthorizingMethodInterceptor.java index f9bd41a5de..69b63b9bec 100644 --- a/core/src/main/java/org/apache/shiro/authz/aop/AnnotationsAuthorizingMethodInterceptor.java +++ b/core/src/main/java/org/apache/shiro/authz/aop/AnnotationsAuthorizingMethodInterceptor.java @@ -45,7 +45,7 @@ public abstract class AnnotationsAuthorizingMethodInterceptor extends Authorizin protected Collection methodInterceptors; /** - * Default no-argument constructor that defaults the + * Default no-argument constructor that defaults the * {@link #methodInterceptors methodInterceptors} attribute to contain two interceptors by default - the * {@link RoleAnnotationMethodInterceptor RoleAnnotationMethodInterceptor} and the * {@link PermissionAnnotationMethodInterceptor PermissionAnnotationMethodInterceptor} to @@ -68,6 +68,7 @@ public AnnotationsAuthorizingMethodInterceptor() { * {@link RoleAnnotationMethodInterceptor RoleAnnotationMethodInterceptor} and a * {@link PermissionAnnotationMethodInterceptor PermissionAnnotationMethodInterceptor} to * support role and permission annotations automatically. + * * @return the method interceptors to execute for the annotated method. */ public Collection getMethodInterceptors() { @@ -76,6 +77,7 @@ public Collection getMethodInterceptors( /** * Sets the method interceptors to execute for the annotated method. + * * @param methodInterceptors the method interceptors to execute for the annotated method. * @see #getMethodInterceptors() */ diff --git a/core/src/main/java/org/apache/shiro/authz/aop/AuthenticatedAnnotationHandler.java b/core/src/main/java/org/apache/shiro/authz/aop/AuthenticatedAnnotationHandler.java index d45d740526..3abf06e0c9 100644 --- a/core/src/main/java/org/apache/shiro/authz/aop/AuthenticatedAnnotationHandler.java +++ b/core/src/main/java/org/apache/shiro/authz/aop/AuthenticatedAnnotationHandler.java @@ -18,11 +18,11 @@ */ package org.apache.shiro.authz.aop; -import java.lang.annotation.Annotation; - import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.annotation.RequiresAuthentication; +import java.lang.annotation.Annotation; + /** * Handles {@link RequiresAuthentication RequiresAuthentication} annotations and ensures the calling subject is @@ -42,15 +42,16 @@ public AuthenticatedAnnotationHandler() { /** * Ensures that the calling Subject is authenticated, and if not, throws an - * {@link org.apache.shiro.authz.UnauthenticatedException UnauthenticatedException} indicating the method is not allowed to be executed. + * {@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..e49f4d02ba 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,9 +58,10 @@ 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); @@ -74,21 +74,23 @@ public Object invoke(MethodInvocation methodInvocation) throws Throwable { * As this is an AnnotationMethodInterceptor, this implementation merely delegates to the internal * {@link AuthorizingAnnotationHandler AuthorizingAnnotationHandler} by first acquiring the annotation by * calling {@link #getAnnotation(MethodInvocation) getAnnotation(methodInvocation)} and then calls - * {@link AuthorizingAnnotationHandler#assertAuthorized(java.lang.annotation.Annotation) handler.assertAuthorized(annotation)}. + * {@link AuthorizingAnnotationHandler#assertAuthorized(java.lang.annotation.Annotation) + * handler.assertAuthorized(annotation)}. * * @param mi the MethodInvocation to check to see if it is allowed to proceed/execute. * @throws AuthorizationException if the method invocation is not allowed to continue/execute. */ 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 - * + *

* {@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..10e567741f 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 @@ -18,19 +18,19 @@ */ package org.apache.shiro.authz.aop; -import java.lang.annotation.Annotation; - import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.annotation.RequiresGuest; +import java.lang.annotation.Annotation; /** * 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 * have an {@link org.apache.shiro.subject.Subject#getPrincipal() identity} before invoking the method. *

- * This annotation essentially ensures that subject.{@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} == null. + * This annotation essentially ensures that subject. + * {@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} == null. * * @since 0.9.0 */ @@ -38,7 +38,7 @@ public class GuestAnnotationHandler extends AuthorizingAnnotationHandler { /** * Default no-argument constructor that ensures this interceptor looks for - * + *

* {@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest} annotations in a method * declaration. */ @@ -53,14 +53,13 @@ public GuestAnnotationHandler() { * 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..7acaa5454e 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 @@ -25,7 +25,8 @@ * is declared, and if so, ensures the calling Subject does not * have an {@link org.apache.shiro.subject.Subject#getPrincipal() identity} before invoking the method. *

- * This annotation essentially ensures that subject.{@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} == null. + * This annotation essentially ensures that subject. + * {@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} == null. * * @since 0.9.0 */ 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..d8cfb9031e 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; @@ -59,12 +58,13 @@ protected String[] getAnnotationValue(Annotation a) { * 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 +88,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..244fc673d3 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 @@ -21,8 +21,9 @@ import org.apache.shiro.aop.AnnotationResolver; /** - * 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. + * 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 +38,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 +46,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..0cc8de0614 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 @@ -26,8 +26,8 @@ import java.util.Arrays; /** - * 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. + * 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. * * @since 0.9.0 */ @@ -46,12 +46,13 @@ public RoleAnnotationHandler() { * 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 +68,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..8ab9327760 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. @@ -43,13 +44,14 @@ public RolesAllowedAnnotationHandler() { * 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 +65,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..77bd16a7f4 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 @@ -18,12 +18,11 @@ */ package org.apache.shiro.authz.aop; -import java.lang.annotation.Annotation; - import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.annotation.RequiresUser; +import java.lang.annotation.Annotation; /** * Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser} annotation @@ -31,7 +30,8 @@ * {@link org.apache.shiro.subject.Subject#isAuthenticated() authenticated} or remembered via remember * me services before allowing access. *

- * This annotation essentially ensures that subject.{@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} != null. + * This annotation essentially ensures that subject. + * {@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} != null. * * @since 0.9.0 */ @@ -39,7 +39,7 @@ public class UserAnnotationHandler extends AuthorizingAnnotationHandler { /** * Default no-argument constructor that ensures this handler looks for - * + *

* {@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser} annotations. */ public UserAnnotationHandler() { @@ -53,14 +53,14 @@ 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..5c569fc8c5 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 @@ -26,7 +26,8 @@ * {@link org.apache.shiro.subject.Subject#isAuthenticated() authenticated} or remembered via remember * me services before invoking the method. *

- * This annotation essentially ensures that subject.{@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} != null. + * This annotation essentially ensures that subject. + * {@link org.apache.shiro.subject.Subject#getPrincipal() getPrincipal()} != null. * * @since 0.9.0 */ @@ -34,16 +35,15 @@ public class UserAnnotationMethodInterceptor extends AuthorizingAnnotationMethod /** * Default no-argument constructor that ensures this interceptor looks for - * + *

* {@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 Set actions; private Set targets; - private static final long serialVersionUID = 1l; - /** * Creates a domain permission with *all* actions for *all* targets; */ diff --git a/core/src/main/java/org/apache/shiro/authz/permission/InvalidPermissionStringException.java b/core/src/main/java/org/apache/shiro/authz/permission/InvalidPermissionStringException.java index d7c19403f5..5888319096 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/InvalidPermissionStringException.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/InvalidPermissionStringException.java @@ -27,10 +27,9 @@ * * @since 0.9 */ -public class InvalidPermissionStringException extends ShiroException -{ +public class InvalidPermissionStringException extends ShiroException { - private String permissionString; + private final String permissionString; /** * Constructs a new exception with the given message and permission string. diff --git a/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolver.java b/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolver.java index 1714c39359..9da96a4306 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolver.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolver.java @@ -42,9 +42,11 @@ * Although this happens to be the Shiro default, you are of course free to provide custom * String-to-Permission conversion by providing Shiro components any instance of this interface. * - * @see org.apache.shiro.authz.ModularRealmAuthorizer#setPermissionResolver(PermissionResolver) ModularRealmAuthorizer.setPermissionResolver - * @see org.apache.shiro.realm.AuthorizingRealm#setPermissionResolver(PermissionResolver) AuthorizingRealm.setPermissionResolver - * @see PermissionResolverAware PermissionResolverAware + * @see org.apache.shiro.authz.ModularRealmAuthorizer#setPermissionResolver(PermissionResolver) + * ModularRealmAuthorizer.setPermissionResolver + * @see org.apache.shiro.realm.AuthorizingRealm#setPermissionResolver(PermissionResolver) + * AuthorizingRealm.setPermissionResolver + * @see PermissionResolverAware PermissionResolverAware * @since 0.9 */ public interface PermissionResolver { @@ -54,8 +56,7 @@ public interface PermissionResolver { * * @param permissionString the String representation of a permission. * @return A Permission object that can be used internally to determine a subject's permissions. - * @throws InvalidPermissionStringException - * if the permission string is not valid for this resolver. + * @throws InvalidPermissionStringException if the permission string is not valid for this resolver. */ Permission resolvePermission(String permissionString); diff --git a/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolverAware.java b/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolverAware.java index 9ea76c2338..fa1e1c76b2 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolverAware.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/PermissionResolverAware.java @@ -36,5 +36,5 @@ public interface PermissionResolverAware { * * @param pr the PermissionResolver being set. */ - public void setPermissionResolver(PermissionResolver pr); + void setPermissionResolver(PermissionResolver pr); } diff --git a/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolver.java b/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolver.java index 68e3cdb69e..5ff3d14bcf 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolver.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolver.java @@ -28,7 +28,6 @@ *

* In some cases a {@link org.apache.shiro.realm.Realm} my only be able to return a list of roles. This * component allows an application to resolve the roles into permissions. - * */ public interface RolePermissionResolver { diff --git a/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolverAware.java b/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolverAware.java index be9d841e03..f8c4621d91 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolverAware.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/RolePermissionResolverAware.java @@ -36,5 +36,5 @@ public interface RolePermissionResolverAware { * * @param rpr the RolePermissionResolver being set. */ - public void setRolePermissionResolver(RolePermissionResolver rpr); + void setRolePermissionResolver(RolePermissionResolver rpr); } diff --git a/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermission.java b/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermission.java index 2eeaffbf90..dd8f1c5011 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermission.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermission.java @@ -105,8 +105,6 @@ */ public class WildcardPermission implements Permission, Serializable { - //TODO - JavaDoc methods - /*-------------------------------------------- | C O N S T A N T S | ============================================*/ @@ -123,6 +121,7 @@ public class WildcardPermission implements Permission, Serializable { /*-------------------------------------------- | C O N S T R U C T O R S | ============================================*/ + /** * Default no-arg constructor for subclasses only - end-user developers instantiating Permission instances must * provide a wildcard string at a minimum, since Permission instances are immutable once instantiated. @@ -151,7 +150,8 @@ protected void setParts(String wildcardString, boolean caseSensitive) { wildcardString = StringUtils.clean(wildcardString); if (wildcardString == null || wildcardString.isEmpty()) { - throw new IllegalArgumentException("Wildcard string cannot be null or empty. Make sure permission strings are properly formatted."); + throw new IllegalArgumentException("Wildcard string cannot be null or empty." + + "Make sure permission strings are properly formatted."); } if (!caseSensitive) { @@ -165,13 +165,15 @@ protected void setParts(String wildcardString, boolean caseSensitive) { Set subparts = CollectionUtils.asSet(part.split(SUBPART_DIVIDER_TOKEN)); if (subparts.isEmpty()) { - throw new IllegalArgumentException("Wildcard string cannot contain parts with only dividers. Make sure permission strings are properly formatted."); + throw new IllegalArgumentException("Wildcard string cannot contain parts with only dividers." + + "Make sure permission strings are properly formatted."); } this.parts.add(subparts); } if (this.parts.isEmpty()) { - throw new IllegalArgumentException("Wildcard string cannot contain only dividers. Make sure permission strings are properly formatted."); + throw new IllegalArgumentException("Wildcard string cannot contain only dividers." + + "Make sure permission strings are properly formatted."); } } @@ -184,8 +186,9 @@ protected List> getParts() { /** * Sets the pre-split String parts of this WildcardPermission. - * @since 1.3.0 + * * @param parts pre-split String parts. + * @since 1.3.0 */ protected void setParts(List> parts) { this.parts = parts; @@ -238,7 +241,7 @@ public String toString() { buffer.append(PART_DIVIDER_TOKEN); } Iterator partIt = part.iterator(); - while(partIt.hasNext()) { + while (partIt.hasNext()) { buffer.append(partIt.next()); if (partIt.hasNext()) { buffer.append(SUBPART_DIVIDER_TOKEN); diff --git a/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermissionResolver.java b/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermissionResolver.java index 0adffada7c..6bfb2d3a5f 100644 --- a/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermissionResolver.java +++ b/core/src/main/java/org/apache/shiro/authz/permission/WildcardPermissionResolver.java @@ -29,19 +29,20 @@ */ public class WildcardPermissionResolver implements PermissionResolver { boolean caseSensitive; - + /** * Constructor to specify case sensitivity for the resolved permissions. + * * @param caseSensitive true if permissions should be case sensitive. */ public WildcardPermissionResolver(boolean caseSensitive) { - this.caseSensitive=caseSensitive; + this.caseSensitive = caseSensitive; } /** - * Default constructor. + * Default constructor. * Equivalent to calling WildcardPermissionResolver(false) - * + * * @see WildcardPermissionResolver#WildcardPermissionResolver(boolean) */ public WildcardPermissionResolver() { @@ -50,26 +51,29 @@ public WildcardPermissionResolver() { /** * Set the case sensitivity of the resolved Wildcard permissions. + * * @param state the caseSensitive flag state for resolved permissions. */ public void setCaseSensitive(boolean state) { this.caseSensitive = state; } + /** * Return true if this resolver produces case sensitive permissions. + * * @return true if this resolver produces case sensitive permissions. */ public boolean isCaseSensitive() { return caseSensitive; } - + /** * Returns a new {@link WildcardPermission WildcardPermission} instance constructed based on the specified * permissionString. * * @param permissionString the permission string to convert to a {@link Permission Permission} instance. * @return a new {@link WildcardPermission WildcardPermission} instance constructed based on the specified - * permissionString + * permissionString */ public Permission resolvePermission(String permissionString) { return new WildcardPermission(permissionString, caseSensitive); diff --git a/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutor.java b/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutor.java index 78c8424292..d7e0769fd8 100644 --- a/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutor.java +++ b/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutor.java @@ -95,7 +95,7 @@ public void setTargetExecutor(Executor targetExecutor) { * {@code SecurityUtils}.{@link SecurityUtils#getSubject() getSubject()}. * * @return the currently Subject instance that should be associated with Runnable or Callable instances before - * being dispatched to the target {@code Executor} instance. + * being dispatched to the target {@code Executor} instance. */ protected Subject getSubject() { return SecurityUtils.getSubject(); diff --git a/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutorService.java b/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutorService.java index 07be8bdcf8..52fa28104c 100644 --- a/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutorService.java +++ b/core/src/main/java/org/apache/shiro/concurrent/SubjectAwareExecutorService.java @@ -23,7 +23,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * {@code ExecutorService} implementation that will automatically first associate any argument @@ -40,7 +46,8 @@ * Consider this code that could be repeated in many places across an application: *

  * {@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(Map seed) { * {@link #lookupSecurityManager()} method is provided as an alternative. * * @return the application's {@code SecurityManager} instance accessible in the backing map using the - * {@link #getSecurityManagerName() securityManagerName} property as the lookup key. + * {@link #getSecurityManagerName() securityManagerName} property as the lookup key. */ public SecurityManager getSecurityManager() throws IllegalStateException { SecurityManager securityManager = lookupSecurityManager(); if (securityManager == null) { - throw new IllegalStateException("No SecurityManager found in Environment. This is an invalid " + - "environment state."); + throw new IllegalStateException("No SecurityManager found in Environment. This is an invalid " + + "environment state."); } return securityManager; } @@ -107,7 +107,7 @@ protected SecurityManager lookupSecurityManager() { * instance. Unless set otherwise, the default is {@code securityManager}. * * @return the name of the {@link SecurityManager} instance in the backing map. Used as a key to lookup the - * instance. + * instance. */ public String getSecurityManagerName() { return securityManagerName; @@ -129,7 +129,7 @@ public void setSecurityManagerName(String securityManagerName) { * * @return the live (modifiable) internal objects collection. */ - public Map getObjects() { + public Map getObjects() { return this.objects; } @@ -147,10 +147,11 @@ public T getObject(String name, Class requiredType) throws RequiredTypeEx return null; } if (!requiredType.isInstance(o)) { - String msg = "Object named '" + name + "' (of type [" + o.getClass().getName() + "]) is not of required type [" + requiredType.getName() + "]."; + String msg = "Object named '" + name + "' (of type [" + o.getClass().getName() + "]) is not of required type [" + + requiredType.getName() + "]."; throw new RequiredTypeException(msg); } - return (T)o; + return (T) o; } public void setObject(String name, Object instance) { diff --git a/core/src/main/java/org/apache/shiro/env/NamedObjectEnvironment.java b/core/src/main/java/org/apache/shiro/env/NamedObjectEnvironment.java index 1d6aa349b8..e428adcdee 100644 --- a/core/src/main/java/org/apache/shiro/env/NamedObjectEnvironment.java +++ b/core/src/main/java/org/apache/shiro/env/NamedObjectEnvironment.java @@ -29,12 +29,12 @@ public interface NamedObjectEnvironment extends Environment { * Returns the object in Shiro's environment with the specified name and type or {@code null} if * no object with that name was found. * - * @param name the assigned name of the object. + * @param name the assigned name of the object. * @param requiredType the class to which the discovered object must be assignable. - * @param the type of the class - * @throws RequiredTypeException if the discovered object does not equal, extend, or implement the specified class. + * @param the type of the class * @return the object in Shiro's environment with the specified name (of the specified type) or {@code null} if * no object with that name was found. + * @throws RequiredTypeException if the discovered object does not equal, extend, or implement the specified class. */ T getObject(String name, Class requiredType) throws RequiredTypeException; } diff --git a/core/src/main/java/org/apache/shiro/env/package-info.java b/core/src/main/java/org/apache/shiro/env/package-info.java index 6ad3bd3f34..a725a1a7b6 100644 --- a/core/src/main/java/org/apache/shiro/env/package-info.java +++ b/core/src/main/java/org/apache/shiro/env/package-info.java @@ -17,9 +17,10 @@ * under the License. */ /** - * Concepts used to represent Shiro's aggregate state in an application. An {@link Environment} instance represents + * Concepts used to represent Shiro's aggregate state in an application. + * An {@link org.apache.shiro.env.Environment} instance represents * everything Shiro needs to function in an application. * - * @see Environment + * @see org.apache.shiro.env.Environment */ -package org.apache.shiro.env; \ No newline at end of file +package org.apache.shiro.env; diff --git a/core/src/main/java/org/apache/shiro/ini/IniFactorySupport.java b/core/src/main/java/org/apache/shiro/ini/IniFactorySupport.java index b83477e524..4fb2370bd5 100644 --- a/core/src/main/java/org/apache/shiro/ini/IniFactorySupport.java +++ b/core/src/main/java/org/apache/shiro/ini/IniFactorySupport.java @@ -32,15 +32,19 @@ * Base support class for {@link Factory} implementations that generate their instance(s) based on * {@link Ini} configuration. * + * @param T * @since 1.0 * @deprecated use Shiro's {@code Environment} mechanisms instead. */ @Deprecated public abstract class IniFactorySupport extends AbstractFactory { + /** + * default ini resource path. + */ public static final String DEFAULT_INI_RESOURCE_PATH = "classpath:shiro.ini"; - private static transient final Logger log = LoggerFactory.getLogger(IniFactorySupport.class); + private static final Logger LOGGER = LoggerFactory.getLogger(IniFactorySupport.class); private Ini ini; @@ -64,6 +68,7 @@ public void setIni(Ini ini) { /** * Returns a mapping of String to bean representing the default set of object used by the factory. * These beans can be used by this factory in conjunction with objects parsed from the INI configuration. + * * @return A Map of default objects, or null. * @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(Map defaultBeans) { * the file does not exist. * * @return a new Ini instance created from the default {@code classpath:shiro.ini} file, or {@code null} if - * the file does not exist. + * the file does not exist. */ public static Ini loadDefaultClassPathIni() { Ini ini = null; if (ResourceUtils.resourceExists(DEFAULT_INI_RESOURCE_PATH)) { - log.debug("Found shiro.ini at the root of the classpath."); + LOGGER.debug("Found shiro.ini at the root of the classpath."); ini = new Ini(); ini.loadFromPath(DEFAULT_INI_RESOURCE_PATH); if (CollectionUtils.isEmpty(ini)) { - log.warn("shiro.ini found at the root of the classpath, but it did not contain any data."); + LOGGER.warn("shiro.ini found at the root of the classpath, but it did not contain any data."); } } return ini; @@ -115,7 +121,7 @@ public static Ini loadDefaultClassPathIni() { protected Ini resolveIni() { Ini ini = getIni(); if (CollectionUtils.isEmpty(ini)) { - log.debug("Null or empty Ini instance. Falling back to the default {} file.", DEFAULT_INI_RESOURCE_PATH); + LOGGER.debug("Null or empty Ini instance. Falling back to the default {} file.", DEFAULT_INI_RESOURCE_PATH); ini = loadDefaultClassPathIni(); } return ini; @@ -137,20 +143,20 @@ public T createInstance() { T instance; if (CollectionUtils.isEmpty(ini)) { - log.debug("No populated Ini available. Creating a default instance."); + LOGGER.debug("No populated Ini available. Creating a default instance."); instance = createDefaultInstance(); if (instance == null) { - String msg = getClass().getName() + " implementation did not return a default instance in " + - "the event of a null/empty Ini configuration. This is required to support the " + - "Factory interface. Please check your implementation."; + String msg = getClass().getName() + " implementation did not return a default instance in " + + "the event of a null/empty Ini configuration. This is required to support the " + + "Factory interface. Please check your implementation."; throw new IllegalStateException(msg); } } else { - log.debug("Creating instance from Ini [" + ini + "]"); + LOGGER.debug("Creating instance from Ini [" + ini + "]"); instance = createInstance(ini); if (instance == null) { - String msg = getClass().getName() + " implementation did not return a constructed instance from " + - "the createInstance(Ini) method implementation."; + String msg = getClass().getName() + " implementation did not return a constructed instance from " + + "the createInstance(Ini) method implementation."; throw new IllegalStateException(msg); } } @@ -158,7 +164,18 @@ public T createInstance() { return instance; } + /** + * create instance. + * + * @param ini ini + * @return T + */ protected abstract T createInstance(Ini ini); + /** + * create default instance. + * + * @return T + */ protected abstract T createDefaultInstance(); } diff --git a/core/src/main/java/org/apache/shiro/ini/IniSecurityManagerFactory.java b/core/src/main/java/org/apache/shiro/ini/IniSecurityManagerFactory.java index 171292a985..328dce68bc 100644 --- a/core/src/main/java/org/apache/shiro/ini/IniSecurityManagerFactory.java +++ b/core/src/main/java/org/apache/shiro/ini/IniSecurityManagerFactory.java @@ -50,12 +50,22 @@ @Deprecated public class IniSecurityManagerFactory extends IniFactorySupport { + /** + * main section name. + */ public static final String MAIN_SECTION_NAME = "main"; + /** + * security manager name. + */ public static final String SECURITY_MANAGER_NAME = "securityManager"; + + /** + * ini realm name. + */ public static final String INI_REALM_NAME = "iniRealm"; - private static transient final Logger log = LoggerFactory.getLogger(IniSecurityManagerFactory.class); + private static final Logger LOGGER = LoggerFactory.getLogger(IniSecurityManagerFactory.class); private ReflectionBuilder builder; @@ -81,7 +91,7 @@ public IniSecurityManagerFactory(String iniResourcePath) { } public void destroy() { - if(getReflectionBuilder() != null) { + if (getReflectionBuilder() != null) { getReflectionBuilder().destroy(); } } @@ -127,8 +137,8 @@ protected boolean isAutoApplyRealms(SecurityManager securityManager) { RealmSecurityManager realmSecurityManager = (RealmSecurityManager) securityManager; Collection realms = realmSecurityManager.getRealms(); if (!CollectionUtils.isEmpty(realms)) { - log.info("Realms have been explicitly set on the SecurityManager instance - auto-setting of " + - "realms will not occur."); + LOGGER.info("Realms have been explicitly set on the SecurityManager instance - auto-setting of " + + "realms will not occur."); autoApply = false; } } @@ -214,9 +224,9 @@ private Collection getRealms(Map instances) { if (existingName == null || existingName.startsWith(realm.getClass().getName())) { if (realm instanceof Nameable) { ((Nameable) realm).setName(name); - log.debug("Applied name '{}' to Nameable realm instance {}", name, realm); + LOGGER.debug("Applied name '{}' to Nameable realm instance {}", name, realm); } else { - log.info("Realm does not implement the {} interface. Configured name will not be applied.", + LOGGER.info("Realm does not implement the {} interface. Configured name will not be applied.", Nameable.class.getName()); } } @@ -232,8 +242,8 @@ private void assertRealmSecurityManager(SecurityManager securityManager) { throw new NullPointerException("securityManager instance cannot be null"); } if (!(securityManager instanceof RealmSecurityManager)) { - String msg = "securityManager instance is not a " + RealmSecurityManager.class.getName() + - " instance. This is required to access or configure realms on the instance."; + String msg = "securityManager instance is not a " + RealmSecurityManager.class.getName() + + " instance. This is required to access or configure realms on the instance."; throw new ConfigurationException(msg); } } @@ -250,13 +260,13 @@ protected void applyRealmsToSecurityManager(Collection realms, SecurityMa * * @param ini the Ini instance to inspect for account data resulting in an implicitly created realm. * @return {@code true} if the Ini contains account data and a {@code Realm} should be implicitly - * {@link #createRealm(Ini) created} to reflect the account data, {@code false} if no realm should be - * implicitly created. + * {@link #createRealm(Ini) created} to reflect the account data, {@code false} if no realm should be + * implicitly created. */ protected boolean shouldImplicitlyCreateRealm(Ini ini) { - return !CollectionUtils.isEmpty(ini) && - (!CollectionUtils.isEmpty(ini.getSection(IniRealm.ROLES_SECTION_NAME)) || - !CollectionUtils.isEmpty(ini.getSection(IniRealm.USERS_SECTION_NAME))); + return !CollectionUtils.isEmpty(ini) + && (!CollectionUtils.isEmpty(ini.getSection(IniRealm.ROLES_SECTION_NAME)) + || !CollectionUtils.isEmpty(ini.getSection(IniRealm.USERS_SECTION_NAME))); } /** @@ -269,12 +279,14 @@ protected Realm createRealm(Ini ini) { //IniRealm realm = new IniRealm(ini); changed to support SHIRO-322 IniRealm realm = new IniRealm(); realm.setName(INI_REALM_NAME); - realm.setIni(ini); //added for SHIRO-322 + //added for SHIRO-322 + realm.setIni(ini); return realm; } /** * Returns the ReflectionBuilder instance used to create SecurityManagers object graph. + * * @return ReflectionBuilder instance used to create SecurityManagers object graph. * @since 1.4 */ @@ -285,6 +297,7 @@ public ReflectionBuilder getReflectionBuilder() { /** * Sets the ReflectionBuilder that will be used to create the SecurityManager based on the contents of * the Ini configuration. + * * @param builder The ReflectionBuilder used to parse the Ini configuration. * @since 1.4 */ @@ -292,4 +305,4 @@ public ReflectionBuilder getReflectionBuilder() { public void setReflectionBuilder(ReflectionBuilder builder) { this.builder = builder; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/apache/shiro/ini/package-info.java b/core/src/main/java/org/apache/shiro/ini/package-info.java new file mode 100644 index 0000000000..100556138b --- /dev/null +++ b/core/src/main/java/org/apache/shiro/ini/package-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +/** + * Concepts used to represent Shiro's aggregate state in an application. + * An {@link org.apache.shiro.env.Environment} instance represents + * everything Shiro needs to function in an application. + * + * @see org.apache.shiro.env.Environment + */ +package org.apache.shiro.ini; diff --git a/core/src/main/java/org/apache/shiro/jndi/JndiLocator.java b/core/src/main/java/org/apache/shiro/jndi/JndiLocator.java index 1701e73bbe..85bae8bd6b 100644 --- a/core/src/main/java/org/apache/shiro/jndi/JndiLocator.java +++ b/core/src/main/java/org/apache/shiro/jndi/JndiLocator.java @@ -42,16 +42,16 @@ public class JndiLocator { /** - * Private class log. + * JNDI prefix used in a Jakarta EE container */ - private static final Logger log = LoggerFactory.getLogger(JndiLocator.class); + public static final String CONTAINER_PREFIX = "java:comp/env/"; /** - * JNDI prefix used in a J2EE container + * Private class log. */ - public static final String CONTAINER_PREFIX = "java:comp/env/"; + private static final Logger LOGGER = LoggerFactory.getLogger(JndiLocator.class); - private boolean resourceRef = false; + private boolean resourceRef; private JndiTemplate jndiTemplate = new JndiTemplate(); @@ -91,7 +91,7 @@ public Properties getJndiEnvironment() { } /** - * Set whether the lookup occurs in a J2EE container, i.e. if the prefix + * Set whether the lookup occurs in a Jakarta EE container, i.e. if the prefix * "java:comp/env/" needs to be added if the JNDI name doesn't already * contain it. Default is "false". *

Note: Will only get applied if no other scheme (e.g. "java:") is given. @@ -101,7 +101,7 @@ public void setResourceRef(boolean resourceRef) { } /** - * Return whether the lookup occurs in a J2EE container. + * Return whether the lookup occurs in a Jakarta EE container. */ public boolean isResourceRef() { return this.resourceRef; @@ -141,20 +141,19 @@ protected Object lookup(String jndiName, Class requiredType) throws NamingExcept Object jndiObject; try { jndiObject = getJndiTemplate().lookup(convertedName, requiredType); - } - catch (NamingException ex) { + } catch (NamingException ex) { if (!convertedName.equals(jndiName)) { // Try fallback to originally specified name... - if (log.isDebugEnabled()) { - log.debug("Converted JNDI name [" + convertedName + - "] not found - trying original name [" + jndiName + "]. " + ex); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Converted JNDI name [" + convertedName + + "] not found - trying original name [" + jndiName + "]. " + ex); } jndiObject = getJndiTemplate().lookup(jndiName, requiredType); } else { throw ex; } } - log.debug("Located object with JNDI name '{}'", convertedName); + LOGGER.debug("Located object with JNDI name '{}'", convertedName); return jndiObject; } diff --git a/core/src/main/java/org/apache/shiro/jndi/JndiObjectFactory.java b/core/src/main/java/org/apache/shiro/jndi/JndiObjectFactory.java index a67bf30393..2fa72bb442 100644 --- a/core/src/main/java/org/apache/shiro/jndi/JndiObjectFactory.java +++ b/core/src/main/java/org/apache/shiro/jndi/JndiObjectFactory.java @@ -24,6 +24,7 @@ /** * A factory implementation intended to be used to look up objects in jndi. + * * @param * @since 1.2 */ @@ -34,7 +35,7 @@ public class JndiObjectFactory extends JndiLocator implements Factory { public T getInstance() { try { - if(requiredType != null) { + if (requiredType != null) { return requiredType.cast(this.lookup(resourceName, requiredType)); } else { return (T) this.lookup(resourceName); diff --git a/core/src/main/java/org/apache/shiro/jndi/JndiTemplate.java b/core/src/main/java/org/apache/shiro/jndi/JndiTemplate.java index a9870518b1..4600a802f6 100644 --- a/core/src/main/java/org/apache/shiro/jndi/JndiTemplate.java +++ b/core/src/main/java/org/apache/shiro/jndi/JndiTemplate.java @@ -44,11 +44,13 @@ */ public class JndiTemplate { - private static final Logger log = LoggerFactory.getLogger(JndiTemplate.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JndiTemplate.class); private Properties environment; - /** Create a new JndiTemplate instance. */ + /** + * Create a new JndiTemplate instance. + */ public JndiTemplate() { } @@ -91,12 +93,11 @@ public Object execute(JndiCallback contextCallback) throws NamingException { Context ctx = createInitialContext(); try { return contextCallback.doInContext(ctx); - } - finally { + } finally { try { ctx.close(); } catch (NamingException ex) { - log.debug("Could not close JNDI InitialContext", ex); + LOGGER.debug("Could not close JNDI InitialContext", ex); } } } @@ -115,7 +116,7 @@ protected Context createInitialContext() throws NamingException { Hashtable icEnv = null; if (env != null) { icEnv = new Hashtable(env.size()); - for (Enumeration en = env.propertyNames(); en.hasMoreElements();) { + for (Enumeration en = env.propertyNames(); en.hasMoreElements(); ) { String key = (String) en.nextElement(); icEnv.put(key, env.getProperty(key)); } @@ -128,12 +129,12 @@ protected Context createInitialContext() throws NamingException { * * @param name the JNDI name of the object * @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(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..c67ee8bbc1 100644 --- a/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/AbstractRememberMeManager.java @@ -18,13 +18,12 @@ */ package org.apache.shiro.mgt; -import java.util.function.Supplier; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.RememberMeAuthenticationToken; -import org.apache.shiro.crypto.cipher.ByteSourceBroker; import org.apache.shiro.crypto.cipher.AesCipherService; +import org.apache.shiro.crypto.cipher.ByteSourceBroker; import org.apache.shiro.crypto.cipher.CipherService; import org.apache.shiro.lang.io.DefaultSerializer; import org.apache.shiro.lang.io.Serializer; @@ -36,6 +35,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.function.Supplier; + /** * Abstract implementation of the {@code RememberMeManager} interface that handles * {@link #setSerializer(Serializer) serialization} and @@ -68,7 +69,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 +79,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 +119,7 @@ public AbstractRememberMeManager(Supplier keySupplier) { * {@link org.apache.shiro.lang.io.DefaultSerializer}. * * @return the {@code Serializer} used to serialize and deserialize {@link PrincipalCollection} instances for - * persistent remember me storage. + * persistent remember me storage. */ public Serializer getSerializer() { return serializer; @@ -143,7 +145,7 @@ public void setSerializer(Serializer serializer) { * Unless overridden by the {@link #setCipherService} method, the default instance is an {@link AesCipherService}. * * @return the {@code Cipher} to use for encrypting and decrypting serialized identity data to prevent easy - * inspection of Subject identity data + * inspection of Subject identity data */ public CipherService getCipherService() { return cipherService; @@ -273,15 +275,15 @@ public void setCipherKey(byte[] cipherKey) { * @return true if remember me services should be performed as a result of the successful authentication attempt. */ protected boolean isRememberMe(AuthenticationToken token) { - return token != null && (token instanceof RememberMeAuthenticationToken) && - ((RememberMeAuthenticationToken) token).isRememberMe(); + return token instanceof RememberMeAuthenticationToken && ((RememberMeAuthenticationToken) token).isRememberMe(); } /** * Reacts to the successful login attempt by first always {@link #forgetIdentity(Subject) forgetting} any previously * stored identity. Then if the {@code token} * {@link #isRememberMe(org.apache.shiro.authc.AuthenticationToken) is a RememberMe} token, the associated identity - * will be {@link #rememberIdentity(org.apache.shiro.subject.Subject, org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) remembered} + * will be {@link #rememberIdentity(org.apache.shiro.subject.Subject, org.apache.shiro.authc.AuthenticationToken, + * org.apache.shiro.authc.AuthenticationInfo) remembered} * for later retrieval during a new user session. * * @param subject the subject for which the principals are being remembered. @@ -296,9 +298,9 @@ public void onSuccessfulLogin(Subject subject, AuthenticationToken token, Authen if (isRememberMe(token)) { rememberIdentity(subject, token, info); } else { - if (log.isDebugEnabled()) { - log.debug("AuthenticationToken did not indicate RememberMe is requested. " + - "RememberMe functionality will not be executed for corresponding account."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("AuthenticationToken did not indicate RememberMe is requested. " + + "RememberMe functionality will not be executed for corresponding account."); } } } @@ -414,7 +416,7 @@ public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext * is being used to construct a {@link Subject} instance. To be used to assist with data * lookup. * @return the previously persisted serialized identity, or {@code null} if there is no available data for the - * Subject. + * Subject. */ protected abstract byte[] getRememberedSerializedIdentity(SubjectContext subjectContext); @@ -453,13 +455,14 @@ protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectCont */ protected PrincipalCollection onRememberedPrincipalFailure(RuntimeException e, SubjectContext context) { - if (log.isWarnEnabled()) { - String message = "There was a failure while trying to retrieve remembered principals. This could be due to a " + - "configuration problem or corrupted principals. This could also be due to a recently " + - "changed encryption key, if you are using a shiro.ini file, this property would be " + - "'securityManager.rememberMeManager.cipherKey' see: http://shiro.apache.org/web.html#Web-RememberMeServices. " + - "The remembered identity will be forgotten and not used for this request."; - log.warn(message); + if (LOGGER.isWarnEnabled()) { + String message = "There was a failure while trying to retrieve remembered principals. This could be due to a " + + "configuration problem or corrupted principals. This could also be due to a recently " + + "changed encryption key, if you are using a shiro.ini file, this property would be " + + "'securityManager.rememberMeManager.cipherKey'" + + "see: http://shiro.apache.org/web.html#Web-RememberMeServices. " + + "The remembered identity will be forgotten and not used for this request."; + LOGGER.warn(message); } forgetIdentity(context); //propagate - security manager implementation will handle and warn appropriately diff --git a/core/src/main/java/org/apache/shiro/mgt/AuthenticatingSecurityManager.java b/core/src/main/java/org/apache/shiro/mgt/AuthenticatingSecurityManager.java index c1a7cdb535..a455e0898d 100644 --- a/core/src/main/java/org/apache/shiro/mgt/AuthenticatingSecurityManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/AuthenticatingSecurityManager.java @@ -65,7 +65,7 @@ public AuthenticatingSecurityManager() { * {@link org.apache.shiro.authc.pam.ModularRealmAuthenticator ModularRealmAuthenticator}. * * @return the delegate Authenticator 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..0cbea9dc02 100644 --- a/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java @@ -145,7 +145,8 @@ public void checkPermissions(PrincipalCollection principals, String... permissio this.authorizer.checkPermissions(principals, permissions); } - public void checkPermissions(PrincipalCollection principals, Collection permissions) throws AuthorizationException { + public void checkPermissions(PrincipalCollection principals, Collection permissions) + throws AuthorizationException { this.authorizer.checkPermissions(principals, permissions); } @@ -168,8 +169,9 @@ public void checkRole(PrincipalCollection principals, String role) throws Author public void checkRoles(PrincipalCollection principals, Collection roles) throws AuthorizationException { this.authorizer.checkRoles(principals, roles); } - + public void checkRoles(PrincipalCollection principals, String... roles) throws AuthorizationException { this.authorizer.checkRoles(principals, roles); - } + } + } diff --git a/core/src/main/java/org/apache/shiro/mgt/CachingSecurityManager.java b/core/src/main/java/org/apache/shiro/mgt/CachingSecurityManager.java index 80219d4c68..d83f971fc8 100644 --- a/core/src/main/java/org/apache/shiro/mgt/CachingSecurityManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/CachingSecurityManager.java @@ -46,6 +46,7 @@ public abstract class CachingSecurityManager implements SecurityManager, Destroy /** * The EventBus to use to use to publish and receive events of interest during Shiro's lifecycle. + * * @since 1.3 */ private EventBus eventBus; @@ -111,7 +112,7 @@ public EventBus getEventBus() { * eventBus is available. * * @param eventBus the EventBus used by this {@code SecurityManager} and potentially any of its - * children components. + * children components. * @since 1.3 */ public void setEventBus(EventBus eventBus) { @@ -124,7 +125,7 @@ public void setEventBus(EventBus eventBus) { */ protected void applyEventBusToCacheManager() { if (this.eventBus != null && this.cacheManager != null && this.cacheManager instanceof EventBusAware) { - ((EventBusAware)this.cacheManager).setEventBus(this.eventBus); + ((EventBusAware) this.cacheManager).setEventBus(this.eventBus); } } diff --git a/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java b/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java index 9c59218fd7..9912f6ab14 100644 --- a/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java @@ -72,9 +72,10 @@ * * @since 0.2 */ +@SuppressWarnings("checkstyle:MethodCount") public class DefaultSecurityManager extends SessionsSecurityManager { - private static final Logger log = LoggerFactory.getLogger(DefaultSecurityManager.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSecurityManager.class); protected RememberMeManager rememberMeManager; protected SubjectDAO subjectDAO; @@ -121,7 +122,8 @@ public SubjectFactory getSubjectFactory() { /** * Sets the {@code SubjectFactory} responsible for creating {@link Subject} instances exposed to the application. * - * @param subjectFactory the {@code SubjectFactory} responsible for creating {@link Subject} instances exposed to the application. + * @param subjectFactory the {@code SubjectFactory} responsible for creating + * {@link Subject} instances exposed to the application. */ public void setSubjectFactory(SubjectFactory subjectFactory) { this.subjectFactory = subjectFactory; @@ -133,7 +135,7 @@ public void setSubjectFactory(SubjectFactory subjectFactory) { * implementation is a {@link DefaultSubjectDAO}. * * @return the {@code SubjectDAO} responsible for persisting Subject state, typically used after login or when an - * Subject identity is discovered (e.g. after RememberMe services). + * Subject identity is discovered (e.g. after RememberMe services). * @see DefaultSubjectDAO * @since 1.2 */ @@ -174,7 +176,7 @@ protected SubjectContext createSubjectContext() { * @param info the {@code AuthenticationInfo} of a newly authenticated user. * @param existing the existing {@code Subject} instance that initiated the authentication attempt * @return the {@code Subject} instance that represents the context and session data for the newly - * authenticated subject. + * authenticated subject. */ protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) { SubjectContext context = createSubjectContext(); @@ -210,18 +212,18 @@ protected void rememberMeSuccessfulLogin(AuthenticationToken token, Authenticati try { rmm.onSuccessfulLogin(subject, token, info); } catch (Exception e) { - if (log.isWarnEnabled()) { - String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + - "] threw an exception during onSuccessfulLogin. RememberMe services will not be " + - "performed for account [" + info + "]."; - log.warn(msg, e); + if (LOGGER.isWarnEnabled()) { + String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + + "] threw an exception during onSuccessfulLogin. RememberMe services will not be " + + "performed for account [" + info + "]."; + LOGGER.warn(msg, e); } } } else { - if (log.isTraceEnabled()) { - log.trace("This " + getClass().getName() + " instance does not have a " + - "[" + RememberMeManager.class.getName() + "] instance configured. RememberMe services " + - "will not be performed for account [" + info + "]."); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("This " + getClass().getName() + " instance does not have a " + + "[" + RememberMeManager.class.getName() + "] instance configured. RememberMe services " + + "will not be performed for account [" + info + "]."); } } } @@ -232,11 +234,11 @@ protected void rememberMeFailedLogin(AuthenticationToken token, AuthenticationEx try { rmm.onFailedLogin(subject, token, ex); } catch (Exception e) { - if (log.isWarnEnabled()) { - String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + - "] threw an exception during onFailedLogin for AuthenticationToken [" + - token + "]."; - log.warn(msg, e); + if (LOGGER.isWarnEnabled()) { + String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + + "] threw an exception during onFailedLogin for AuthenticationToken [" + + token + "]."; + LOGGER.warn(msg, e); } } } @@ -248,11 +250,11 @@ protected void rememberMeLogout(Subject subject) { try { rmm.onLogout(subject); } catch (Exception e) { - if (log.isWarnEnabled()) { - String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + - "] threw an exception during onLogout for subject with principals [" + - (subject != null ? subject.getPrincipals() : null) + "]"; - log.warn(msg, e); + if (LOGGER.isWarnEnabled()) { + String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + + "] threw an exception during onLogout for subject with principals [" + + (subject != null ? subject.getPrincipals() : null) + "]"; + LOGGER.warn(msg, e); } } } @@ -277,12 +279,13 @@ public Subject login(Subject subject, AuthenticationToken token) throws Authenti try { onFailedLogin(token, ae, subject); } catch (Exception e) { - if (log.isInfoEnabled()) { - log.info("onFailedLogin method threw an " + - "exception. Logging and propagating original AuthenticationException.", e); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("onFailedLogin method threw an " + + "exception. Logging and propagating original AuthenticationException.", e); } } - throw ae; //propagate + //propagate + throw ae; } Subject loggedIn = createSubject(token, info, subject); @@ -414,10 +417,10 @@ protected void delete(Subject subject) { @SuppressWarnings({"unchecked"}) protected SubjectContext ensureSecurityManager(SubjectContext context) { if (context.resolveSecurityManager() != null) { - log.trace("Context already contains a SecurityManager instance. Returning."); + LOGGER.trace("Context already contains a SecurityManager instance. Returning."); return context; } - log.trace("No SecurityManager found in context. Adding self reference."); + LOGGER.trace("No SecurityManager found in context. Adding self reference."); context.setSecurityManager(this); return context; } @@ -438,19 +441,19 @@ protected SubjectContext ensureSecurityManager(SubjectContext context) { @SuppressWarnings({"unchecked"}) protected SubjectContext resolveSession(SubjectContext context) { if (context.resolveSession() != null) { - log.debug("Context already contains a session. Returning."); + LOGGER.debug("Context already contains a session. Returning."); return context; } try { - //Context couldn't resolve it directly, let's see if we can since we have direct access to + //Context couldn't resolve it directly, let's see if we can since we have direct access to //the session manager: Session session = resolveContextSession(context); if (session != null) { context.setSession(session); } } catch (InvalidSessionException e) { - log.debug("Resolved SubjectContext context session is invalid. Ignoring and creating an anonymous " + - "(session-less) Subject instance.", e); + LOGGER.debug("Resolved SubjectContext context session is invalid. Ignoring and creating an anonymous " + + "(session-less) Subject instance.", e); } return context; } @@ -496,13 +499,13 @@ protected SubjectContext resolvePrincipals(SubjectContext context) { PrincipalCollection principals = context.resolvePrincipals(); if (isEmpty(principals)) { - log.trace("No identity (PrincipalCollection) found in the context. Looking for a remembered identity."); + LOGGER.trace("No identity (PrincipalCollection) found in the context. Looking for a remembered identity."); principals = getRememberedIdentity(context); if (!isEmpty(principals)) { - log.debug("Found remembered PrincipalCollection. Adding to the context to be used " + - "for subject construction by the SubjectFactory."); + LOGGER.debug("Found remembered PrincipalCollection. Adding to the context to be used " + + "for subject construction by the SubjectFactory."); context.setPrincipals(principals); @@ -522,7 +525,7 @@ protected SubjectContext resolvePrincipals(SubjectContext context) { // bindPrincipalsToSession(principals, context); } else { - log.trace("No remembered identity found. Returning original context."); + LOGGER.trace("No remembered identity found. Returning original context."); } } @@ -555,8 +558,8 @@ public void logout(Subject subject) { PrincipalCollection principals = subject.getPrincipals(); if (principals != null && !principals.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug("Logging out subject with primary principal {}", principals.getPrimaryPrincipal()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Logging out subject with primary principal {}", principals.getPrimaryPrincipal()); } Authenticator authc = getAuthenticator(); if (authc instanceof LogoutAware) { @@ -567,18 +570,18 @@ public void logout(Subject subject) { try { delete(subject); } catch (Exception e) { - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { String msg = "Unable to cleanly unbind Subject. Ignoring (logging out)."; - log.debug(msg, e); + LOGGER.debug(msg, e); } } finally { try { stopSession(subject); } catch (Exception e) { - if (log.isDebugEnabled()) { - String msg = "Unable to cleanly stop Session for Subject [" + subject.getPrincipal() + "] " + - "Ignoring (logging out)."; - log.debug(msg, e); + if (LOGGER.isDebugEnabled()) { + String msg = "Unable to cleanly stop Session for Subject [" + subject.getPrincipal() + "] " + + "Ignoring (logging out)."; + LOGGER.debug(msg, e); } } } @@ -612,10 +615,10 @@ protected PrincipalCollection getRememberedIdentity(SubjectContext subjectContex try { return rmm.getRememberedPrincipals(subjectContext); } catch (Exception e) { - if (log.isWarnEnabled()) { - String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + - "] threw an exception during getRememberedPrincipals()."; - log.warn(msg, e); + if (LOGGER.isWarnEnabled()) { + String msg = "Delegate RememberMeManager instance of type [" + rmm.getClass().getName() + + "] threw an exception during getRememberedPrincipals()."; + LOGGER.warn(msg, e); } } } diff --git a/core/src/main/java/org/apache/shiro/mgt/DefaultSessionStorageEvaluator.java b/core/src/main/java/org/apache/shiro/mgt/DefaultSessionStorageEvaluator.java index b720ac6cdf..b36080e96b 100644 --- a/core/src/main/java/org/apache/shiro/mgt/DefaultSessionStorageEvaluator.java +++ b/core/src/main/java/org/apache/shiro/mgt/DefaultSessionStorageEvaluator.java @@ -73,7 +73,7 @@ public boolean isSessionStorageEnabled(Subject subject) { * authenticate on every request). * * @return {@code true} if any Subject's {@code Session} may be used to persist that {@code Subject}'s state, - * {@code false} otherwise. + * {@code false} otherwise. */ public boolean isSessionStorageEnabled() { return sessionStorageEnabled; diff --git a/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectDAO.java b/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectDAO.java index 06b4e463ab..354517369b 100644 --- a/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectDAO.java +++ b/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectDAO.java @@ -80,7 +80,7 @@ */ public class DefaultSubjectDAO implements SubjectDAO { - private static final Logger log = LoggerFactory.getLogger(DefaultSubjectDAO.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSubjectDAO.class); /** * Evaluator that determines if a Subject's session may be used to store the Subject's own state. @@ -112,7 +112,7 @@ protected boolean isSessionStorageEnabled(Subject subject) { * the Subject's session. The default instance is a {@link DefaultSessionStorageEvaluator}. * * @return the {@code SessionStorageEvaluator} that will determine if a {@code Subject}'s state may be persisted in - * the Subject's session. + * the Subject's session. * @see DefaultSessionStorageEvaluator */ public SessionStorageEvaluator getSessionStorageEvaluator() { @@ -145,8 +145,8 @@ public Subject save(Subject subject) { if (isSessionStorageEnabled(subject)) { saveToSession(subject); } else { - log.trace("Session storage of subject state for Subject [{}] has been disabled: identity and " + - "authentication state are expected to be initialized on every request or invocation.", subject); + LOGGER.trace("Session storage of subject state for Subject [{}] has been disabled: identity and " + + "authentication state are expected to be initialized on every request or invocation.", subject); } return subject; @@ -191,7 +191,7 @@ protected void mergePrincipals(Subject subject) { try { Field field = DelegatingSubject.class.getDeclaredField("principals"); field.setAccessible(true); - currentPrincipals = (PrincipalCollection)field.get(subject); + currentPrincipals = (PrincipalCollection) field.get(subject); } catch (Exception e) { throw new IllegalStateException("Unable to access DelegatingSubject principals property.", e); } diff --git a/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java b/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java index 7e41abbcdf..618a44146b 100644 --- a/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java +++ b/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java @@ -26,7 +26,8 @@ /** - * Default {@link SubjectFactory SubjectFactory} implementation that creates {@link org.apache.shiro.subject.support.DelegatingSubject DelegatingSubject} + * Default {@link SubjectFactory SubjectFactory} implementation that creates + * {@link org.apache.shiro.subject.support.DelegatingSubject DelegatingSubject} * instances. * * @since 1.0 @@ -49,7 +50,7 @@ public Subject createSubject(SubjectContext context) { /** * @deprecated since 1.2 - override {@link #createSubject(org.apache.shiro.subject.SubjectContext)} directly if you - * need to instantiate a custom {@link Subject} class. + * need to instantiate a custom {@link Subject} class. */ @Deprecated protected Subject newSubjectInstance(PrincipalCollection principals, boolean authenticated, String host, diff --git a/core/src/main/java/org/apache/shiro/mgt/RealmSecurityManager.java b/core/src/main/java/org/apache/shiro/mgt/RealmSecurityManager.java index aaca9d8b22..748ddd169a 100644 --- a/core/src/main/java/org/apache/shiro/mgt/RealmSecurityManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/RealmSecurityManager.java @@ -139,9 +139,9 @@ protected void applyEventBusToRealms() { EventBus eventBus = getEventBus(); Collection realms = getRealms(); if (eventBus != null && realms != null && !realms.isEmpty()) { - for(Realm realm : realms) { + for (Realm realm : realms) { if (realm instanceof EventBusAware) { - ((EventBusAware)realm).setEventBus(eventBus); + ((EventBusAware) realm).setEventBus(eventBus); } } } @@ -149,8 +149,8 @@ protected void applyEventBusToRealms() { /** * Simply calls {@link #applyCacheManagerToRealms() applyCacheManagerToRealms()} to allow the - * newly set {@link org.apache.shiro.cache.CacheManager CacheManager} to be propagated to the internal collection of Realm - * that would need to use it. + * newly set {@link org.apache.shiro.cache.CacheManager CacheManager} to be propagated to the + * internal collection of Realm that would need to use it. */ protected void afterCacheManagerSet() { super.afterCacheManagerSet(); 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..e2180888e8 100644 --- a/core/src/main/java/org/apache/shiro/mgt/SessionsSecurityManager.java +++ b/core/src/main/java/org/apache/shiro/mgt/SessionsSecurityManager.java @@ -98,9 +98,9 @@ public SessionManager getSessionManager() { } /** - * Calls {@link org.apache.shiro.mgt.AuthorizingSecurityManager#afterCacheManagerSet() super.afterCacheManagerSet()} and then immediately calls - * {@link #applyCacheManagerToSessionManager() applyCacheManagerToSessionManager()} to ensure the - * CacheManager is applied to the SessionManager as necessary. + * Calls {@link org.apache.shiro.mgt.AuthorizingSecurityManager#afterCacheManagerSet() super.afterCacheManagerSet()} + * and then immediately calls {@link #applyCacheManagerToSessionManager() applyCacheManagerToSessionManager()} + * to ensure the CacheManager is applied to the SessionManager as necessary. */ @Override protected void afterCacheManagerSet() { @@ -144,7 +144,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..58ea1e9652 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 authenticat * set. * * @return a {@link Cache} instance to use for authentication caching, or {@code null} if no cache has been - * set. + * set. * @see #setAuthenticationCache(org.apache.shiro.cache.Cache) * @see #isAuthenticationCachingEnabled() * @since 1.2 @@ -284,7 +282,7 @@ public Cache getAuthenticationCache() { * of this page in the class-level JavaDoc. * * @return the name of a {@link Cache} to lookup from any available {@link #getCacheManager() cacheManager} if - * a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}. + * a cache is not explicitly configured via {@link #setAuthenticationCache(org.apache.shiro.cache.Cache)}. * @see #isAuthenticationCachingEnabled() * @since 1.2 */ @@ -455,13 +453,13 @@ private Cache getAuthenticationCacheLazy() { if (this.authenticationCache == null) { - log.trace("No authenticationCache instance set. Checking for a cacheManager..."); + LOGGER.trace("No authenticationCache instance set. Checking for a cacheManager..."); CacheManager cacheManager = getCacheManager(); if (cacheManager != null) { String cacheName = getAuthenticationCacheName(); - log.debug("CacheManager [{}] configured. Building authentication cache '{}'", cacheManager, cacheName); + LOGGER.debug("CacheManager [{}] configured. Building authentication cache '{}'", cacheManager, cacheName); this.authenticationCache = cacheManager.getCache(cacheName); } } @@ -475,7 +473,7 @@ private Cache getAuthenticationCacheLazy() { * * @param token the token submitted during the authentication attempt. * @return any cached AuthenticationInfo corresponding to the specified token or {@code null} if there currently - * isn't any cached data. + * isn't any cached data. * @since 1.2 */ private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token) { @@ -483,13 +481,13 @@ private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token Cache cache = getAvailableAuthenticationCache(); if (cache != null && token != null) { - log.trace("Attempting to retrieve the AuthenticationInfo from cache."); + LOGGER.trace("Attempting to retrieve the AuthenticationInfo from cache."); Object key = getAuthenticationCacheKey(token); info = cache.get(key); if (info == null) { - log.trace("No AuthorizationInfo found in cache for key [{}]", key); + LOGGER.trace("No AuthorizationInfo found in cache for key [{}]", key); } else { - log.trace("Found cached AuthorizationInfo for key [{}]", key); + LOGGER.trace("Found cached AuthorizationInfo for key [{}]", key); } } @@ -498,7 +496,7 @@ private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token /** * Caches the specified info if authentication caching - * {@link #isAuthenticationCachingEnabled(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) isEnabled} + * {@link #isAuthenticationCachingEnabled(AuthenticationToken, AuthenticationInfo) isEnabled} * for the specific token/info pair and a cache instance is available to be used. * * @param token the authentication token submitted which resulted in a successful authentication attempt. @@ -507,7 +505,7 @@ private AuthenticationInfo getCachedAuthenticationInfo(AuthenticationToken token */ private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, AuthenticationInfo info) { if (!isAuthenticationCachingEnabled(token, info)) { - log.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token); + LOGGER.debug("AuthenticationInfo caching is disabled for info [{}]. Submitted token: [{}].", info, token); //return quietly, caching is disabled for this token/info pair: return; } @@ -516,7 +514,7 @@ private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, Authen if (cache != null) { Object key = getAuthenticationCacheKey(token); cache.put(key, info); - log.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info); + LOGGER.trace("Cached AuthenticationInfo for continued authentication. key=[{}], value=[{}].", key, info); } } @@ -532,7 +530,7 @@ private void cacheAuthenticationInfoIfPossible(AuthenticationToken token, Authen * @param info the {@code AuthenticationInfo} acquired from data source lookup via * {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} * @return {@code true} if authentication caching should be utilized based on the specified - * {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise. + * {@link AuthenticationToken} and/or {@link AuthenticationInfo}, {@code false} otherwise. * @since 1.2 */ protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, AuthenticationInfo info) { @@ -548,7 +546,7 @@ protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, Auth *

  • If there is no cached {@link AuthenticationInfo} found, delegate to the * {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} method to perform the actual * lookup. If authentication caching is enabled and possible, any returned info object will be - * {@link #cacheAuthenticationInfoIfPossible(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo) cached} + * {@link #cacheAuthenticationInfoIfPossible(AuthenticationToken, AuthenticationInfo) cached} * to be used in future authentication attempts.
  • *
  • If an AuthenticationInfo instance is not found in the cache or by lookup, {@code null} is returned to * indicate an account cannot be found.
  • @@ -560,7 +558,7 @@ protected boolean isAuthenticationCachingEnabled(AuthenticationToken token, Auth * * @param token the submitted account principal and credentials. * @return the AuthenticationInfo corresponding to the given {@code token}, or {@code null} if no - * AuthenticationInfo could be found. + * AuthenticationInfo could be found. * @throws AuthenticationException if authentication failed. */ public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { @@ -569,18 +567,18 @@ public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); - log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); + LOGGER.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { cacheAuthenticationInfoIfPossible(token, info); } } else { - log.debug("Using cached authentication info [{}] to perform credentials matching.", info); + LOGGER.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { assertCredentialsMatch(token, info); } else { - log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); + LOGGER.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; @@ -603,9 +601,9 @@ protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationI throw new IncorrectCredentialsException(msg); } } else { - throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " + - "credentials during authentication. If you do not wish for credentials to be examined, you " + - "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance."); + throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " + + "credentials during authentication. If you do not wish for credentials to be examined, you " + + "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance."); } } @@ -706,7 +704,7 @@ protected void clearCachedAuthenticationInfo(PrincipalCollection principals) { * * @param token the authentication token containing the user's principal and credentials. * @return an {@link AuthenticationInfo} object containing account data resulting from the - * authentication ONLY if the lookup is successful (i.e. account exists and is valid, etc.) + * authentication ONLY if the lookup is successful (i.e. account exists and is valid, etc.) * @throws AuthenticationException if there is an error acquiring data or performing * realm-specific authentication logic for the specified token */ diff --git a/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java b/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java index 347e7e4ece..aa702c2eb3 100644 --- a/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java @@ -19,8 +19,16 @@ package org.apache.shiro.realm; import org.apache.shiro.authc.credential.CredentialsMatcher; -import org.apache.shiro.authz.*; -import org.apache.shiro.authz.permission.*; +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.Authorizer; +import org.apache.shiro.authz.Permission; +import org.apache.shiro.authz.UnauthorizedException; +import org.apache.shiro.authz.permission.PermissionResolver; +import org.apache.shiro.authz.permission.PermissionResolverAware; +import org.apache.shiro.authz.permission.RolePermissionResolver; +import org.apache.shiro.authz.permission.RolePermissionResolverAware; +import org.apache.shiro.authz.permission.WildcardPermissionResolver; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.subject.PrincipalCollection; @@ -30,10 +38,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; - /** * An {@code AuthorizingRealm} extends the {@code AuthenticatingRealm}'s capabilities by adding Authorization * (access control) support. @@ -45,23 +59,23 @@ *

    * If you find that you do not want to utilize the {@link AuthorizationInfo AuthorizationInfo} construct, * you are of course free to subclass the {@link AuthenticatingRealm AuthenticatingRealm} directly instead and - * implement the remaining Realm interface methods directly. You might do this if you want have better control + * implement the remaining Realm interface methods directly. You might do this if you want to have better control * over how the Role and Permission checks occur for your specific data source. However, using AuthorizationInfo - * (and its default implementation {@link org.apache.shiro.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}) is sufficient in the large + * (and its default implementation {@link org.apache.shiro.authz.SimpleAuthorizationInfo SimpleAuthorizationInfo}) + * is sufficient in the large * majority of Realm cases. * * @see org.apache.shiro.authz.SimpleAuthorizationInfo * @since 0.2 */ +@SuppressWarnings({"checkstyle:MethodCount"}) public abstract class AuthorizingRealm extends AuthenticatingRealm implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware { - //TODO - complete JavaDoc - /*------------------------------------------- | C O N S T A N T S | ============================================*/ - private static final Logger log = LoggerFactory.getLogger(AuthorizingRealm.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizingRealm.class); /** * The default suffix appended to the realm name for caching AuthorizationInfo instances. @@ -102,8 +116,12 @@ public AuthorizingRealm(CredentialsMatcher matcher) { public AuthorizingRealm(CacheManager cacheManager, CredentialsMatcher matcher) { super(); - if (cacheManager != null) setCacheManager(cacheManager); - if (matcher != null) setCredentialsMatcher(matcher); + if (cacheManager != null) { + setCacheManager(cacheManager); + } + if (matcher != null) { + setCredentialsMatcher(matcher); + } this.authorizationCachingEnabled = true; this.permissionResolver = new WildcardPermissionResolver(); @@ -179,7 +197,9 @@ public PermissionResolver getPermissionResolver() { } public void setPermissionResolver(PermissionResolver permissionResolver) { - if (permissionResolver == null) throw new IllegalArgumentException("Null PermissionResolver is not allowed"); + if (permissionResolver == null) { + throw new IllegalArgumentException("Null PermissionResolver is not allowed"); + } this.permissionResolver = permissionResolver; } @@ -231,23 +251,23 @@ private Cache getAuthorizationCacheLazy() { if (this.authorizationCache == null) { - if (log.isDebugEnabled()) { - log.debug("No authorizationCache instance set. Checking for a cacheManager..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No authorizationCache instance set. Checking for a cacheManager..."); } CacheManager cacheManager = getCacheManager(); if (cacheManager != null) { String cacheName = getAuthorizationCacheName(); - if (log.isDebugEnabled()) { - log.debug("CacheManager [" + cacheManager + "] has been configured. Building " + - "authorization cache named [" + cacheName + "]"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CacheManager [" + cacheManager + "] has been configured. Building " + + "authorization cache named [" + cacheName + "]"); } this.authorizationCache = cacheManager.getCache(cacheName); } else { - if (log.isDebugEnabled()) { - log.debug("No cache or cacheManager properties have been set. Authorization cache cannot " + - "be obtained."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No cache or cacheManager properties have been set. Authorization cache cannot " + + "be obtained."); } } } @@ -306,7 +326,7 @@ private Cache getAvailableAuthorizationCache() { * @param principals the corresponding Subject's identifying principals with which to look up the Subject's * {@code AuthorizationInfo}. * @return the authorization information for the account associated with the specified {@code principals}, - * or {@code null} if no account could be found. + * or {@code null} if no account could be found. */ protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { @@ -316,22 +336,22 @@ protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) AuthorizationInfo info = null; - if (log.isTraceEnabled()) { - log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); } Cache cache = getAvailableAuthorizationCache(); if (cache != null) { - if (log.isTraceEnabled()) { - log.trace("Attempting to retrieve the AuthorizationInfo from cache."); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Attempting to retrieve the AuthorizationInfo from cache."); } Object key = getAuthorizationCacheKey(principals); info = cache.get(key); - if (log.isTraceEnabled()) { + if (LOGGER.isTraceEnabled()) { if (info == null) { - log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); + LOGGER.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); } else { - log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); + LOGGER.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); } } } @@ -342,8 +362,8 @@ protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) info = doGetAuthorizationInfo(principals); // If the info is not null and the cache has been created, then cache the authorization info. if (info != null && cache != null) { - if (log.isTraceEnabled()) { - log.trace("Caching authorization info for principals: [" + principals + "]."); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Caching authorization info for principals: [" + principals + "]."); } Object key = getAuthorizationCacheKey(principals); cache.put(key, info); @@ -559,7 +579,8 @@ public void checkPermissions(PrincipalCollection subjectIdentifier, String... pe } } - public void checkPermissions(PrincipalCollection principal, Collection permissions) throws AuthorizationException { + public void checkPermissions(PrincipalCollection principal, + Collection permissions) throws AuthorizationException { AuthorizationInfo info = getAuthorizationInfo(principal); checkPermissions(permissions, info); } diff --git a/core/src/main/java/org/apache/shiro/realm/CachingRealm.java b/core/src/main/java/org/apache/shiro/realm/CachingRealm.java index 4f9fffedee..fbe47cf3ba 100644 --- a/core/src/main/java/org/apache/shiro/realm/CachingRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/CachingRealm.java @@ -47,9 +47,7 @@ */ public abstract class CachingRealm implements Realm, Nameable, CacheManagerAware, LogoutAware { - private static final Logger log = LoggerFactory.getLogger(CachingRealm.class); - - //TODO - complete JavaDoc + private static final Logger LOGGER = LoggerFactory.getLogger(CachingRealm.class); private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger(); @@ -78,7 +76,7 @@ public CachingRealm() { * caching is disabled. * * @return the CacheManager used for data caching to reduce EIS round trips, or null if - * caching is disabled. + * caching is disabled. */ public CacheManager getCacheManager() { return this.cacheManager; @@ -105,7 +103,7 @@ public void setCacheManager(CacheManager cacheManager) { * manage account data in memory already lookups would already be as efficient as possible. * * @return {@code true} if caching will be globally enabled if a {@link CacheManager} has been - * configured, {@code false} otherwise + * configured, {@code false} otherwise */ public boolean isCachingEnabled() { return cachingEnabled; @@ -168,7 +166,7 @@ private static boolean isEmpty(PrincipalCollection pc) { protected void clearCache(PrincipalCollection principals) { if (!isEmpty(principals)) { doClearCache(principals); - log.trace("Cleared cache entries for account with principals [{}]", principals); + LOGGER.trace("Cleared cache entries for account with principals [{}]", principals); } } @@ -196,7 +194,7 @@ protected void doClearCache(PrincipalCollection principals) { * * @param principals the PrincipalCollection holding all principals (from all realms) associated with a single Subject. * @return the 'primary' principal attributed to this particular realm, or the fallback 'master' principal if it - * exists, or if not {@code null}. + * exists, or if not {@code null}. * @since 1.2 */ protected Object getAvailablePrincipal(PrincipalCollection principals) { diff --git a/core/src/main/java/org/apache/shiro/realm/Realm.java b/core/src/main/java/org/apache/shiro/realm/Realm.java index 3889fa6c77..0a1430f467 100644 --- a/core/src/main/java/org/apache/shiro/realm/Realm.java +++ b/core/src/main/java/org/apache/shiro/realm/Realm.java @@ -51,7 +51,8 @@ * practically any application environment. * *

    Most users will not implement the Realm interface directly, but will extend one of the subclasses, - * {@link org.apache.shiro.realm.AuthenticatingRealm AuthenticatingRealm} or {@link org.apache.shiro.realm.AuthorizingRealm}, greatly reducing the effort required + * {@link org.apache.shiro.realm.AuthenticatingRealm AuthenticatingRealm} or + * {@link org.apache.shiro.realm.AuthorizingRealm}, greatly reducing the effort required * to implement a Realm from scratch.

    * * @see org.apache.shiro.realm.CachingRealm CachingRealm @@ -80,7 +81,7 @@ public interface Realm { * * @param token the AuthenticationToken submitted for the authentication attempt * @return true if this realm can/will authenticate Subjects represented by specified token, - * false otherwise. + * false otherwise. */ boolean supports(AuthenticationToken token); @@ -95,10 +96,10 @@ public interface Realm { * * @param token the application-specific representation of an account principal and credentials. * @return the authentication information for the account associated with the specified token, - * or null if no account could be found. - * @throws org.apache.shiro.authc.AuthenticationException - * if there is an error obtaining or constructing an AuthenticationInfo object based on the - * specified token or implementation-specific login behavior fails. + * or null if no account could be found. + * @throws org.apache.shiro.authc.AuthenticationException if there is an error obtaining or constructing + * an AuthenticationInfo objectbased on the specified token + * or implementation-specific login behavior fails. */ AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; diff --git a/core/src/main/java/org/apache/shiro/realm/RealmFactory.java b/core/src/main/java/org/apache/shiro/realm/RealmFactory.java index b360a5b432..2c35b6e0af 100644 --- a/core/src/main/java/org/apache/shiro/realm/RealmFactory.java +++ b/core/src/main/java/org/apache/shiro/realm/RealmFactory.java @@ -46,7 +46,7 @@ public interface RealmFactory { * {@link java.util.Iterator Iterator} determines the order in which Realms are used. * * @return the Collection of Realms that the application's SecurityManager will use - * for security data access. + * for security data access. */ Collection getRealms(); diff --git a/core/src/main/java/org/apache/shiro/realm/SimpleAccountRealm.java b/core/src/main/java/org/apache/shiro/realm/SimpleAccountRealm.java index 2542b04516..e9347da53f 100644 --- a/core/src/main/java/org/apache/shiro/realm/SimpleAccountRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/SimpleAccountRealm.java @@ -50,17 +50,24 @@ */ public class SimpleAccountRealm extends AuthorizingRealm { - //TODO - complete JavaDoc - protected final Map users; //username-to-SimpleAccount - protected final Map roles; //roleName-to-SimpleRole - protected final ReadWriteLock USERS_LOCK; - protected final ReadWriteLock ROLES_LOCK; + /** + * username-to-SimpleAccount. + */ + protected final Map users; + + /** + * roleName-to-SimpleRole. + */ + protected final Map roles; + + protected final ReadWriteLock usersLock; + protected final ReadWriteLock rolesLock; public SimpleAccountRealm() { this.users = new LinkedHashMap(); this.roles = new LinkedHashMap(); - USERS_LOCK = new ReentrantReadWriteLock(); - ROLES_LOCK = new ReentrantReadWriteLock(); + usersLock = new ReentrantReadWriteLock(); + rolesLock = new ReentrantReadWriteLock(); //SimpleAccountRealms are memory-only realms - no need for an additional cache mechanism since we're //already as memory-efficient as we can be: setCachingEnabled(false); @@ -72,11 +79,11 @@ public SimpleAccountRealm(String name) { } protected SimpleAccount getUser(String username) { - USERS_LOCK.readLock().lock(); + usersLock.readLock().lock(); try { return this.users.get(username); } finally { - USERS_LOCK.readLock().unlock(); + usersLock.readLock().unlock(); } } @@ -104,20 +111,20 @@ protected String getUsername(PrincipalCollection principals) { protected void add(SimpleAccount account) { String username = getUsername(account); - USERS_LOCK.writeLock().lock(); + usersLock.writeLock().lock(); try { this.users.put(username, account); } finally { - USERS_LOCK.writeLock().unlock(); + usersLock.writeLock().unlock(); } } protected SimpleRole getRole(String rolename) { - ROLES_LOCK.readLock().lock(); + rolesLock.readLock().lock(); try { return roles.get(rolename); } finally { - ROLES_LOCK.readLock().unlock(); + rolesLock.readLock().unlock(); } } @@ -130,11 +137,11 @@ public void addRole(String name) { } protected void add(SimpleRole role) { - ROLES_LOCK.writeLock().lock(); + rolesLock.writeLock().lock(); try { roles.put(role.getName(), role); } finally { - ROLES_LOCK.writeLock().unlock(); + rolesLock.writeLock().unlock(); } } @@ -176,11 +183,11 @@ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = getUsername(principals); - USERS_LOCK.readLock().lock(); + usersLock.readLock().lock(); try { return this.users.get(username); } finally { - USERS_LOCK.readLock().unlock(); + usersLock.readLock().unlock(); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java b/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java index a24ec248d9..144208dde8 100644 --- a/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealm.java @@ -39,7 +39,12 @@ import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.LdapContext; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; /** @@ -52,13 +57,11 @@ */ public class ActiveDirectoryRealm extends AbstractLdapRealm { - //TODO - complete JavaDoc - /*-------------------------------------------- | C O N S T A N T S | ============================================*/ - private static final Logger log = LoggerFactory.getLogger(ActiveDirectoryRealm.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ActiveDirectoryRealm.class); private static final String ROLE_NAMES_DELIMETER = ","; @@ -85,11 +88,10 @@ public void setGroupRolesMap(Map groupRolesMap) { | M E T H O D S | ============================================*/ - /** * Builds an {@link AuthenticationInfo} object by querying the active directory LDAP context for the * specified username. This method binds to the LDAP server using the provided username and password - - * which if successful, indicates that the password is correct. + * which, if successful, indicates that the password is correct. *

    * This method can be overridden by subclasses to query the LDAP server in a more complex way. * @@ -98,7 +100,8 @@ public void setGroupRolesMap(Map groupRolesMap) { * @return an {@link AuthenticationInfo} instance containing information retrieved from LDAP. * @throws NamingException if any LDAP errors occur during the search. */ - protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException { + protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) + throws NamingException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; @@ -133,7 +136,8 @@ protected AuthenticationInfo buildAuthenticationInfo(String username, char[] pas * @return the AuthorizationInfo for the given Subject principal. * @throws NamingException if an error occurs when searching the LDAP server. */ - protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException { + protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, + LdapContextFactory ldapContextFactory) throws NamingException { String username = (String) getAvailablePrincipal(principals); @@ -163,19 +167,20 @@ protected Set getRoleNamesForUser(String username, LdapContext ldapConte searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); String userPrincipalName = username; - if (principalSuffix != null && !userPrincipalName.toLowerCase(Locale.ROOT).endsWith(principalSuffix.toLowerCase(Locale.ROOT))) { + if (principalSuffix != null + && !userPrincipalName.toLowerCase(Locale.ROOT).endsWith(principalSuffix.toLowerCase(Locale.ROOT))) { userPrincipalName += principalSuffix; } - Object[] searchArguments = new Object[]{userPrincipalName}; + Object[] searchArguments = new Object[] {userPrincipalName}; NamingEnumeration answer = ldapContext.search(searchBase, searchFilter, searchArguments, searchControls); while (answer.hasMoreElements()) { SearchResult sr = (SearchResult) answer.next(); - if (log.isDebugEnabled()) { - log.debug("Retrieving group names for user [" + sr.getName() + "]"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Retrieving group names for user [" + sr.getName() + "]"); } Attributes attrs = sr.getAttributes(); @@ -189,8 +194,8 @@ protected Set getRoleNamesForUser(String username, LdapContext ldapConte Collection groupNames = LdapUtils.getAllAttributeValues(attr); - if (log.isDebugEnabled()) { - log.debug("Groups found for user [" + username + "]: " + groupNames); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Groups found for user [" + username + "]: " + groupNames); } Collection rolesForGroups = getRoleNamesForGroups(groupNames); @@ -218,8 +223,8 @@ protected Collection getRoleNamesForGroups(Collection groupNames if (strRoleNames != null) { for (String roleName : strRoleNames.split(ROLE_NAMES_DELIMETER)) { - if (log.isDebugEnabled()) { - log.debug("User is member of group [" + groupName + "] so adding role [" + roleName + "]"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("User is member of group [" + groupName + "] so adding role [" + roleName + "]"); } roleNames.add(roleName); diff --git a/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java b/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java index 8388ae0ec1..2d476ac14d 100644 --- a/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java @@ -46,7 +46,6 @@ import java.util.LinkedHashSet; import java.util.Set; - /** * Realm that allows authentication and authorization via JDBC calls. The default queries suggest a potential schema * for retrieving the user's password for authentication, and querying for a user's roles and permissions. The @@ -55,7 +54,8 @@ * If the default implementation * of authentication and authorization cannot handle your schema, this class can be subclassed and the * appropriate methods overridden. (usually {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)}, - * {@link #getRoleNamesForUser(java.sql.Connection,String)}, and/or {@link #getPermissions(java.sql.Connection,String,java.util.Collection)} + * {@link #getRoleNamesForUser(java.sql.Connection, String)}, + * and/or {@link #getPermissions(java.sql.Connection, String, java.util.Collection)} *

    * This realm supports caching by extending from {@link org.apache.shiro.realm.AuthorizingRealm}. * @@ -63,8 +63,6 @@ */ public class JdbcRealm extends AuthorizingRealm { - //TODO - complete JavaDoc - /*-------------------------------------------- | C O N S T A N T S | ============================================*/ @@ -72,11 +70,12 @@ public class JdbcRealm extends AuthorizingRealm { * The default query used to retrieve account data for the user. */ protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?"; - + /** * The default query used to retrieve account data for the user when {@link #saltStyle} is COLUMN. */ - protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?"; + protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY + = "select password, password_salt from users where username = ?"; /** * The default query used to retrieve the roles that apply to a user. @@ -88,17 +87,17 @@ public class JdbcRealm extends AuthorizingRealm { */ protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?"; - private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class); - + private static final Logger LOGGER = LoggerFactory.getLogger(JdbcRealm.class); + /** * Password hash salt configuration.

      - *
    • NO_SALT - password hashes are not salted.
    • - *
    • CRYPT - password hashes are stored in unix crypt format.
    • - *
    • COLUMN - salt is in a separate column in the database.
    • - *
    • EXTERNAL - salt is not stored in the database. {@link #getSaltForUser(String)} will be called - * to get the salt
    + *
  • NO_SALT - password hashes are not salted.
  • + *
  • CRYPT - password hashes are stored in unix crypt format.
  • + *
  • COLUMN - salt is in a separate column in the database.
  • + *
  • EXTERNAL - salt is not stored in the database. {@link #getSaltForUser(String)} will be called + * to get the salt
  • */ - public enum SaltStyle {NO_SALT, CRYPT, COLUMN, EXTERNAL}; + public enum SaltStyle { NO_SALT, CRYPT, COLUMN, EXTERNAL } /*-------------------------------------------- | I N S T A N C E V A R I A B L E S | @@ -111,8 +110,8 @@ public enum SaltStyle {NO_SALT, CRYPT, COLUMN, EXTERNAL}; protected String permissionsQuery = DEFAULT_PERMISSIONS_QUERY; - protected boolean permissionsLookupEnabled = false; - + protected boolean permissionsLookupEnabled; + protected SaltStyle saltStyle = SaltStyle.NO_SALT; protected boolean saltIsBase64Encoded = true; @@ -124,7 +123,7 @@ public enum SaltStyle {NO_SALT, CRYPT, COLUMN, EXTERNAL}; /*-------------------------------------------- | A C C E S S O R S / M O D I F I E R S | ============================================*/ - + /** * Sets the datasource that should be used to retrieve connections used by this realm. * @@ -139,7 +138,7 @@ public void setDataSource(DataSource dataSource) { * implementation, this query must take the user's username as a single parameter and return a single result * with the user's password as the first column. If you require a solution that does not match this query * structure, you can override {@link #doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)} or - * just {@link #getPasswordForUser(java.sql.Connection,String)} + * just {@link #getPasswordForUser(java.sql.Connection, String)} * * @param authenticationQuery the query to use for authentication. * @see #DEFAULT_AUTHENTICATION_QUERY @@ -153,7 +152,7 @@ public void setAuthenticationQuery(String authenticationQuery) { * implementation, this query must take the user's username as a single parameter and return a row * per role with a single column containing the role name. If you require a solution that does not match this query * structure, you can override {@link #doGetAuthorizationInfo(PrincipalCollection)} or just - * {@link #getRoleNamesForUser(java.sql.Connection,String)} + * {@link #getRoleNamesForUser(java.sql.Connection, String)} * * @param userRolesQuery the query to use for retrieving a user's roles. * @see #DEFAULT_USER_ROLES_QUERY @@ -168,7 +167,7 @@ public void setUserRolesQuery(String userRolesQuery) { * per permission with a single column, containing the permission. * If you require a solution that does not match this query * structure, you can override {@link #doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)} or just - * {@link #getPermissions(java.sql.Connection,String,java.util.Collection)}

    + * {@link #getPermissions(java.sql.Connection, String, java.util.Collection)}

    *

    * Permissions are only retrieved if you set {@link #permissionsLookupEnabled} to true. Otherwise, * this query is ignored. @@ -191,10 +190,10 @@ public void setPermissionsQuery(String permissionsQuery) { public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) { this.permissionsLookupEnabled = permissionsLookupEnabled; } - + /** * Sets the salt style. See {@link #saltStyle}. - * + * * @param saltStyle new SaltStyle to set. */ public void setSaltStyle(SaltStyle saltStyle) { @@ -237,21 +236,23 @@ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) String password = null; String salt = null; switch (saltStyle) { - case NO_SALT: - password = getPasswordForUser(conn, username)[0]; - break; - case CRYPT: - // TODO: separate password and hash from getPasswordForUser[0] - throw new ConfigurationException("Not implemented yet"); - //break; - case COLUMN: - String[] queryResults = getPasswordForUser(conn, username); - password = queryResults[0]; - salt = queryResults[1]; - break; - case EXTERNAL: - password = getPasswordForUser(conn, username)[0]; - salt = getSaltForUser(username); + case NO_SALT: + password = getPasswordForUser(conn, username)[0]; + break; + case CRYPT: + // TODO: separate password and hash from getPasswordForUser[0] + throw new ConfigurationException("Not implemented yet"); + //break; + case COLUMN: + String[] queryResults = getPasswordForUser(conn, username); + password = queryResults[0]; + salt = queryResults[1]; + break; + case EXTERNAL: + password = getPasswordForUser(conn, username)[0]; + salt = getSaltForUser(username); + break; + default: } if (password == null) { @@ -259,19 +260,19 @@ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) } info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName()); - + if (salt != null) { - if (saltStyle == SaltStyle.COLUMN && saltIsBase64Encoded) { + if (saltStyle == SaltStyle.COLUMN && saltIsBase64Encoded) { info.setCredentialsSalt(ByteSource.Util.bytes(Base64.decode(salt))); - } else { + } else { info.setCredentialsSalt(ByteSource.Util.bytes(salt)); - } + } } } catch (SQLException e) { final String message = "There was a SQL error while authenticating user [" + username + "]"; - if (log.isErrorEnabled()) { - log.error(message, e); + if (LOGGER.isErrorEnabled()) { + LOGGER.error(message, e); } // Rethrow any SQL errors as an authentication exception @@ -288,16 +289,16 @@ private String[] getPasswordForUser(Connection conn, String username) throws SQL String[] result; boolean returningSeparatedSalt = false; switch (saltStyle) { - case NO_SALT: - case CRYPT: - case EXTERNAL: - result = new String[1]; - break; - default: - result = new String[2]; - returningSeparatedSalt = true; + case NO_SALT: + case CRYPT: + case EXTERNAL: + result = new String[1]; + break; + default: + result = new String[2]; + returningSeparatedSalt = true; } - + PreparedStatement ps = null; ResultSet rs = null; try { @@ -313,7 +314,8 @@ private String[] getPasswordForUser(Connection conn, String username) throws SQL // Check to ensure only one row is processed if (foundResult) { - throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique."); + throw new AuthenticationException("More than one user row found for user [" + + username + "]. Usernames must be unique."); } result[0] = rs.getString(1); @@ -361,8 +363,8 @@ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal } catch (SQLException e) { final String message = "There was a SQL error while authorizing user [" + username + "]"; - if (log.isErrorEnabled()) { - log.error(message, e); + if (LOGGER.isErrorEnabled()) { + LOGGER.error(message, e); } // Rethrow any SQL errors as an authorization exception @@ -397,8 +399,8 @@ protected Set getRoleNamesForUser(Connection conn, String username) thro if (roleName != null) { roleNames.add(roleName); } else { - if (log.isWarnEnabled()) { - log.warn("Null role name found while retrieving role names for user [" + username + "]"); + if (LOGGER.isWarnEnabled()) { + LOGGER.warn("Null role name found while retrieving role names for user [" + username + "]"); } } } @@ -443,7 +445,7 @@ protected Set getPermissions(Connection conn, String username, Collectio return permissions; } - + protected String getSaltForUser(String username) { return username; } diff --git a/core/src/main/java/org/apache/shiro/realm/jdbc/package-info.java b/core/src/main/java/org/apache/shiro/realm/jdbc/package-info.java index af7be66ef1..40c469f043 100644 --- a/core/src/main/java/org/apache/shiro/realm/jdbc/package-info.java +++ b/core/src/main/java/org/apache/shiro/realm/jdbc/package-info.java @@ -16,8 +16,9 @@ * specific language governing permissions and limitations * under the License. */ + /** - * Realms that acquire security data from an RDBMS (Relational Database Management System) using the + * Realms that acquire security data from an RDBMS (Relational Database Management System) using the * JDBC API. */ package org.apache.shiro.realm.jdbc; diff --git a/core/src/main/java/org/apache/shiro/realm/jndi/JndiRealmFactory.java b/core/src/main/java/org/apache/shiro/realm/jndi/JndiRealmFactory.java index 45144d3251..6ca774fb35 100644 --- a/core/src/main/java/org/apache/shiro/realm/jndi/JndiRealmFactory.java +++ b/core/src/main/java/org/apache/shiro/realm/jndi/JndiRealmFactory.java @@ -40,7 +40,7 @@ */ public class JndiRealmFactory extends JndiLocator implements RealmFactory { - Collection jndiNames = null; + Collection jndiNames; /** * Returns the JNDI names that will be used to look up Realm(s) from JNDI. @@ -80,8 +80,8 @@ public void setJndiNames(Collection jndiNames) { public void setJndiNames(String commaDelimited) throws IllegalStateException { String arg = StringUtils.clean(commaDelimited); if (arg == null) { - String msg = "One or more comma-delimited jndi names must be specified for the " + - getClass().getName() + " to locate Realms."; + String msg = "One or more comma-delimited jndi names must be specified for the " + + getClass().getName() + " to locate Realms."; throw new IllegalStateException(msg); } String[] names = StringUtils.tokenizeToStringArray(arg, ","); @@ -101,8 +101,8 @@ public void setJndiNames(String commaDelimited) throws IllegalStateException { public Collection getRealms() throws IllegalStateException { Collection jndiNames = getJndiNames(); if (jndiNames == null || jndiNames.isEmpty()) { - String msg = "One or more jndi names must be specified for the " + - getClass().getName() + " to locate Realms."; + String msg = "One or more jndi names must be specified for the " + + getClass().getName() + " to locate Realms."; throw new IllegalStateException(msg); } List realms = new ArrayList(jndiNames.size()); diff --git a/core/src/main/java/org/apache/shiro/realm/jndi/package-info.java b/core/src/main/java/org/apache/shiro/realm/jndi/package-info.java index 4aa3f9317f..fcd9cb1dd0 100644 --- a/core/src/main/java/org/apache/shiro/realm/jndi/package-info.java +++ b/core/src/main/java/org/apache/shiro/realm/jndi/package-info.java @@ -17,5 +17,6 @@ * under the License. */ /** - * Support for acquiring Realms from JNDI, particularly useful for configuring Shiro in JEE or EJB environments. */ + * Support for acquiring Realms from JNDI, particularly useful for configuring Shiro in JEE or EJB environments. + */ package org.apache.shiro.realm.jndi; diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java b/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java index 7909e89855..edd6e52832 100644 --- a/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/ldap/AbstractLdapRealm.java @@ -37,8 +37,8 @@ * list as well.

    * *

    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,8 +228,8 @@ 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; - + protected abstract AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, + LdapContextFactory ldapContextFactory) throws NamingException; /** *

    Abstract method that should be implemented by subclasses to builds an @@ -243,6 +241,7 @@ 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; + 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..d742f7bf30 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,429 @@ -/* - * 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. - *

    Authentication

    - * During an authentication attempt, if the submitted {@code AuthenticationToken}'s - * {@link org.apache.shiro.authc.AuthenticationToken#getPrincipal() principal} is a simple username, but the - * LDAP directory expects a complete User Distinguished Name (User DN) to establish a connection, the - * {@link #setUserDnTemplate(String) userDnTemplate} property must be configured. If not configured, - * the property will pass the simple username directly as the User DN, which is often incorrect in most LDAP - * environments (maybe Microsoft ActiveDirectory being the exception). - *

    Authorization

    - * By default, authorization is effectively disabled due to the default - * {@link #doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)} implementation returning {@code null}. - * If you wish to perform authorization based on an LDAP schema, you must subclass this one - * and override that method to reflect your organization's data model. - *

    Configuration

    - * This class primarily provides the {@link #setUserDnTemplate(String) userDnTemplate} property to allow you to specify - * the your LDAP server's User DN format. Most other configuration is performed via the nested - * {@link LdapContextFactory contextFactory} property. - *

    - * For example, defining this realm in Shiro .ini: - *

    - * [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. - *

    Usage

    - * User DN formats are unique to the LDAP directory's schema, and each environment differs - you will need to - * specify the format corresponding to your directory. You do this by specifying the full User DN as normal, but - * but you use a {@code {0}} placeholder token in the string representing the location where the - * user's submitted principal (usually a username or uid) will be substituted at runtime. - *

    - * For example, if your directory - * uses an LDAP {@code uid} attribute to represent usernames, the User DN for the {@code jsmith} user may look like - * this: - *

    - *

    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. + *

    Authentication

    + * During an authentication attempt, if the submitted {@code AuthenticationToken}'s + * {@link org.apache.shiro.authc.AuthenticationToken#getPrincipal() principal} is a simple username, but the + * LDAP directory expects a complete User Distinguished Name (User DN) to establish a connection, the + * {@link #setUserDnTemplate(String) userDnTemplate} property must be configured. If not configured, + * the property will pass the simple username directly as the User DN, which is often incorrect in most LDAP + * environments (maybe Microsoft ActiveDirectory being the exception). + *

    Authorization

    + * By default, authorization is effectively disabled due to the default + * {@link #doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)} implementation returning {@code null}. + * If you wish to perform authorization based on an LDAP schema, you must subclass this one + * and override that method to reflect your organization's data model. + *

    Configuration

    + * This class primarily provides the {@link #setUserDnTemplate(String) userDnTemplate} property to allow you to specify + * the your LDAP server's User DN format. Most other configuration is performed via the nested + * {@link LdapContextFactory contextFactory} property. + *

    + * For example, defining this realm in Shiro .ini: + *

    + * [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. + *

    Usage

    + * User DN formats are unique to the LDAP directory's schema, and each environment differs - you will need to + * specify the format corresponding to your directory. You do this by specifying the full User DN as normal, but + * but you use a {@code {0}} placeholder token in the string representing the location where the + * user's submitted principal (usually a username or uid) will be substituted at runtime. + *

    + * For example, if your directory + * uses an LDAP {@code uid} attribute to represent usernames, the User DN for the {@code jsmith} user may look like + * this: + *

    + *

    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; + } + + /** + * 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(AuthenticationToken, Object, Object, 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..4659b26f0d 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}. - *

    Configuration

    - * This class basically wraps a default template JNDI environment properties Map. This properties map is the base - * configuration template used to acquire JNDI {@link LdapContext} connections at runtime. The - * {@link #getLdapContext(Object, Object)} method implementation merges this default template with other properties - * accessible at runtime only (for example per-method principals and credentials). The constructed runtime map is the - * one used to acquire the {@link LdapContext}. - *

    - * The template can be configured directly via the {@link #getEnvironment()}/{@link #setEnvironment(java.util.Map)} - * properties directly if necessary, but it is usually more convenient to use the supporting wrapper get/set methods - * for various environment properties. These wrapper methods interact with the environment - * template on your behalf, leaving your configuration cleaner and easier to understand. - *

    - * For example, consider the following two identical configurations: - *

    - * [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; - private boolean poolingEnabled; - private String systemPassword; - private String systemUsername; - - /*------------------------------------------- - | C O N S T R U C T O R S | - ===========================================*/ - - /** - * Default no-argument constructor that initializes the backing {@link #getEnvironment() environment template} with - * the {@link #setContextFactoryClassName(String) contextFactoryClassName} equal to - * {@code com.sun.jndi.ldap.LdapCtxFactory} (the Sun/Oracle default) and the default - * {@link #setReferral(String) referral} behavior to {@code follow}. - */ - public JndiLdapContextFactory() { - this.environment = new HashMap(); - setContextFactoryClassName(DEFAULT_CONTEXT_FACTORY_CLASS_NAME); - setReferral(DEFAULT_REFERRAL); - poolingEnabled = true; - } - - /*------------------------------------------- - | A C C E S S O R S / M O D I F I E R S | - ===========================================*/ - - /** - * Sets the type of LDAP authentication mechanism to use when connecting to the LDAP server. - * This is a wrapper method for setting the JNDI {@link #getEnvironment() environment template}'s - * {@link Context#SECURITY_AUTHENTICATION} property. - *

    - * "none" (i.e. anonymous) and "simple" authentications are supported automatically and don't need to be configured - * via this property. However, if you require a different mechanism, such as a SASL or External mechanism, you - * must configure that explicitly via this property. See the - * JNDI LDAP - * Authentication Mechanisms for more information. - * - * @param authenticationMechanism the type of LDAP authentication to perform. - * @see - * http://download-llnw.oracle.com/javase/tutorial/jndi/ldap/auth_mechs.html - */ - public void setAuthenticationMechanism(String authenticationMechanism) { - setEnvironmentProperty(Context.SECURITY_AUTHENTICATION, authenticationMechanism); - } - - /** - * Returns the type of LDAP authentication mechanism to use when connecting to the LDAP server. - * This is a wrapper method for getting the JNDI {@link #getEnvironment() environment template}'s - * {@link Context#SECURITY_AUTHENTICATION} property. - *

    - * If this property remains un-configured (i.e. {@code null} indicating the - * {@link #setAuthenticationMechanism(String)} method wasn't used), this indicates that the default JNDI - * "none" (anonymous) and "simple" authentications are supported automatically. Any non-null value returned - * represents an explicitly configured mechanism (e.g. a SASL or external mechanism). See the - * JNDI LDAP - * Authentication Mechanisms for more information. - * - * @return the type of LDAP authentication mechanism to use when connecting to the LDAP server. - * @see - * http://download-llnw.oracle.com/javase/tutorial/jndi/ldap/auth_mechs.html - */ - public String getAuthenticationMechanism() { - return (String) getEnvironmentProperty(Context.SECURITY_AUTHENTICATION); - } - - /** - * The name of the ContextFactory class to use. This defaults to the SUN LDAP JNDI implementation - * but can be overridden to use custom LDAP factories. - *

    - * This is a wrapper method for setting the JNDI environment's {@link Context#INITIAL_CONTEXT_FACTORY} property. - * - * @param contextFactoryClassName the context factory that should be used. - */ - public void setContextFactoryClassName(String contextFactoryClassName) { - setEnvironmentProperty(Context.INITIAL_CONTEXT_FACTORY, contextFactoryClassName); - } - - /** - * Sets the name of the ContextFactory class to use. This defaults to the SUN LDAP JNDI implementation - * but can be overridden to use custom LDAP factories. - *

    - * This is a wrapper method for getting the JNDI environment's {@link Context#INITIAL_CONTEXT_FACTORY} property. - * - * @return the name of the ContextFactory class to use. - */ - public String getContextFactoryClassName() { - return (String) getEnvironmentProperty(Context.INITIAL_CONTEXT_FACTORY); - } - - /** - * Returns the base JNDI environment template to use when acquiring an LDAP connection (an {@link LdapContext}). - * This property is the base configuration template to use for all connections. This template is then - * merged with appropriate runtime values as necessary in the - * {@link #getLdapContext(Object, Object)} implementation. The merged environment instance is what is used to - * acquire the {@link LdapContext} at runtime. - *

    - * Most other get/set methods in this class act as thin proxy wrappers that interact with this property. The - * benefit of using them is you have an easier-to-use configuration mechanism compared to setting map properties - * based on JNDI context keys. - * - * @return the base JNDI environment template to use when acquiring an LDAP connection (an {@link LdapContext}) - */ - public Map getEnvironment() { - return this.environment; - } - - /** - * Sets the base JNDI environment template to use when acquiring LDAP connections. It is typically more common - * to use the other get/set methods in this class to set individual environment settings rather than use - * this method, but it is available for advanced users that want full control over the base JNDI environment - * settings. - *

    - * Note that this template only represents the base/default environment settings. It is then merged with - * appropriate runtime values as necessary in the {@link #getLdapContext(Object, Object)} implementation. - * The merged environment instance is what is used to acquire the connection ({@link LdapContext}) at runtime. - * - * @param env the base JNDI environment template to use when acquiring LDAP connections. - */ - @SuppressWarnings({"unchecked"}) - public void setEnvironment(Map env) { - this.environment = env; - } - - /** - * Returns the environment property value bound under the specified key. - * - * @param name the name of the environment property - * @return the property value or {@code null} if the value has not been set. - */ - private Object getEnvironmentProperty(String name) { - return this.environment.get(name); - } - - /** - * Will apply the value to the environment attribute if and only if the value is not null or empty. If it is - * null or empty, the corresponding environment attribute will be removed. - * - * @param name the environment property key - * @param value the environment property value. A null/empty value will trigger removal. - */ - private void setEnvironmentProperty(String name, String value) { - if (StringUtils.hasText(value)) { - this.environment.put(name, value); - } else { - this.environment.remove(name); - } - } - - /** - * Returns whether or not connection pooling should be used when possible and appropriate. This property is NOT - * backed by the {@link #getEnvironment() environment template} like most other properties in this class. It - * is a flag to indicate that pooling is preferred. The default value is {@code true}. - *

    - * However, pooling will only actually be enabled if this property is {@code true} and the connection - * being created is for the {@link #getSystemUsername() systemUsername} user. Connection pooling is not used for - * general authentication attempts by application end-users because the probability of re-use for that same - * user-specific connection after an authentication attempt is extremely low. - *

    - * If this attribute is {@code true} and it has been determined that the connection is being made with the - * {@link #getSystemUsername() systemUsername}, the - * {@link #getLdapContext(Object, Object)} implementation will set the Sun/Oracle-specific - * {@code com.sun.jndi.ldap.connect.pool} environment property to "{@code true}". This means setting - * this property is only likely to work if using the Sun/Oracle default context factory class (i.e. not using - * a custom {@link #getContextFactoryClassName() contextFactoryClassName}). - * - * @return whether or not connection pooling should be used when possible and appropriate - */ - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - /** - * Sets whether or not connection pooling should be used when possible and appropriate. This property is NOT - * a wrapper to the {@link #getEnvironment() environment template} like most other properties in this class. It - * is a flag to indicate that pooling is preferred. The default value is {@code true}. - *

    - * However, pooling will only actually be enabled if this property is {@code true} and the connection - * being created is for the {@link #getSystemUsername() systemUsername} user. Connection pooling is not used for - * general authentication attempts by application end-users because the probability of re-use for that same - * user-specific connection after an authentication attempt is extremely low. - *

    - * If this attribute is {@code true} and it has been determined that the connection is being made with the - * {@link #getSystemUsername() systemUsername}, the - * {@link #getLdapContext(Object, Object)} implementation will set the Sun/Oracle-specific - * {@code com.sun.jndi.ldap.connect.pool} environment property to "{@code true}". This means setting - * this property is only likely to work if using the Sun/Oracle default context factory class (i.e. not using - * a custom {@link #getContextFactoryClassName() contextFactoryClassName}). - * - * @param poolingEnabled whether or not connection pooling should be used when possible and appropriate - */ - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - /** - * Sets the LDAP referral behavior when creating a connection. Defaults to {@code follow}. See the Sun/Oracle LDAP - * referral documentation for more. - * - * @param referral the referral property. - * @see Referrals in JNDI - */ - public void setReferral(String referral) { - setEnvironmentProperty(Context.REFERRAL, referral); - } - - /** - * Returns the LDAP referral behavior when creating a connection. Defaults to {@code follow}. - * See the Sun/Oracle LDAP - * referral documentation for more. - * - * @return the LDAP referral behavior when creating a connection. - * @see Referrals in JNDI - */ - public String getReferral() { - return (String) getEnvironmentProperty(Context.REFERRAL); - } - - /** - * The LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>). This must be configured. - * - * @param url the LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>) - */ - public void setUrl(String url) { - setEnvironmentProperty(Context.PROVIDER_URL, url); - } - - /** - * Returns the LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>). - * This must be configured. - * - * @return the LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>) - */ - public String getUrl() { - return (String) getEnvironmentProperty(Context.PROVIDER_URL); - } - - /** - * Sets the password of the {@link #setSystemUsername(String) systemUsername} that will be used when creating an - * LDAP connection used for authorization queries. - *

    - * Note that setting this property is not required if the calling LDAP Realm does not perform authorization - * checks. - * - * @param systemPassword the password of the {@link #setSystemUsername(String) systemUsername} that will be used - * when creating an LDAP connection used for authorization queries. - */ - public void setSystemPassword(String systemPassword) { - this.systemPassword = systemPassword; - } - - /** - * Returns the password of the {@link #setSystemUsername(String) systemUsername} that will be used when creating an - * LDAP connection used for authorization queries. - *

    - * Note that setting this property is not required if the calling LDAP Realm does not perform authorization - * checks. - * - * @return the password of the {@link #setSystemUsername(String) systemUsername} that will be used when creating an - * LDAP connection used for authorization queries. - */ - public String getSystemPassword() { - return this.systemPassword; - } - - /** - * Sets the system username that will be used when creating an LDAP connection used for authorization queries. - * The user must have the ability to query for authorization data for any application user. - *

    - * Note that setting this property is not required if the calling LDAP Realm does not perform authorization - * checks. - * - * @param systemUsername the system username that will be used when creating an LDAP connection used for - * authorization queries. - */ - public void setSystemUsername(String systemUsername) { - this.systemUsername = systemUsername; - } - - /** - * Returns the system username that will be used when creating an LDAP connection used for authorization queries. - * The user must have the ability to query for authorization data for any application user. - *

    - * Note that setting this property is not required if the calling LDAP Realm does not perform authorization - * checks. - * - * @return the system username that will be used when creating an LDAP connection used for authorization queries. - */ - public String getSystemUsername() { - return systemUsername; - } - - /*-------------------------------------------- - | M E T H O D S | - ============================================*/ - - /** - * This implementation delegates to {@link #getLdapContext(Object, Object)} using the - * {@link #getSystemUsername() systemUsername} and {@link #getSystemPassword() systemPassword} properties as - * arguments. - * - * @return the system LdapContext - * @throws NamingException if there is a problem connecting to the LDAP directory - */ - public LdapContext getSystemLdapContext() throws NamingException { - return getLdapContext(getSystemUsername(), getSystemPassword()); - } - - /** - * Returns {@code true} if LDAP connection pooling should be used when acquiring a connection based on the specified - * account principal, {@code false} otherwise. - *

    - * This implementation returns {@code true} only if {@link #isPoolingEnabled()} and the principal equals the - * {@link #getSystemUsername()}. The reasoning behind this is that connection pooling is not desirable for - * general authentication attempts by application end-users because the probability of re-use for that same - * user-specific connection after an authentication attempt is extremely low. - * - * @param principal the principal under which the connection will be made - * @return {@code true} if LDAP connection pooling should be used when acquiring a connection based on the specified - * account principal, {@code false} otherwise. - */ - protected boolean isPoolingConnections(Object principal) { - return isPoolingEnabled() && principal != null && principal.equals(getSystemUsername()); - } - - /** - * This implementation returns an LdapContext based on the configured JNDI/LDAP environment configuration. - * The environment (Map) used at runtime is created by merging the default/configured - * {@link #getEnvironment() environment template} with some runtime values as necessary (e.g. a principal and - * credential available at runtime only). - *

    - * After the merged Map instance is created, the LdapContext connection is - * {@link #createLdapContext(java.util.Hashtable) created} and returned. - * - * @param principal the principal to use when acquiring a connection to the LDAP directory - * @param credentials the credentials (password, X.509 certificate, etc.) to use when acquiring a connection to the - * LDAP directory - * @return the acquired {@code LdapContext} connection bound using the specified principal and credentials. - * @throws NamingException - * @throws IllegalStateException - */ - public LdapContext getLdapContext(Object principal, Object credentials) throws NamingException, - IllegalStateException { - - String url = getUrl(); - if (url == null) { - throw new IllegalStateException("An LDAP URL must be specified of the form ldap://:"); - } - - //copy the environment template into the runtime instance that will be further edited based on - //the method arguments and other class attributes. - Hashtable env = new Hashtable(this.environment); - - Object authcMech = getAuthenticationMechanism(); - if (authcMech == null && (principal != null || credentials != null)) { - //authenticationMechanism has not been set, but either a principal and/or credentials were - //supplied, indicating that at least a 'simple' authentication attempt is indeed occurring - the Shiro - //end-user just didn't configure it explicitly. So we set it to be 'simple' here as a convenience; - //the Sun provider implementation already does this same logic, but by repeating that logic here, we ensure - //this convenience exists regardless of provider implementation): - env.put(Context.SECURITY_AUTHENTICATION, SIMPLE_AUTHENTICATION_MECHANISM_NAME); - } - if (principal != null) { - env.put(Context.SECURITY_PRINCIPAL, principal); - } - if (credentials != null) { - env.put(Context.SECURITY_CREDENTIALS, credentials); - } - - boolean pooling = isPoolingConnections(principal); - if (pooling) { - env.put(SUN_CONNECTION_POOLING_PROPERTY, "true"); - } - - if (log.isDebugEnabled()) { - log.debug("Initializing LDAP context using URL [{}] and principal [{}] with pooling {}", - new Object[]{url, principal, (pooling ? "enabled" : "disabled")}); - } - - // validate the config before creating the context - validateAuthenticationInfo(env); - - return createLdapContext(env); - } - - /** - * Creates and returns a new {@link javax.naming.ldap.InitialLdapContext} instance. This method exists primarily - * to support testing where a mock LdapContext can be returned instead of actually creating a connection, but - * subclasses are free to provide a different implementation if necessary. - * - * @param env the JNDI environment settings used to create the LDAP connection - * @return an LdapConnection - * @throws NamingException if a problem occurs creating the connection - */ - protected LdapContext createLdapContext(Hashtable env) throws NamingException { - return new InitialLdapContext(env, null); - } - - - /** - * Validates the configuration in the JNDI 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 environment) - throws AuthenticationException - { - // validate when using Simple auth both principal and credentials are set - if(SIMPLE_AUTHENTICATION_MECHANISM_NAME.equals(environment.get(Context.SECURITY_AUTHENTICATION))) { - - // only validate credentials if we have a non-empty principal - if( environment.get(Context.SECURITY_PRINCIPAL) != null && - StringUtils.hasText( String.valueOf( environment.get(Context.SECURITY_PRINCIPAL) ))) { - - Object credentials = environment.get(Context.SECURITY_CREDENTIALS); - - // from the FAQ, we need to check for empty credentials: - // http://docs.oracle.com/javase/tutorial/jndi/ldap/faq.html - if( credentials == null || - (credentials instanceof byte[] && ((byte[])credentials).length <= 0) || // empty byte[] - (credentials instanceof char[] && ((char[])credentials).length <= 0) || // empty char[] - (String.class.isInstance(credentials) && !StringUtils.hasText(String.valueOf(credentials)))) { - - throw new javax.naming.AuthenticationException("LDAP Simple authentication requires both a " - + "principal and credentials."); - } - } - } - } - -} +/* + * 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}. + *

    Configuration

    + * This class basically wraps a default template JNDI environment properties Map. This properties map is the base + * configuration template used to acquire JNDI {@link LdapContext} connections at runtime. The + * {@link #getLdapContext(Object, Object)} method implementation merges this default template with other properties + * accessible at runtime only (for example per-method principals and credentials). The constructed runtime map is the + * one used to acquire the {@link LdapContext}. + *

    + * The template can be configured directly via the {@link #getEnvironment()}/{@link #setEnvironment(java.util.Map)} + * properties directly if necessary, but it is usually more convenient to use the supporting wrapper get/set methods + * for various environment properties. These wrapper methods interact with the environment + * template on your behalf, leaving your configuration cleaner and easier to understand. + *

    + * For example, consider the following two identical configurations: + *

    + * [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; + private boolean poolingEnabled; + private String systemPassword; + private String systemUsername; + + /*------------------------------------------- + | C O N S T R U C T O R S | + ===========================================*/ + + /** + * Default no-argument constructor that initializes the backing {@link #getEnvironment() environment template} with + * the {@link #setContextFactoryClassName(String) contextFactoryClassName} equal to + * {@code com.sun.jndi.ldap.LdapCtxFactory} (the Sun/Oracle default) and the default + * {@link #setReferral(String) referral} behavior to {@code follow}. + */ + public JndiLdapContextFactory() { + this.environment = new HashMap(); + setContextFactoryClassName(DEFAULT_CONTEXT_FACTORY_CLASS_NAME); + setReferral(DEFAULT_REFERRAL); + poolingEnabled = true; + } + + /*------------------------------------------- + | A C C E S S O R S / M O D I F I E R S | + ===========================================*/ + + /** + * Sets the type of LDAP authentication mechanism to use when connecting to the LDAP server. + * This is a wrapper method for setting the JNDI {@link #getEnvironment() environment template}'s + * {@link Context#SECURITY_AUTHENTICATION} property. + *

    + * "none" (i.e. anonymous) and "simple" authentications are supported automatically and don't need to be configured + * via this property. However, if you require a different mechanism, such as a SASL or External mechanism, you + * must configure that explicitly via this property. See the + * JNDI LDAP + * Authentication Mechanisms for more information. + * + * @param authenticationMechanism the type of LDAP authentication to perform. + * @see + * http://download-llnw.oracle.com/javase/tutorial/jndi/ldap/auth_mechs.html + */ + public void setAuthenticationMechanism(String authenticationMechanism) { + setEnvironmentProperty(Context.SECURITY_AUTHENTICATION, authenticationMechanism); + } + + /** + * Returns the type of LDAP authentication mechanism to use when connecting to the LDAP server. + * This is a wrapper method for getting the JNDI {@link #getEnvironment() environment template}'s + * {@link Context#SECURITY_AUTHENTICATION} property. + *

    + * If this property remains un-configured (i.e. {@code null} indicating the + * {@link #setAuthenticationMechanism(String)} method wasn't used), this indicates that the default JNDI + * "none" (anonymous) and "simple" authentications are supported automatically. Any non-null value returned + * represents an explicitly configured mechanism (e.g. a SASL or external mechanism). See the + * JNDI LDAP + * Authentication Mechanisms for more information. + * + * @return the type of LDAP authentication mechanism to use when connecting to the LDAP server. + * @see + * http://download-llnw.oracle.com/javase/tutorial/jndi/ldap/auth_mechs.html + */ + public String getAuthenticationMechanism() { + return (String) getEnvironmentProperty(Context.SECURITY_AUTHENTICATION); + } + + /** + * The name of the ContextFactory class to use. This defaults to the SUN LDAP JNDI implementation + * but can be overridden to use custom LDAP factories. + *

    + * This is a wrapper method for setting the JNDI environment's {@link Context#INITIAL_CONTEXT_FACTORY} property. + * + * @param contextFactoryClassName the context factory that should be used. + */ + public void setContextFactoryClassName(String contextFactoryClassName) { + setEnvironmentProperty(Context.INITIAL_CONTEXT_FACTORY, contextFactoryClassName); + } + + /** + * Sets the name of the ContextFactory class to use. This defaults to the SUN LDAP JNDI implementation + * but can be overridden to use custom LDAP factories. + *

    + * This is a wrapper method for getting the JNDI environment's {@link Context#INITIAL_CONTEXT_FACTORY} property. + * + * @return the name of the ContextFactory class to use. + */ + public String getContextFactoryClassName() { + return (String) getEnvironmentProperty(Context.INITIAL_CONTEXT_FACTORY); + } + + /** + * Returns the base JNDI environment template to use when acquiring an LDAP connection (an {@link LdapContext}). + * This property is the base configuration template to use for all connections. This template is then + * merged with appropriate runtime values as necessary in the + * {@link #getLdapContext(Object, Object)} implementation. The merged environment instance is what is used to + * acquire the {@link LdapContext} at runtime. + *

    + * Most other get/set methods in this class act as thin proxy wrappers that interact with this property. The + * benefit of using them is you have an easier-to-use configuration mechanism compared to setting map properties + * based on JNDI context keys. + * + * @return the base JNDI environment template to use when acquiring an LDAP connection (an {@link LdapContext}) + */ + public Map getEnvironment() { + return this.environment; + } + + /** + * Sets the base JNDI environment template to use when acquiring LDAP connections. It is typically more common + * to use the other get/set methods in this class to set individual environment settings rather than use + * this method, but it is available for advanced users that want full control over the base JNDI environment + * settings. + *

    + * Note that this template only represents the base/default environment settings. It is then merged with + * appropriate runtime values as necessary in the {@link #getLdapContext(Object, Object)} implementation. + * The merged environment instance is what is used to acquire the connection ({@link LdapContext}) at runtime. + * + * @param env the base JNDI environment template to use when acquiring LDAP connections. + */ + @SuppressWarnings({"unchecked"}) + public void setEnvironment(Map env) { + this.environment = env; + } + + /** + * Returns the environment property value bound under the specified key. + * + * @param name the name of the environment property + * @return the property value or {@code null} if the value has not been set. + */ + private Object getEnvironmentProperty(String name) { + return this.environment.get(name); + } + + /** + * Will apply the value to the environment attribute if and only if the value is not null or empty. If it is + * null or empty, the corresponding environment attribute will be removed. + * + * @param name the environment property key + * @param value the environment property value. A null/empty value will trigger removal. + */ + private void setEnvironmentProperty(String name, String value) { + if (StringUtils.hasText(value)) { + this.environment.put(name, value); + } else { + this.environment.remove(name); + } + } + + /** + * Returns whether or not connection pooling should be used when possible and appropriate. This property is NOT + * backed by the {@link #getEnvironment() environment template} like most other properties in this class. It + * is a flag to indicate that pooling is preferred. The default value is {@code true}. + *

    + * However, pooling will only actually be enabled if this property is {@code true} and the connection + * being created is for the {@link #getSystemUsername() systemUsername} user. Connection pooling is not used for + * general authentication attempts by application end-users because the probability of re-use for that same + * user-specific connection after an authentication attempt is extremely low. + *

    + * If this attribute is {@code true} and it has been determined that the connection is being made with the + * {@link #getSystemUsername() systemUsername}, the + * {@link #getLdapContext(Object, Object)} implementation will set the Sun/Oracle-specific + * {@code com.sun.jndi.ldap.connect.pool} environment property to "{@code true}". This means setting + * this property is only likely to work if using the Sun/Oracle default context factory class (i.e. not using + * a custom {@link #getContextFactoryClassName() contextFactoryClassName}). + * + * @return whether or not connection pooling should be used when possible and appropriate + */ + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + /** + * Sets whether or not connection pooling should be used when possible and appropriate. This property is NOT + * a wrapper to the {@link #getEnvironment() environment template} like most other properties in this class. It + * is a flag to indicate that pooling is preferred. The default value is {@code true}. + *

    + * However, pooling will only actually be enabled if this property is {@code true} and the connection + * being created is for the {@link #getSystemUsername() systemUsername} user. Connection pooling is not used for + * general authentication attempts by application end-users because the probability of re-use for that same + * user-specific connection after an authentication attempt is extremely low. + *

    + * If this attribute is {@code true} and it has been determined that the connection is being made with the + * {@link #getSystemUsername() systemUsername}, the + * {@link #getLdapContext(Object, Object)} implementation will set the Sun/Oracle-specific + * {@code com.sun.jndi.ldap.connect.pool} environment property to "{@code true}". This means setting + * this property is only likely to work if using the Sun/Oracle default context factory class (i.e. not using + * a custom {@link #getContextFactoryClassName() contextFactoryClassName}). + * + * @param poolingEnabled whether or not connection pooling should be used when possible and appropriate + */ + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + /** + * Sets the LDAP referral behavior when creating a connection. Defaults to {@code follow}. See the Sun/Oracle LDAP + * referral documentation for more. + * + * @param referral the referral property. + * @see Referrals in JNDI + */ + public void setReferral(String referral) { + setEnvironmentProperty(Context.REFERRAL, referral); + } + + /** + * Returns the LDAP referral behavior when creating a connection. Defaults to {@code follow}. + * See the Sun/Oracle LDAP + * referral documentation for more. + * + * @return the LDAP referral behavior when creating a connection. + * @see Referrals in JNDI + */ + public String getReferral() { + return (String) getEnvironmentProperty(Context.REFERRAL); + } + + /** + * The LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>). This must be configured. + * + * @param url the LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>) + */ + public void setUrl(String url) { + setEnvironmentProperty(Context.PROVIDER_URL, url); + } + + /** + * Returns the LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>). + * This must be configured. + * + * @return the LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>) + */ + public String getUrl() { + return (String) getEnvironmentProperty(Context.PROVIDER_URL); + } + + /** + * Sets the password of the {@link #setSystemUsername(String) systemUsername} that will be used when creating an + * LDAP connection used for authorization queries. + *

    + * Note that setting this property is not required if the calling LDAP Realm does not perform authorization + * checks. + * + * @param systemPassword the password of the {@link #setSystemUsername(String) systemUsername} that will be used + * when creating an LDAP connection used for authorization queries. + */ + public void setSystemPassword(String systemPassword) { + this.systemPassword = systemPassword; + } + + /** + * Returns the password of the {@link #setSystemUsername(String) systemUsername} that will be used when creating an + * LDAP connection used for authorization queries. + *

    + * Note that setting this property is not required if the calling LDAP Realm does not perform authorization + * checks. + * + * @return the password of the {@link #setSystemUsername(String) systemUsername} that will be used when creating an + * LDAP connection used for authorization queries. + */ + public String getSystemPassword() { + return this.systemPassword; + } + + /** + * Sets the system username that will be used when creating an LDAP connection used for authorization queries. + * The user must have the ability to query for authorization data for any application user. + *

    + * Note that setting this property is not required if the calling LDAP Realm does not perform authorization + * checks. + * + * @param systemUsername the system username that will be used when creating an LDAP connection used for + * authorization queries. + */ + public void setSystemUsername(String systemUsername) { + this.systemUsername = systemUsername; + } + + /** + * Returns the system username that will be used when creating an LDAP connection used for authorization queries. + * The user must have the ability to query for authorization data for any application user. + *

    + * Note that setting this property is not required if the calling LDAP Realm does not perform authorization + * checks. + * + * @return the system username that will be used when creating an LDAP connection used for authorization queries. + */ + public String getSystemUsername() { + return systemUsername; + } + + /*-------------------------------------------- + | M E T H O D S | + ============================================*/ + + /** + * This implementation delegates to {@link #getLdapContext(Object, Object)} using the + * {@link #getSystemUsername() systemUsername} and {@link #getSystemPassword() systemPassword} properties as + * arguments. + * + * @return the system LdapContext + * @throws NamingException if there is a problem connecting to the LDAP directory + */ + public LdapContext getSystemLdapContext() throws NamingException { + return getLdapContext(getSystemUsername(), getSystemPassword()); + } + + /** + * Returns {@code true} if LDAP connection pooling should be used when acquiring a connection based on the specified + * account principal, {@code false} otherwise. + *

    + * This implementation returns {@code true} only if {@link #isPoolingEnabled()} and the principal equals the + * {@link #getSystemUsername()}. The reasoning behind this is that connection pooling is not desirable for + * general authentication attempts by application end-users because the probability of re-use for that same + * user-specific connection after an authentication attempt is extremely low. + * + * @param principal the principal under which the connection will be made + * @return {@code true} if LDAP connection pooling should be used when acquiring a connection based on the specified + * account principal, {@code false} otherwise. + */ + protected boolean isPoolingConnections(Object principal) { + return isPoolingEnabled() && principal != null && principal.equals(getSystemUsername()); + } + + /** + * This implementation returns an LdapContext based on the configured JNDI/LDAP environment configuration. + * The environment (Map) used at runtime is created by merging the default/configured + * {@link #getEnvironment() environment template} with some runtime values as necessary (e.g. a principal and + * credential available at runtime only). + *

    + * After the merged Map instance is created, the LdapContext connection is + * {@link #createLdapContext(java.util.Hashtable) created} and returned. + * + * @param principal the principal to use when acquiring a connection to the LDAP directory + * @param credentials the credentials (password, X.509 certificate, etc.) to use when acquiring a connection to the + * LDAP directory + * @return the acquired {@code LdapContext} connection bound using the specified principal and credentials. + * @throws NamingException + * @throws IllegalStateException + */ + public LdapContext getLdapContext(Object principal, Object credentials) throws NamingException, + IllegalStateException { + + String url = getUrl(); + if (url == null) { + throw new IllegalStateException("An LDAP URL must be specified of the form ldap://:"); + } + + //copy the environment template into the runtime instance that will be further edited based on + //the method arguments and other class attributes. + Hashtable env = new Hashtable(this.environment); + + Object authcMech = getAuthenticationMechanism(); + if (authcMech == null && (principal != null || credentials != null)) { + //authenticationMechanism has not been set, but either a principal and/or credentials were + //supplied, indicating that at least a 'simple' authentication attempt is indeed occurring - the Shiro + //end-user just didn't configure it explicitly. So we set it to be 'simple' here as a convenience; + //the Sun provider implementation already does this same logic, but by repeating that logic here, we ensure + //this convenience exists regardless of provider implementation): + env.put(Context.SECURITY_AUTHENTICATION, SIMPLE_AUTHENTICATION_MECHANISM_NAME); + } + if (principal != null) { + env.put(Context.SECURITY_PRINCIPAL, principal); + } + if (credentials != null) { + env.put(Context.SECURITY_CREDENTIALS, credentials); + } + + boolean pooling = isPoolingConnections(principal); + if (pooling) { + env.put(SUN_CONNECTION_POOLING_PROPERTY, "true"); + } + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Initializing LDAP context using URL [{}] and principal [{}] with pooling {}", + new Object[] {url, principal, (pooling ? "enabled" : "disabled")}); + } + + // validate the config before creating the context + validateAuthenticationInfo(env); + + return createLdapContext(env); + } + + /** + * Creates and returns a new {@link javax.naming.ldap.InitialLdapContext} instance. This method exists primarily + * to support testing where a mock LdapContext can be returned instead of actually creating a connection, but + * subclasses are free to provide a different implementation if necessary. + * + * @param env the JNDI environment settings used to create the LDAP connection + * @return an LdapConnection + * @throws NamingException if a problem occurs creating the connection + */ + protected LdapContext createLdapContext(Hashtable env) throws NamingException { + return new InitialLdapContext(env, null); + } + + + /** + * Validates the configuration in the JNDI 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:BooleanExpressionComplexity"}) + protected void validateAuthenticationInfo(Hashtable environment) + throws AuthenticationException { + // validate when using Simple auth both principal and credentials are set + if (SIMPLE_AUTHENTICATION_MECHANISM_NAME.equals(environment.get(Context.SECURITY_AUTHENTICATION))) { + + // only validate credentials if we have a non-empty principal + if (environment.get(Context.SECURITY_PRINCIPAL) != null + && StringUtils.hasText(String.valueOf(environment.get(Context.SECURITY_PRINCIPAL)))) { + + Object credentials = environment.get(Context.SECURITY_CREDENTIALS); + + // from the FAQ, we need to check for empty credentials: + // http://docs.oracle.com/javase/tutorial/jndi/ldap/faq.html + if (credentials == null + || (credentials instanceof byte[] && ((byte[]) credentials).length <= 0) + || (credentials instanceof char[] && ((char[]) credentials).length <= 0) + || (String.class.isInstance(credentials) && !StringUtils.hasText(String.valueOf(credentials)))) { + + throw new javax.naming.AuthenticationException("LDAP Simple authentication requires both a " + + "principal and credentials."); + } + } + } + } + +} diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapRealm.java b/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapRealm.java index 1c7fd54626..415c97fbe4 100644 --- a/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/ldap/JndiLdapRealm.java @@ -20,10 +20,10 @@ /** * This class has been replaced with DefaultLdapRealm. + * * @see DefaultLdapRealm - * @deprecated Renamed to {@link DefaultLdapRealm}, this class will be removed prior to 2.0 * @since 1.1 - * + * @deprecated Renamed to {@link DefaultLdapRealm}, this class will be removed prior to 2.0 */ public class JndiLdapRealm extends DefaultLdapRealm { diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/LdapContextFactory.java b/core/src/main/java/org/apache/shiro/realm/ldap/LdapContextFactory.java index 632d3b6b51..6b69c025ff 100644 --- a/core/src/main/java/org/apache/shiro/realm/ldap/LdapContextFactory.java +++ b/core/src/main/java/org/apache/shiro/realm/ldap/LdapContextFactory.java @@ -34,7 +34,7 @@ public interface LdapContextFactory { * anonymously if no system account is configured. * * @return a {@code LdapContext} bound by the system account, or bound anonymously if no system account - * is configured. + * is configured. * @throws javax.naming.NamingException if there is an error creating the context. */ LdapContext getSystemLdapContext() throws NamingException; @@ -59,5 +59,5 @@ public interface LdapContextFactory { * @since 1.1 */ LdapContext getLdapContext(Object principal, Object credentials) throws NamingException; - + } diff --git a/core/src/main/java/org/apache/shiro/realm/ldap/LdapUtils.java b/core/src/main/java/org/apache/shiro/realm/ldap/LdapUtils.java index 750b017f75..ba12a2a28f 100644 --- a/core/src/main/java/org/apache/shiro/realm/ldap/LdapUtils.java +++ b/core/src/main/java/org/apache/shiro/realm/ldap/LdapUtils.java @@ -40,7 +40,10 @@ public final class LdapUtils { /** * Private internal log instance. */ - private static final Logger log = LoggerFactory.getLogger(LdapUtils.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LdapUtils.class); + + private LdapUtils() { + } /** * Closes an LDAP context, logging any errors, but not throwing @@ -54,7 +57,7 @@ public static void closeContext(LdapContext ctx) { ctx.close(); } } catch (NamingException e) { - log.error("Exception while closing LDAP context. ", e); + LOGGER.error("Exception while closing LDAP context. ", e); } } @@ -81,16 +84,18 @@ public static Collection getAllAttributeValues(Attribute attr) throws Na return values; } - //added based on SHIRO-127, per Emmanuel's comment [1] - // [1] https://issues.apache.org/jira/browse/SHIRO-127?focusedCommentId=12891380&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12891380 - + /** + * added based on SHIRO-127, per Emmanuel's comment [1] + * [1] + */ public static void closeEnumeration(NamingEnumeration ne) { try { if (ne != null) { ne.close(); } } catch (NamingException e) { - log.error("Exception while closing NamingEnumeration: ", e); + LOGGER.error("Exception while closing NamingEnumeration: ", e); } } diff --git a/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java b/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java index 10b993ba9b..96b9ba32b8 100644 --- a/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/text/IniRealm.java @@ -44,13 +44,23 @@ */ public class IniRealm extends TextConfigurationRealm { + /** + * users section name + */ public static final String USERS_SECTION_NAME = "users"; + /** + * roles section name + */ public static final String ROLES_SECTION_NAME = "roles"; - private static transient final Logger log = LoggerFactory.getLogger(IniRealm.class); + private static final Logger LOGGER = LoggerFactory.getLogger(IniRealm.class); private String resourcePath; - private Ini ini; //reference added in 1.2 for SHIRO-322 + + /** + * reference added in 1.2 for SHIRO-322 + */ + private Ini ini; public IniRealm() { super(); @@ -107,7 +117,7 @@ public void setResourcePath(String resourcePath) { /** * Returns the Ini instance used to configure this realm. Provided for JavaBeans-style configuration of this * realm, particularly useful in Dependency Injection environments. - * + * * @return the Ini instance which will be inspected to create accounts, groups and permissions for this realm. */ public Ini getIni() { @@ -117,7 +127,7 @@ public Ini getIni() { /** * Sets the Ini instance used to configure this realm. Provided for JavaBeans-style configuration of this * realm, particularly useful in Dependency Injection environments. - * + * * @param ini the Ini instance which will be inspected to create accounts, groups and permissions for this realm. */ public void setIni(Ini ini) { @@ -130,38 +140,38 @@ protected void onInit() { // This is an in-memory realm only - no need for an additional cache when we're already // as memory-efficient as we can be. - + Ini ini = getIni(); String resourcePath = getResourcePath(); - + if (!CollectionUtils.isEmpty(this.users) || !CollectionUtils.isEmpty(this.roles)) { if (!CollectionUtils.isEmpty(ini)) { - log.warn("Users or Roles are already populated. Configured Ini instance will be ignored."); + LOGGER.warn("Users or Roles are already populated. Configured Ini instance will be ignored."); } if (StringUtils.hasText(resourcePath)) { - log.warn("Users or Roles are already populated. resourcePath '{}' will be ignored.", resourcePath); + LOGGER.warn("Users or Roles are already populated. resourcePath '{}' will be ignored.", resourcePath); } - - log.debug("Instance is already populated with users or roles. No additional user/role population " + - "will be performed."); + + LOGGER.debug("Instance is already populated with users or roles. No additional user/role population " + + "will be performed."); return; } - + if (CollectionUtils.isEmpty(ini)) { - log.debug("No INI instance configuration present. Checking resourcePath..."); - + LOGGER.debug("No INI instance configuration present. Checking resourcePath..."); + if (StringUtils.hasText(resourcePath)) { - log.debug("Resource path {} defined. Creating INI instance.", resourcePath); + LOGGER.debug("Resource path {} defined. Creating INI instance.", resourcePath); ini = Ini.fromResourcePath(resourcePath); if (!CollectionUtils.isEmpty(ini)) { setIni(ini); } } } - + if (CollectionUtils.isEmpty(ini)) { - String msg = "Ini instance and/or resourcePath resulted in null or empty Ini configuration. Cannot " + - "load account data."; + String msg = "Ini instance and/or resourcePath resulted in null or empty Ini configuration. Cannot " + + "load account data."; throw new IllegalStateException(msg); } @@ -170,24 +180,24 @@ protected void onInit() { private void processDefinitions(Ini ini) { if (CollectionUtils.isEmpty(ini)) { - log.warn("{} defined, but the ini instance is null or empty.", getClass().getSimpleName()); + LOGGER.warn("{} defined, but the ini instance is null or empty.", getClass().getSimpleName()); return; } Ini.Section rolesSection = ini.getSection(ROLES_SECTION_NAME); if (!CollectionUtils.isEmpty(rolesSection)) { - log.debug("Discovered the [{}] section. Processing...", ROLES_SECTION_NAME); + LOGGER.debug("Discovered the [{}] section. Processing...", ROLES_SECTION_NAME); processRoleDefinitions(rolesSection); } Ini.Section usersSection = ini.getSection(USERS_SECTION_NAME); if (!CollectionUtils.isEmpty(usersSection)) { - log.debug("Discovered the [{}] section. Processing...", USERS_SECTION_NAME); + LOGGER.debug("Discovered the [{}] section. Processing...", USERS_SECTION_NAME); processUserDefinitions(usersSection); } else { - log.info("{} defined, but there is no [{}] section defined. This realm will not be populated with any " + - "users and it is assumed that they will be populated programatically. Users must be defined " + - "for this Realm instance to be useful.", getClass().getSimpleName(), USERS_SECTION_NAME); + LOGGER.info("{} defined, but there is no [{}] section defined. This realm will not be populated with any " + + "users and it is assumed that they will be populated programatically. Users must be defined " + + "for this Realm instance to be useful.", getClass().getSimpleName(), USERS_SECTION_NAME); } } } diff --git a/core/src/main/java/org/apache/shiro/realm/text/PropertiesRealm.java b/core/src/main/java/org/apache/shiro/realm/text/PropertiesRealm.java index 3ced80f8ce..fc48083ea8 100644 --- a/core/src/main/java/org/apache/shiro/realm/text/PropertiesRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/text/PropertiesRealm.java @@ -96,10 +96,10 @@ public class PropertiesRealm extends TextConfigurationRealm implements Destroyab /*------------------------------------------- | I N S T A N C E V A R I A B L E S | ============================================*/ - private static final Logger log = LoggerFactory.getLogger(PropertiesRealm.class); + private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesRealm.class); - protected ExecutorService scheduler = null; - protected boolean useXmlFormat = false; + protected ExecutorService scheduler; + protected boolean useXmlFormat; protected String resourcePath = DEFAULT_RESOURCE_PATH; protected long fileLastModified; protected int reloadIntervalSeconds = DEFAULT_RELOAD_INTERVAL_SECONDS; @@ -176,8 +176,8 @@ public void destroy() { scheduler.shutdown(); } } catch (Exception e) { - if (log.isInfoEnabled()) { - log.info("Unable to cleanly shutdown Scheduler. Ignoring (shutting down)...", e); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Unable to cleanly shutdown Scheduler. Ignoring (shutting down)...", e); } } finally { scheduler = null; @@ -187,7 +187,8 @@ public void destroy() { protected void startReloadThread() { if (this.reloadIntervalSeconds > 0) { this.scheduler = Executors.newSingleThreadScheduledExecutor(); - ((ScheduledExecutorService) this.scheduler).scheduleAtFixedRate(this, reloadIntervalSeconds, reloadIntervalSeconds, TimeUnit.SECONDS); + ((ScheduledExecutorService) this.scheduler) + .scheduleAtFixedRate(this, reloadIntervalSeconds, reloadIntervalSeconds, TimeUnit.SECONDS); } } @@ -195,20 +196,20 @@ public void run() { try { reloadPropertiesIfNecessary(); } catch (Exception e) { - if (log.isErrorEnabled()) { - log.error("Error while reloading property files for realm.", e); + if (LOGGER.isErrorEnabled()) { + LOGGER.error("Error while reloading property files for realm.", e); } } } private void loadProperties() { if (resourcePath == null || resourcePath.length() == 0) { - throw new IllegalStateException("The resourcePath property is not set. " + - "It must be set prior to this realm being initialized."); + throw new IllegalStateException("The resourcePath property is not set. " + + "It must be set prior to this realm being initialized."); } - if (log.isDebugEnabled()) { - log.debug("Loading user security information from file [" + resourcePath + "]..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Loading user security information from file [" + resourcePath + "]..."); } Properties properties = loadProperties(resourcePath); @@ -221,30 +222,30 @@ private Properties loadProperties(String resourcePath) { InputStream is = null; try { - if (log.isDebugEnabled()) { - log.debug("Opening input stream for path [" + resourcePath + "]..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Opening input stream for path [" + resourcePath + "]..."); } is = ResourceUtils.getInputStreamForPath(resourcePath); if (useXmlFormat) { - if (log.isDebugEnabled()) { - log.debug("Loading properties from path [" + resourcePath + "] in XML format..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Loading properties from path [" + resourcePath + "] in XML format..."); } props.loadFromXML(is); } else { - if (log.isDebugEnabled()) { - log.debug("Loading properties from path [" + resourcePath + "]..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Loading properties from path [" + resourcePath + "]..."); } props.load(is); } } catch (IOException e) { - throw new ShiroException("Error reading properties path [" + resourcePath + "]. " + - "Initializing of the realm from this file failed.", e); + throw new ShiroException("Error reading properties path [" + resourcePath + "]. " + + "Initializing of the realm from this file failed.", e); } finally { ResourceUtils.close(is); } @@ -280,12 +281,12 @@ private boolean isFileModified() { @SuppressWarnings("unchecked") private void restart() { if (resourcePath == null || resourcePath.length() == 0) { - throw new IllegalStateException("The resourcePath property is not set. " + - "It must be set prior to this realm being initialized."); + throw new IllegalStateException("The resourcePath property is not set. " + + "It must be set prior to this realm being initialized."); } - if (log.isDebugEnabled()) { - log.debug("Loading user security information from file [" + resourcePath + "]..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Loading user security information from file [" + resourcePath + "]..."); } try { @@ -308,8 +309,8 @@ private void createRealmEntitiesFromProperties(Properties properties) { String key = propNames.nextElement().trim(); String value = properties.getProperty(key).trim(); - if (log.isTraceEnabled()) { - log.trace("Processing properties line - key: [" + key + "], value: [" + value + "]."); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Processing properties line - key: [" + key + "], value: [" + value + "]."); } if (isUsername(key)) { @@ -319,8 +320,8 @@ private void createRealmEntitiesFromProperties(Properties properties) { String rolename = getRolename(key); roleDefs.append(rolename).append(" = ").append(value).append("\n"); } else { - String msg = "Encountered unexpected key/value pair. All keys must be prefixed with either '" + - USERNAME_PREFIX + "' or '" + ROLENAME_PREFIX + "'."; + String msg = "Encountered unexpected key/value pair. All keys must be prefixed with either '" + + USERNAME_PREFIX + "' or '" + ROLENAME_PREFIX + "'."; throw new IllegalStateException(msg); } } diff --git a/core/src/main/java/org/apache/shiro/realm/text/TextConfigurationRealm.java b/core/src/main/java/org/apache/shiro/realm/text/TextConfigurationRealm.java index 8feb159929..c3880a4922 100644 --- a/core/src/main/java/org/apache/shiro/realm/text/TextConfigurationRealm.java +++ b/core/src/main/java/org/apache/shiro/realm/text/TextConfigurationRealm.java @@ -62,8 +62,8 @@ public TextConfigurationRealm() { /** * Will call 'processDefinitions' on startup. * - * @since 1.2 * @see SHIRO-223 + * @since 1.2 */ @Override protected void onInit() { @@ -148,7 +148,7 @@ protected void processRoleDefinitions(Map roleDefs) { if (roleDefs == null || roleDefs.isEmpty()) { return; } - for (Map.Entry entry : roleDefs.entrySet()) { + for (Map.Entry entry : roleDefs.entrySet()) { String rolename = entry.getKey(); String value = entry.getValue(); @@ -178,7 +178,7 @@ protected void processUserDefinitions(Map userDefs) { if (userDefs == null || userDefs.isEmpty()) { return; } - for (Map.Entry entry : userDefs.entrySet()) { + for (Map.Entry entry : userDefs.entrySet()) { String username = entry.getKey(); String value = entry.getValue(); diff --git a/core/src/main/java/org/apache/shiro/session/Session.java b/core/src/main/java/org/apache/shiro/session/Session.java index f91d224003..109dc69129 100644 --- a/core/src/main/java/org/apache/shiro/session/Session.java +++ b/core/src/main/java/org/apache/shiro/session/Session.java @@ -104,7 +104,7 @@ public interface Session { * if the host is unknown. * * @return the host name or IP string of the host that originated this session, or {@code null} - * if the host address is unknown. + * if the host address is unknown. */ String getHost(); @@ -149,7 +149,8 @@ public interface Session { * It is common for a {@code Subject} implementation to retain authentication state in the * {@code Session}. If the session * is explicitly stopped by application code by calling this method directly, it could clear out any - * authentication state that might exist, thereby effectively removing the "authenticated" state of the {@code Subject}. + * authentication state that might exist, thereby effectively removing + * the "authenticated" state of the {@code Subject}. *

    * As such, you might consider {@link org.apache.shiro.subject.Subject#logout logging-out} the 'owning' * {@code Subject} instead of manually calling this method, as a log out is expected to stop the @@ -164,7 +165,7 @@ public interface Session { * attributes, this returns an empty collection. * * @return the keys of all attributes stored under this session, or an empty collection if - * there are no session attributes. + * there are no session attributes. * @throws InvalidSessionException if this session has stopped or expired prior to calling this method. * @since 0.2 */ @@ -176,7 +177,7 @@ public interface Session { * * @param key the unique name of the object bound to this session * @return the object bound under the specified {@code key} name or {@code null} if there is - * no object bound under that name. + * no object bound under that name. * @throws InvalidSessionException if this session has stopped or expired prior to calling * this method. */ @@ -202,7 +203,7 @@ public interface Session { * * @param key the name uniquely identifying the object to remove * @return the object removed or {@code null} if there was no object bound under the name - * {@code key}. + * {@code key}. * @throws InvalidSessionException if this session has stopped or expired prior to calling * this method. */ diff --git a/core/src/main/java/org/apache/shiro/session/mgt/AbstractNativeSessionManager.java b/core/src/main/java/org/apache/shiro/session/mgt/AbstractNativeSessionManager.java index 86353bd63f..a172a01d03 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/AbstractNativeSessionManager.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/AbstractNativeSessionManager.java @@ -42,9 +42,10 @@ * * @since 1.0 */ +@SuppressWarnings({"checkstyle:MethodCount"}) public abstract class AbstractNativeSessionManager extends AbstractSessionManager implements NativeSessionManager, EventBusAware { - private static final Logger log = LoggerFactory.getLogger(AbstractSessionManager.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSessionManager.class); private EventBus eventBus; @@ -112,11 +113,11 @@ public Session start(SessionContext context) { * @param context the initialization data that can be used by the implementation or underlying * {@link SessionFactory} when instantiating the internal {@code Session} instance. * @return the new {@code Session} instance. - * @throws org.apache.shiro.authz.HostUnauthorizedException - * if the system access control policy restricts access based - * on client location/IP and the specified hostAddress hasn't been enabled. - * @throws AuthorizationException if the system access control policy does not allow the currently executing - * caller to start sessions. + * @throws org.apache.shiro.authz.HostUnauthorizedException if the system access control policy restricts access based + * on client location/IP and + * the specified hostAddress hasn't been enabled. + * @throws AuthorizationException if the system access control policy does not allow + * the currently executing caller to start sessions. */ protected abstract Session createSession(SessionContext context) throws AuthorizationException; @@ -280,8 +281,8 @@ public boolean isValid(SessionKey key) { public void stop(SessionKey key) throws InvalidSessionException { Session session = lookupRequiredSession(key); try { - if (log.isDebugEnabled()) { - log.debug("Stopping session with id [" + session.getId() + "]"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Stopping session with id [" + session.getId() + "]"); } session.stop(); onStop(session, key); diff --git a/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java b/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java index 8991bbae31..45e57f3bac 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java @@ -39,16 +39,14 @@ public abstract class AbstractValidatingSessionManager extends AbstractNativeSessionManager implements ValidatingSessionManager, Destroyable { - //TODO - complete JavaDoc - - private static final Logger log = LoggerFactory.getLogger(AbstractValidatingSessionManager.class); - /** * The default interval at which sessions will be validated (1 hour); * This can be overridden by calling {@link #setSessionValidationInterval(long)} */ public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = MILLIS_PER_HOUR; + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractValidatingSessionManager.class); + protected boolean sessionValidationSchedulerEnabled; /** @@ -113,7 +111,7 @@ public long getSessionValidationInterval() { protected final Session doGetSession(final SessionKey key) throws InvalidSessionException { enableSessionValidationIfNecessary(); - log.trace("Attempting to retrieve session with key {}", key); + LOGGER.trace("Attempting to retrieve session with key {}", key); Session s = retrieveSession(key); if (s != null) { @@ -151,7 +149,7 @@ protected void validate(Session session, SessionKey key) throws InvalidSessionEx } protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) { - log.trace("Session with id [{}] has expired.", s.getId()); + LOGGER.trace("Session with id [{}] has expired.", s.getId()); try { onExpiration(s); notifyExpiration(s); @@ -172,7 +170,7 @@ protected void onInvalidation(Session s, InvalidSessionException ise, SessionKey onExpiration(s, (ExpiredSessionException) ise, key); return; } - log.trace("Session with id [{}] is invalid.", s.getId()); + LOGGER.trace("Session with id [{}] is invalid.", s.getId()); try { onStop(s); notifyStop(s); @@ -185,10 +183,10 @@ protected void doValidate(Session session) throws InvalidSessionException { if (session instanceof ValidatingSession) { ((ValidatingSession) session).validate(); } else { - String msg = "The " + getClass().getName() + " implementation only supports validating " + - "Session implementations of the " + ValidatingSession.class.getName() + " interface. " + - "Please either implement this interface in your session implementation or override the " + - AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation."; + String msg = "The " + getClass().getName() + " implementation only supports validating " + + "Session implementations of the " + ValidatingSession.class.getName() + " interface. " + + "Please either implement this interface in your session implementation or override the " + + AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation."; throw new IllegalStateException(msg); } } @@ -209,13 +207,13 @@ protected long getTimeout(Session session) { protected SessionValidationScheduler createSessionValidationScheduler() { ExecutorServiceSessionValidationScheduler scheduler; - if (log.isDebugEnabled()) { - log.debug("No sessionValidationScheduler set. Attempting to create default instance."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No sessionValidationScheduler set. Attempting to create default instance."); } scheduler = new ExecutorServiceSessionValidationScheduler(this); scheduler.setSessionValidationInterval(getSessionValidationInterval()); - if (log.isTraceEnabled()) { - log.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "]."); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "]."); } return scheduler; } @@ -229,8 +227,8 @@ protected synchronized void enableSessionValidation() { // it is possible that that a scheduler was already created and set via 'setSessionValidationScheduler()' // but would not have been enabled/started yet if (!scheduler.isEnabled()) { - if (log.isInfoEnabled()) { - log.info("Enabling session validation scheduler..."); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Enabling session validation scheduler..."); } scheduler.enableSessionValidation(); afterSessionValidationEnabled(); @@ -246,13 +244,13 @@ protected synchronized void disableSessionValidation() { if (scheduler != null) { try { scheduler.disableSessionValidation(); - if (log.isInfoEnabled()) { - log.info("Disabled session validation scheduler."); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Disabled session validation scheduler."); } } catch (Exception e) { - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { String msg = "Unable to disable SessionValidationScheduler. Ignoring (shutting down)..."; - log.debug(msg, e); + LOGGER.debug(msg, e); } } LifecycleUtils.destroy(scheduler); @@ -271,8 +269,8 @@ public void destroy() { * @see ValidatingSessionManager#validateSessions() */ public void validateSessions() { - if (log.isInfoEnabled()) { - log.info("Validating all active sessions..."); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Validating all active sessions..."); } int invalidCount = 0; @@ -287,25 +285,25 @@ public void validateSessions() { SessionKey key = new DefaultSessionKey(s.getId()); validate(s, key); } catch (InvalidSessionException e) { - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { boolean expired = (e instanceof ExpiredSessionException); - String msg = "Invalidated session with id [" + s.getId() + "]" + - (expired ? " (expired)" : " (stopped)"); - log.debug(msg); + String msg = "Invalidated session with id [" + s.getId() + "]" + + (expired ? " (expired)" : " (stopped)"); + LOGGER.debug(msg); } invalidCount++; } } } - if (log.isInfoEnabled()) { + if (LOGGER.isInfoEnabled()) { String msg = "Finished session validation."; if (invalidCount > 0) { msg += " [" + invalidCount + "] sessions were stopped."; } else { msg += " No sessions were stopped."; } - log.info(msg); + LOGGER.info(msg); } } diff --git a/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java b/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java index c7e40cfcd1..604a9de425 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/DefaultSessionManager.java @@ -40,13 +40,13 @@ */ public class DefaultSessionManager extends AbstractValidatingSessionManager implements CacheManagerAware { - //TODO - complete JavaDoc + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSessionManager.class); - private static final Logger log = LoggerFactory.getLogger(DefaultSessionManager.class); + //todo - move SessionDAO up to AbstractValidatingSessionManager? + protected SessionDAO sessionDAO; - private SessionFactory sessionFactory; - protected SessionDAO sessionDAO; //todo - move SessionDAO up to AbstractValidatingSessionManager? + private SessionFactory sessionFactory; private CacheManager cacheManager; @@ -104,7 +104,7 @@ public void setSessionFactory(SessionFactory sessionFactory) { * some other means (cron, quartz, etc.). * * @return {@code true} if sessions should be automatically deleted after they are discovered to be invalid, - * {@code false} if invalid sessions will be manually deleted by some process external to Shiro's control. + * {@code false} if invalid sessions will be manually deleted by some process external to Shiro's control. * @since 1.0 */ public boolean isDeleteInvalidSessions() { @@ -152,8 +152,8 @@ private void applyCacheManagerToSessionDAO() { protected Session doCreateSession(SessionContext context) { Session s = newSessionInstance(context); - if (log.isTraceEnabled()) { - log.trace("Creating session for host {}", s.getHost()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Creating session for host {}", s.getHost()); } create(s); return s; @@ -171,8 +171,8 @@ protected Session newSessionInstance(SessionContext context) { * @param session the Session instance to persist to the underlying EIS. */ protected void create(Session session) { - if (log.isDebugEnabled()) { - log.debug("Creating new EIS record for new session instance [" + session + "]"); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Creating new EIS record for new session instance [" + session + "]"); } sessionDAO.create(session); } @@ -215,8 +215,8 @@ protected void onChange(Session session) { protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException { Serializable sessionId = getSessionId(sessionKey); if (sessionId == null) { - log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a " + - "session could not be found.", sessionKey); + LOGGER.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a " + + "session could not be found.", sessionKey); return null; } Session s = retrieveSessionFromDataSource(sessionId); diff --git a/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java b/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java index 115b008df0..1e38fdc511 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java @@ -47,8 +47,8 @@ public class DelegatingSession implements Session, Serializable { private final SessionKey key; //cached fields to avoid a server-side method call if out-of-process: - private Date startTimestamp = null; - private String host = null; + private Date startTimestamp; + private String host; /** * Handle to the target NativeSessionManager that will support the delegate calls. @@ -64,9 +64,9 @@ public DelegatingSession(NativeSessionManager sessionManager, SessionKey key) { throw new IllegalArgumentException("sessionKey argument cannot be null."); } if (key.getSessionId() == null) { - String msg = "The " + DelegatingSession.class.getName() + " implementation requires that the " + - "SessionKey argument returns a non-null sessionId to support the " + - "Session.getId() invocations."; + String msg = "The " + DelegatingSession.class.getName() + " implementation requires that the " + + "SessionKey argument returns a non-null sessionId to support the " + + "Session.getId() invocations."; throw new IllegalArgumentException(msg); } this.sessionManager = sessionManager; diff --git a/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java b/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java index fc10de7a96..72b16174a0 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java @@ -39,13 +39,15 @@ public class ExecutorServiceSessionValidationScheduler implements SessionValidat //TODO - complete JavaDoc - /** Private internal log instance. */ - private static final Logger log = LoggerFactory.getLogger(ExecutorServiceSessionValidationScheduler.class); + /** + * Private internal log instance. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(ExecutorServiceSessionValidationScheduler.class); ValidatingSessionManager sessionManager; private ScheduledExecutorService service; private long sessionValidationInterval = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL; - private boolean enabled = false; + private boolean enabled; private String threadNamePrefix = "SessionValidationThread-"; public ExecutorServiceSessionValidationScheduler() { @@ -85,47 +87,47 @@ public String getThreadNamePrefix() { } /** - * Creates a single thread {@link ScheduledExecutorService} to validate sessions at fixed intervals + * Creates a single thread {@link ScheduledExecutorService} to validate sessions at fixed intervals * and enables this scheduler. The executor is created as a daemon thread to allow JVM to shut down */ //TODO Implement an integration test to test for jvm exit as part of the standalone example // (so we don't have to change the unit test execution model for the core module) public void enableSessionValidation() { - if (this.sessionValidationInterval > 0l) { - this.service = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { - private final AtomicInteger count = new AtomicInteger(1); - - public Thread newThread(Runnable r) { - Thread thread = new Thread(r); - thread.setDaemon(true); - thread.setName(threadNamePrefix + count.getAndIncrement()); - return thread; - } - }); + if (this.sessionValidationInterval > 0L) { + this.service = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + private final AtomicInteger count = new AtomicInteger(1); + + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setDaemon(true); + thread.setName(threadNamePrefix + count.getAndIncrement()); + return thread; + } + }); this.service.scheduleAtFixedRate(this, sessionValidationInterval, - sessionValidationInterval, TimeUnit.MILLISECONDS); + sessionValidationInterval, TimeUnit.MILLISECONDS); } this.enabled = true; } public void run() { - if (log.isDebugEnabled()) { - log.debug("Executing session validation..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Executing session validation..."); } Thread.currentThread().setUncaughtExceptionHandler((t, e) -> { - log.error("Error while validating the session, the thread will be stopped and session validation disabled", e); + LOGGER.error("Error while validating the session, the thread will be stopped and session validation disabled", e); this.disableSessionValidation(); }); long startTime = System.currentTimeMillis(); try { this.sessionManager.validateSessions(); } catch (RuntimeException e) { - log.error("Error while validating the session", e); + LOGGER.error("Error while validating the session", e); //we don't stop the thread } long stopTime = System.currentTimeMillis(); - if (log.isDebugEnabled()) { - log.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds."); } } diff --git a/core/src/main/java/org/apache/shiro/session/mgt/ImmutableProxiedSession.java b/core/src/main/java/org/apache/shiro/session/mgt/ImmutableProxiedSession.java index 8b8c74a6bf..5f99f76a85 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/ImmutableProxiedSession.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/ImmutableProxiedSession.java @@ -58,8 +58,8 @@ public ImmutableProxiedSession(Session target) { * @throws InvalidSessionException in all cases - used by the Session 'write' method implementations. */ protected void throwImmutableException() throws InvalidSessionException { - String msg = "This session is immutable and read-only - it cannot be altered. This is usually because " + - "the session has been stopped or expired already."; + String msg = "This session is immutable and read-only - it cannot be altered. This is usually because " + + "the session has been stopped or expired already."; throw new InvalidSessionException(msg); } diff --git a/core/src/main/java/org/apache/shiro/session/mgt/NativeSessionManager.java b/core/src/main/java/org/apache/shiro/session/mgt/NativeSessionManager.java index 8c1259e48f..3e24bec6bb 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/NativeSessionManager.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/NativeSessionManager.java @@ -64,8 +64,8 @@ public interface NativeSessionManager extends SessionManager { * the reason for invalidation. * * @param key the session key to use to look up the target session. - * @throws org.apache.shiro.session.InvalidSessionException - * if the session id is invalid (it does not exist or it is stopped or expired). + * @throws org.apache.shiro.session.InvalidSessionException if the session id is invalid + * (it does not exist, or it is stopped or expired). */ void checkValid(SessionKey key) throws InvalidSessionException; @@ -79,8 +79,8 @@ public interface NativeSessionManager extends SessionManager { * * @param key the session key to use to look up the target session. * @return the time in milliseconds that the associated session may remain idle before expiring. - * @throws org.apache.shiro.session.InvalidSessionException - * if the session has been stopped or expired prior to calling this method. + * @throws org.apache.shiro.session.InvalidSessionException if the session has been stopped or + * expired prior to calling this method. */ long getTimeout(SessionKey key) throws InvalidSessionException; @@ -94,8 +94,8 @@ public interface NativeSessionManager extends SessionManager { * * @param key the session key to use to look up the target session. * @param maxIdleTimeInMillis the time in milliseconds that the associated session may remain idle before expiring. - * @throws org.apache.shiro.session.InvalidSessionException - * if the session has been stopped or expired prior to calling this method. + * @throws org.apache.shiro.session.InvalidSessionException if the session has been stopped + * or expired prior to calling this method. */ void setTimeout(SessionKey key, long maxIdleTimeInMillis) throws InvalidSessionException; @@ -104,8 +104,8 @@ public interface NativeSessionManager extends SessionManager { * can be used to explicitly ensure that a session does not time out. * * @param key the session key to use to look up the target session. - * @throws org.apache.shiro.session.InvalidSessionException - * if the session has been stopped or expired prior to calling this method. + * @throws org.apache.shiro.session.InvalidSessionException if the session has been stopped + * or expired prior to calling this method. * @see org.apache.shiro.session.Session#touch */ void touch(SessionKey key) throws InvalidSessionException; @@ -116,7 +116,7 @@ public interface NativeSessionManager extends SessionManager { * * @param key the session key to use to look up the target session. * @return the host name or ip address of the host where the session originated, if known. If unknown, - * this method returns {@code null}. + * this method returns {@code null}. */ String getHost(SessionKey key); diff --git a/core/src/main/java/org/apache/shiro/session/mgt/SessionContext.java b/core/src/main/java/org/apache/shiro/session/mgt/SessionContext.java index b5506df9bd..36471ed57f 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/SessionContext.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/SessionContext.java @@ -79,7 +79,7 @@ public interface SessionContext extends Map { * {@code Session} host. * * @return the originating host name or IP address (as a String) from where the {@code Subject} is initiating the - * {@code Session}. + * {@code Session}. * @see #setHost(String) setHost(String) */ String getHost(); diff --git a/core/src/main/java/org/apache/shiro/session/mgt/SessionManager.java b/core/src/main/java/org/apache/shiro/session/mgt/SessionManager.java index b23af5718d..593e158af7 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/SessionManager.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/SessionManager.java @@ -53,7 +53,7 @@ public interface SessionManager { * * @param key the Session key to use to look-up the Session * @return the {@code Session} instance corresponding to the given lookup key or {@code null} if no session - * could be acquired. + * could be acquired. * @throws SessionException if a session was found but it was invalid (stopped/expired). * @since 1.0 */ diff --git a/core/src/main/java/org/apache/shiro/session/mgt/SessionValidationScheduler.java b/core/src/main/java/org/apache/shiro/session/mgt/SessionValidationScheduler.java index 633239d68a..260b3c22fb 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/SessionValidationScheduler.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/SessionValidationScheduler.java @@ -20,7 +20,8 @@ /** * Interface that should be implemented by classes that can control validating sessions on a regular - * basis. This interface is used as a delegate for session validation by the {@link org.apache.shiro.session.mgt.DefaultSessionManager} + * basis. This interface is used as a delegate for session validation + * by the {@link org.apache.shiro.session.mgt.DefaultSessionManager} * * @see org.apache.shiro.session.mgt.DefaultSessionManager#setSessionValidationScheduler(SessionValidationScheduler) * @since 0.1 @@ -49,4 +50,4 @@ public interface SessionValidationScheduler { */ void disableSessionValidation(); -} \ No newline at end of file +} diff --git a/core/src/main/java/org/apache/shiro/session/mgt/SimpleSession.java b/core/src/main/java/org/apache/shiro/session/mgt/SimpleSession.java index e7101b4f1b..8b125a3184 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/SimpleSession.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/SimpleSession.java @@ -30,7 +30,11 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.text.DateFormat; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; /** @@ -39,8 +43,16 @@ * * @since 0.1 */ +@SuppressWarnings("checkstyle:MethodCount") public class SimpleSession implements ValidatingSession, Serializable { + protected static final long MILLIS_PER_SECOND = 1000; + protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; + protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; + + //serialization bitmask fields. DO NOT CHANGE THE ORDER THEY ARE DECLARED! + static int bitIndexCounter; + // Serialization reminder: // You _MUST_ change this number if you introduce a change to this class // that is NOT serialization backwards compatible. Serialization-compatible @@ -48,15 +60,7 @@ public class SimpleSession implements ValidatingSession, Serializable { // a new number in this case, use the JDK's 'serialver' program to generate it. private static final long serialVersionUID = -7125642695178165650L; - //TODO - complete JavaDoc - private transient static final Logger log = LoggerFactory.getLogger(SimpleSession.class); - - protected static final long MILLIS_PER_SECOND = 1000; - protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; - protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; - - //serialization bitmask fields. DO NOT CHANGE THE ORDER THEY ARE DECLARED! - static int bitIndexCounter = 0; + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSession.class); private static final int ID_BIT_MASK = 1 << bitIndexCounter++; private static final int START_TIMESTAMP_BIT_MASK = 1 << bitIndexCounter++; private static final int STOP_TIMESTAMP_BIT_MASK = 1 << bitIndexCounter++; @@ -93,7 +97,8 @@ public class SimpleSession implements ValidatingSession, Serializable { private transient Map attributes; public SimpleSession() { - this.timeout = DefaultSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT; //TODO - remove concrete reference to DefaultSessionManager + //TODO - remove concrete reference to DefaultSessionManager + this.timeout = DefaultSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT; this.startTimestamp = new Date(); this.lastAccessTime = this.startTimestamp; } @@ -134,7 +139,7 @@ public void setStartTimestamp(Date startTimestamp) { * Once stopped, a session may no longer be used. It is locked from all further activity. * * @return The time the session was stopped, or null if the session is still - * active. + * active. */ public Date getStopTimestamp() { return stopTimestamp; @@ -229,16 +234,16 @@ protected boolean isTimedOut() { long timeout = getTimeout(); - if (timeout >= 0l) { + if (timeout >= 0L) { Date lastAccessTime = getLastAccessTime(); if (lastAccessTime == null) { - String msg = "session.lastAccessTime for session with id [" + - getId() + "] is null. This value must be set at " + - "least once, preferably at least upon instantiation. Please check the " + - getClass().getName() + " implementation and ensure " + - "this value will be set (perhaps in the constructor?)"; + String msg = "session.lastAccessTime for session with id [" + + getId() + "] is null. This value must be set at " + + "least once, preferably at least upon instantiation. Please check the " + + getClass().getName() + " implementation and ensure " + + "this value will be set (perhaps in the constructor?)"; throw new IllegalStateException(msg); } @@ -251,9 +256,9 @@ protected boolean isTimedOut() { Date expireTime = new Date(expireTimeMillis); return lastAccessTime.before(expireTime); } else { - if (log.isTraceEnabled()) { - log.trace("No timeout for session with id [" + getId() + - "]. Session is not considered expired."); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("No timeout for session with id [" + getId() + + "]. Session is not considered expired."); } } @@ -264,9 +269,9 @@ public void validate() throws InvalidSessionException { //check for stopped: if (isStopped()) { //timestamp is set, so the session is considered stopped: - String msg = "Session with id [" + getId() + "] has been " + - "explicitly stopped. No further interaction under this session is " + - "allowed."; + String msg = "Session with id [" + getId() + "] has been " + + "explicitly stopped. No further interaction under this session is " + + "allowed."; throw new StoppedSessionException(msg); } @@ -281,13 +286,13 @@ public void validate() throws InvalidSessionException { Serializable sessionId = getId(); DateFormat df = DateFormat.getInstance(); - String msg = "Session with id [" + sessionId + "] has expired. " + - "Last access time: " + df.format(lastAccessTime) + - ". Current time: " + df.format(new Date()) + - ". Session timeout is set to " + timeout / MILLIS_PER_SECOND + " seconds (" + - timeout / MILLIS_PER_MINUTE + " minutes)"; - if (log.isTraceEnabled()) { - log.trace(msg); + String msg = "Session with id [" + sessionId + "] has expired. " + + "Last access time: " + df.format(lastAccessTime) + + ". Current time: " + df.format(new Date()) + + ". Session timeout is set to " + timeout / MILLIS_PER_SECOND + " seconds (" + + timeout / MILLIS_PER_MINUTE + " minutes)"; + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(msg); } throw new ExpiredSessionException(msg); } @@ -374,14 +379,16 @@ public boolean equals(Object obj) { * @return true if all the attributes, except the id, are equal to this object's attributes. * @since 1.0 */ + @SuppressWarnings({"checkstyle:BooleanExpressionComplexity", "checkstyle:MethodCount"}) protected boolean onEquals(SimpleSession ss) { - return (getStartTimestamp() != null ? getStartTimestamp().equals(ss.getStartTimestamp()) : ss.getStartTimestamp() == null) && - (getStopTimestamp() != null ? getStopTimestamp().equals(ss.getStopTimestamp()) : ss.getStopTimestamp() == null) && - (getLastAccessTime() != null ? getLastAccessTime().equals(ss.getLastAccessTime()) : ss.getLastAccessTime() == null) && - (getTimeout() == ss.getTimeout()) && - (isExpired() == ss.isExpired()) && - (getHost() != null ? getHost().equals(ss.getHost()) : ss.getHost() == null) && - (getAttributes() != null ? getAttributes().equals(ss.getAttributes()) : ss.getAttributes() == null); + return (getStartTimestamp() != null ? getStartTimestamp().equals(ss.getStartTimestamp()) : ss.getStartTimestamp() == null) + && (getStopTimestamp() != null ? getStopTimestamp().equals(ss.getStopTimestamp()) : ss.getStopTimestamp() == null) + && (getLastAccessTime() != null + ? getLastAccessTime().equals(ss.getLastAccessTime()) : ss.getLastAccessTime() == null) + && (getTimeout() == ss.getTimeout()) + && (isExpired() == ss.isExpired()) + && (getHost() != null ? getHost().equals(ss.getHost()) : ss.getHost() == null) + && (getAttributes() != null ? getAttributes().equals(ss.getAttributes()) : ss.getAttributes() == null); } /** @@ -415,7 +422,7 @@ public int hashCode() { * getClass().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 +439,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 +456,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 +478,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 +517,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 +540,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 Cache getActiveSessionsCache() { return this.activeSessions; @@ -162,7 +162,7 @@ private Cache getActiveSessionsCacheLazy() { * cacheManager.getCache(name);

    * * @return a cache instance used to store active sessions, or {@code null} if the {@code CacheManager} has - * not been set. + * not been set. */ protected Cache createActiveSessionsCache() { Cache cache = null; @@ -192,7 +192,7 @@ public Serializable create(Session session) { * * @param sessionId the id of the cached session to acquire. * @return the cached session with the corresponding {@code sessionId}, or {@code null} if the session - * does not exist or is not cached. + * does not exist or is not cached. */ protected Session getCachedSession(Serializable sessionId) { Session cached = null; diff --git a/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java b/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java index 0896fba51d..c131dfa156 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/eis/EnterpriseCacheSessionDAO.java @@ -67,9 +67,10 @@ protected Serializable doCreate(Session session) { } protected Session doReadSession(Serializable sessionId) { - return null; //should never execute because this implementation relies on parent class to access cache, which + //should never execute because this implementation relies on parent class to access cache, which //is where all sessions reside - it is the cache implementation that determines if the //cache is memory only or disk-persistent, etc. + return null; } protected void doUpdate(Session session) { diff --git a/core/src/main/java/org/apache/shiro/session/mgt/eis/MemorySessionDAO.java b/core/src/main/java/org/apache/shiro/session/mgt/eis/MemorySessionDAO.java index 0095a26800..aa07f99767 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/eis/MemorySessionDAO.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/eis/MemorySessionDAO.java @@ -55,9 +55,9 @@ */ public class MemorySessionDAO extends AbstractSessionDAO { - private static final Logger log = LoggerFactory.getLogger(MemorySessionDAO.class); + private static final Logger LOGGER = LoggerFactory.getLogger(MemorySessionDAO.class); - private ConcurrentMap sessions; + private final ConcurrentMap sessions; public MemorySessionDAO() { this.sessions = new ConcurrentHashMap(); diff --git a/core/src/main/java/org/apache/shiro/session/mgt/eis/RandomSessionIdGenerator.java b/core/src/main/java/org/apache/shiro/session/mgt/eis/RandomSessionIdGenerator.java index 09cf0ccf74..d4249cd701 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/eis/RandomSessionIdGenerator.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/eis/RandomSessionIdGenerator.java @@ -33,7 +33,7 @@ */ public class RandomSessionIdGenerator implements SessionIdGenerator { - private static final Logger log = LoggerFactory.getLogger(RandomSessionIdGenerator.class); + private static final Logger LOGGER = LoggerFactory.getLogger(RandomSessionIdGenerator.class); private static final String RANDOM_NUM_GENERATOR_ALGORITHM_NAME = "SHA1PRNG"; private Random random; @@ -42,8 +42,8 @@ public RandomSessionIdGenerator() { try { this.random = java.security.SecureRandom.getInstance(RANDOM_NUM_GENERATOR_ALGORITHM_NAME); } catch (java.security.NoSuchAlgorithmException e) { - log.debug("The SecureRandom SHA1PRNG algorithm is not available on the current platform. Using the " + - "platform's default SecureRandom algorithm.", e); + LOGGER.debug("The SecureRandom SHA1PRNG algorithm is not available on the current platform. Using the " + + "platform's default SecureRandom algorithm.", e); this.random = new java.security.SecureRandom(); } } diff --git a/core/src/main/java/org/apache/shiro/session/mgt/eis/SessionDAO.java b/core/src/main/java/org/apache/shiro/session/mgt/eis/SessionDAO.java index 04722eba6e..ce831e4738 100644 --- a/core/src/main/java/org/apache/shiro/session/mgt/eis/SessionDAO.java +++ b/core/src/main/java/org/apache/shiro/session/mgt/eis/SessionDAO.java @@ -82,9 +82,8 @@ public interface SessionDAO { * errors. * * @param session the Session to update - * @throws org.apache.shiro.session.UnknownSessionException - * if no existing EIS session record exists with the - * identifier of {@link Session#getId() session.getSessionId()} + * @throws org.apache.shiro.session.UnknownSessionException if no existing EIS session record exists with the + * identifier of {@link Session#getId() session.getSessionId()} */ void update(Session session) throws UnknownSessionException; @@ -124,7 +123,7 @@ public interface SessionDAO { * (e.g. now - 30 minutes). * * @return a Collection of {@code Session}s that are considered active, or an - * empty collection or {@code null} if there are no active sessions. + * empty collection or {@code null} if there are no active sessions. */ Collection getActiveSessions(); } diff --git a/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java b/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java index 75da30c286..1de2cc3ad1 100644 --- a/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java +++ b/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java @@ -18,6 +18,10 @@ */ package org.apache.shiro.subject; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.pam.AuthenticationStrategy; + import java.io.Serializable; import java.util.Collection; import java.util.List; @@ -68,7 +72,8 @@ public interface PrincipalCollection extends Iterable, Serializable { * If this heuristic is not sufficient, most Shiro end-users will need to implement a custom * {@link org.apache.shiro.authc.pam.AuthenticationStrategy}. An {@code AuthenticationStrategy} has exact control * over the {@link PrincipalCollection} returned at the end of an authentication attempt via the - * AuthenticationStrategy#{@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. */ Collection byType(Class type); @@ -127,7 +132,7 @@ public interface PrincipalCollection extends Iterable, Serializable { * * @param realmName the name of the Realm from which the principals were retrieved. * @return the Subject's principals from the specified Realm only as a Collection or an empty Collection if there - * are not any principals from that realm. + * are not any principals from that realm. */ Collection fromRealm(String realmName); diff --git a/core/src/main/java/org/apache/shiro/subject/PrincipalMap.java b/core/src/main/java/org/apache/shiro/subject/PrincipalMap.java index 3c5841718d..d08a73c430 100644 --- a/core/src/main/java/org/apache/shiro/subject/PrincipalMap.java +++ b/core/src/main/java/org/apache/shiro/subject/PrincipalMap.java @@ -47,11 +47,11 @@ * * @since 1.2 */ -public interface PrincipalMap extends PrincipalCollection, Map { +public interface PrincipalMap extends PrincipalCollection, Map { - Map getRealmPrincipals(String realmName); + Map getRealmPrincipals(String realmName); - Map setRealmPrincipals(String realmName, Map principals); + Map setRealmPrincipals(String realmName, Map principals); Object setRealmPrincipal(String realmName, String principalName, Object principal); diff --git a/core/src/main/java/org/apache/shiro/subject/SimplePrincipalCollection.java b/core/src/main/java/org/apache/shiro/subject/SimplePrincipalCollection.java index 080c831b19..daf47e81ad 100644 --- a/core/src/main/java/org/apache/shiro/subject/SimplePrincipalCollection.java +++ b/core/src/main/java/org/apache/shiro/subject/SimplePrincipalCollection.java @@ -24,8 +24,16 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.*; - +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; /** * A simple implementation of the {@link MutablePrincipalCollection} interface that tracks principals internally @@ -44,10 +52,10 @@ public class SimplePrincipalCollection implements MutablePrincipalCollection { private static final long serialVersionUID = -6305224034025797558L; //TODO - complete JavaDoc - private Map realmPrincipals; - private transient String cachedToString; //cached toString() result, as this can be printed many times in logging + //cached toString() result, as this can be printed many times in logging + private transient String cachedToString; public SimplePrincipalCollection() { } @@ -229,7 +237,7 @@ public boolean equals(Object o) { } if (o instanceof SimplePrincipalCollection) { SimplePrincipalCollection other = (SimplePrincipalCollection) o; - return this.realmPrincipals != null ? this.realmPrincipals.equals(other.realmPrincipals) : other.realmPrincipals == null; + return Objects.equals(this.realmPrincipals, other.realmPrincipals); } return false; } diff --git a/core/src/main/java/org/apache/shiro/subject/SimplePrincipalMap.java b/core/src/main/java/org/apache/shiro/subject/SimplePrincipalMap.java index 258ac88a1f..e2b3e69b5e 100644 --- a/core/src/main/java/org/apache/shiro/subject/SimplePrincipalMap.java +++ b/core/src/main/java/org/apache/shiro/subject/SimplePrincipalMap.java @@ -20,11 +20,19 @@ import org.apache.shiro.util.CollectionUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * Default implementation of the {@link PrincipalMap} interface. - * + *

    * *EXPERIMENTAL for Shiro 1.2 - DO NOT USE YET* * * @since 1.2 @@ -48,7 +56,7 @@ public SimplePrincipalMap(Map> backingMap) { if (!CollectionUtils.isEmpty(backingMap)) { this.realmPrincipals = backingMap; for (Map principals : this.realmPrincipals.values()) { - if (!CollectionUtils.isEmpty(principals) ) { + if (!CollectionUtils.isEmpty(principals)) { ensureCombinedPrincipals().putAll(principals); } } @@ -93,21 +101,18 @@ public void putAll(Map map) { } public Set keySet() { - return CollectionUtils.isEmpty(this.combinedPrincipals) ? - Collections.emptySet() : - Collections.unmodifiableSet(this.combinedPrincipals.keySet()); + return CollectionUtils.isEmpty(this.combinedPrincipals) ? Collections.emptySet() + : Collections.unmodifiableSet(this.combinedPrincipals.keySet()); } public Collection values() { - return CollectionUtils.isEmpty(this.combinedPrincipals) ? - Collections.emptySet() : - Collections.unmodifiableCollection(this.combinedPrincipals.values()); + return CollectionUtils.isEmpty(this.combinedPrincipals) ? Collections.emptySet() + : Collections.unmodifiableCollection(this.combinedPrincipals.values()); } public Set> entrySet() { - return CollectionUtils.isEmpty(this.combinedPrincipals) ? - Collections.>emptySet() : - Collections.unmodifiableSet(this.combinedPrincipals.entrySet()); + return CollectionUtils.isEmpty(this.combinedPrincipals) + ? Collections.>emptySet() : Collections.unmodifiableSet(this.combinedPrincipals.entrySet()); } public void clear() { @@ -117,17 +122,15 @@ public void clear() { public Object getPrimaryPrincipal() { //heuristic - just use the first one we come across: - return !CollectionUtils.isEmpty(this.combinedPrincipals) ? - this.combinedPrincipals.values().iterator().next() : - null; + return !CollectionUtils.isEmpty(this.combinedPrincipals) ? this.combinedPrincipals.values().iterator().next() : null; } public T oneByType(Class type) { if (CollectionUtils.isEmpty(this.combinedPrincipals)) { return null; } - for( Object value : this.combinedPrincipals.values()) { - if (type.isInstance(value) ) { + for (Object value : this.combinedPrincipals.values()) { + if (type.isInstance(value)) { return type.cast(value); } } @@ -139,8 +142,8 @@ public Collection byType(Class type) { return Collections.emptySet(); } Collection instances = null; - for( Object value : this.combinedPrincipals.values()) { - if (type.isInstance(value) ) { + for (Object value : this.combinedPrincipals.values()) { + if (type.isInstance(value)) { if (instances == null) { instances = new ArrayList(); } @@ -172,7 +175,7 @@ public Collection fromRealm(String realmName) { if (CollectionUtils.isEmpty(this.realmPrincipals)) { return Collections.emptySet(); } - Map principals = this.realmPrincipals.get(realmName); + Map principals = this.realmPrincipals.get(realmName); if (CollectionUtils.isEmpty(principals)) { return Collections.emptySet(); } @@ -198,28 +201,28 @@ public Map getRealmPrincipals(String name) { if (this.realmPrincipals == null) { return null; } - Map principals = this.realmPrincipals.get(name); + Map principals = this.realmPrincipals.get(name); if (principals == null) { return null; } return Collections.unmodifiableMap(principals); } - public Map setRealmPrincipals(String realmName, Map principals) { + public Map setRealmPrincipals(String realmName, Map principals) { if (realmName == null) { throw new NullPointerException("realmName argument cannot be null."); } if (this.realmPrincipals == null) { if (!CollectionUtils.isEmpty(principals)) { - this.realmPrincipals = new HashMap>(); - return this.realmPrincipals.put(realmName, new HashMap(principals)); + this.realmPrincipals = new HashMap>(); + return this.realmPrincipals.put(realmName, new HashMap(principals)); } else { return null; } } else { - Map existingPrincipals = this.realmPrincipals.remove(realmName); + Map existingPrincipals = this.realmPrincipals.remove(realmName); if (!CollectionUtils.isEmpty(principals)) { - this.realmPrincipals.put(realmName, new HashMap(principals)); + this.realmPrincipals.put(realmName, new HashMap(principals)); } return existingPrincipals; } @@ -236,11 +239,11 @@ public Object setRealmPrincipal(String realmName, String principalName, Object p return removeRealmPrincipal(realmName, principalName); } if (this.realmPrincipals == null) { - this.realmPrincipals = new HashMap>(); + this.realmPrincipals = new HashMap>(); } - Map principals = this.realmPrincipals.get(realmName); + Map principals = this.realmPrincipals.get(realmName); if (principals == null) { - principals = new HashMap(); + principals = new HashMap(); this.realmPrincipals.put(realmName, principals); } return principals.put(principalName, principal); @@ -256,7 +259,7 @@ public Object getRealmPrincipal(String realmName, String principalName) { if (this.realmPrincipals == null) { return null; } - Map principals = this.realmPrincipals.get(realmName); + Map principals = this.realmPrincipals.get(realmName); if (principals != null) { return principals.get(principalName); } @@ -273,7 +276,7 @@ public Object removeRealmPrincipal(String realmName, String principalName) { if (this.realmPrincipals == null) { return null; } - Map principals = this.realmPrincipals.get(realmName); + Map principals = this.realmPrincipals.get(realmName); if (principals != null) { return principals.remove(principalName); } diff --git a/core/src/main/java/org/apache/shiro/subject/Subject.java b/core/src/main/java/org/apache/shiro/subject/Subject.java index 8599c7d548..7b1c83f967 100644 --- a/core/src/main/java/org/apache/shiro/subject/Subject.java +++ b/core/src/main/java/org/apache/shiro/subject/Subject.java @@ -57,6 +57,7 @@ * * @since 0.1 */ +@SuppressWarnings("checkstyle:MethodCount") public interface Subject { /** @@ -83,7 +84,8 @@ public interface Subject { * or any other similar suitable unique mechanism valuable to your application. *

    * Most implementations will simply return - * {@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 permissions); @@ -200,8 +202,7 @@ public interface Subject { * Please see the class-level JavaDoc for more information on these String-based permission methods. * * @param permission the String representation of the Permission to check. - * @throws org.apache.shiro.authz.AuthorizationException - * if the user does not have the permission. + * @throws org.apache.shiro.authz.AuthorizationException if the user does not have the permission. * @since 0.9 */ void checkPermission(String permission) throws AuthorizationException; @@ -213,8 +214,7 @@ public interface Subject { * the given permission, an {@link org.apache.shiro.authz.AuthorizationException} will be thrown. * * @param permission the Permission to check. - * @throws org.apache.shiro.authz.AuthorizationException - * if this Subject does not have the permission. + * @throws org.apache.shiro.authz.AuthorizationException if this Subject does not have the permission. */ void checkPermission(Permission permission) throws AuthorizationException; @@ -267,8 +267,8 @@ public interface Subject { * * @param roleIdentifiers the application-specific role identifiers to check (usually role ids or role names). * @return a boolean array where indices correspond to the index of the - * roles in the given identifiers. A true value indicates this Subject has the - * role at that index. False indicates this Subject does not have the role at that index. + * roles in the given identifiers. A true value indicates this Subject has the + * role at that index. False indicates this Subject does not have the role at that index. */ boolean[] hasRoles(List roleIdentifiers); @@ -285,8 +285,7 @@ public interface Subject { * {@link org.apache.shiro.authz.AuthorizationException} if they do not. * * @param roleIdentifier the application-specific role identifier (usually a role id or role name ). - * @throws org.apache.shiro.authz.AuthorizationException - * if this Subject does not have the role. + * @throws org.apache.shiro.authz.AuthorizationException if this Subject does not have the role. */ void checkRole(String roleIdentifier) throws AuthorizationException; @@ -295,8 +294,7 @@ public interface Subject { * {@link org.apache.shiro.authz.AuthorizationException} if they do not. * * @param roleIdentifiers the application-specific role identifiers to check (usually role ids or role names). - * @throws org.apache.shiro.authz.AuthorizationException - * if this Subject does not have all of the specified roles. + * @throws org.apache.shiro.authz.AuthorizationException if this Subject does not have all of the specified roles. */ void checkRoles(Collection roleIdentifiers) throws AuthorizationException; @@ -308,7 +306,7 @@ public interface Subject { * * @param roleIdentifiers roleIdentifiers the application-specific role identifiers to check (usually role ids or role names). * @throws AuthorizationException org.apache.shiro.authz.AuthorizationException - * if this Subject does not have all of the specified roles. + * if this Subject does not have all of the specified roles. * @since 1.1.0 */ void checkRoles(String... roleIdentifiers) throws AuthorizationException; @@ -325,8 +323,7 @@ public interface Subject { * * @param token the token encapsulating the subject's principals and credentials to be passed to the * Authentication subsystem for verification. - * @throws org.apache.shiro.authc.AuthenticationException - * if the authentication attempt fails. + * @throws org.apache.shiro.authc.AuthenticationException if the authentication attempt fails. * @since 0.9 */ void login(AuthenticationToken token) throws AuthenticationException; @@ -340,7 +337,7 @@ public interface Subject { * current session. See the {@link #isRemembered() isRemembered()} method JavaDoc for more. * * @return {@code true} if this Subject proved their identity during their current session - * by providing valid credentials matching those known to the system, {@code false} otherwise. + * by providing valid credentials matching those known to the system, {@code false} otherwise. * @since 0.9 */ boolean isAuthenticated(); @@ -392,7 +389,7 @@ public interface Subject { * check this guarantee via the {@link #isAuthenticated() isAuthenticated()} method and not via this method. * * @return {@code true} if this {@code Subject}'s identity (aka {@link #getPrincipals() principals}) is - * remembered from a successful authentication during a previous session, {@code false} otherwise. + * remembered from a successful authentication during a previous session, {@code false} otherwise. * @since 1.0 */ boolean isRemembered(); @@ -420,7 +417,7 @@ public interface Subject { * * @param create boolean argument determining if a new session should be created or not if there is no existing session. * @return the application {@code Session} associated with this {@code Subject} or {@code null} based - * on the above described logic. + * on the above described logic. * @since 0.2 */ Session getSession(boolean create); @@ -534,7 +531,7 @@ public interface Subject { * information. * * @return {@code true} if this {@code Subject} is 'running as' another identity other than its original one or - * {@code false} otherwise (normal {@code Subject} state). + * {@code false} otherwise (normal {@code Subject} state). * @see #runAs * @since 1.0 */ @@ -546,8 +543,8 @@ public interface Subject { * identity (normal state). See the {@link #runAs runAs} method for more information. * * @return the previous 'pre run as' identity of this {@code Subject} before assuming the current - * {@link #runAs runAs} identity, or {@code null} if this {@code Subject} is not operating under an assumed - * identity (normal state). + * {@link #runAs runAs} identity, or {@code null} if this {@code Subject} is not operating under an assumed + * identity (normal state). * @see #runAs * @since 1.0 */ @@ -561,7 +558,7 @@ public interface Subject { * operating under an assumed identity. * * @return the 'run as' (assumed) identity being released or {@code null} if this {@code Subject} is not operating - * under an assumed identity. + * under an assumed identity. * @see #runAs * @since 1.0 */ @@ -604,7 +601,7 @@ public interface Subject { * * @since 1.0 */ - public static class Builder { + class Builder { /** * Hold all contextual data via the Builder instance's method invocations to be sent to the @@ -639,8 +636,8 @@ public Builder(SecurityManager securityManager) { this.securityManager = securityManager; this.subjectContext = newSubjectContextInstance(); if (this.subjectContext == null) { - throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + - "cannot be null."); + throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + + "cannot be null."); } this.subjectContext.setSecurityManager(securityManager); } @@ -737,7 +734,8 @@ public Builder session(Session session) { * was named "{@code myRealm}", you might create the '{@code jsmith} {@code Subject} instance this * way: *

    -         * PrincipalCollection identity = new {@link org.apache.shiro.subject.SimplePrincipalCollection#SimplePrincipalCollection(Object, String) SimplePrincipalCollection}("jsmith", "myRealm");
    +         * PrincipalCollection identity = new {@link 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 +744,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 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 +838,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 Map { * {@code null} if one has not yet been provided to this context. * * @return the SecurityManager instance that should be used to back the constructed {@link Subject} instance or - * {@code null} if one has not yet been provided to this context. + * {@code null} if one has not yet been provided to this context. */ SecurityManager getSecurityManager(); @@ -78,10 +78,11 @@ public interface SubjectContext extends Map { /** * Resolves the {@code SecurityManager} instance that should be used to back the constructed {@link Subject} - * instance (typically used to support {@link org.apache.shiro.subject.support.DelegatingSubject DelegatingSubject} implementations). + * instance (typically used to support + * {@link org.apache.shiro.subject.support.DelegatingSubject DelegatingSubject} implementations). * * @return the {@code SecurityManager} instance that should be used to back the constructed {@link Subject} - * instance + * instance */ SecurityManager resolveSecurityManager(); @@ -116,7 +117,7 @@ public interface SubjectContext extends Map { * newly authenticated instance. * * @return any existing {@code Subject} that may be in use at the time the new {@code Subject} instance is - * being created. + * being created. */ Subject getSubject(); @@ -176,7 +177,7 @@ public interface SubjectContext extends Map { * reason for ignoring Shiro's default authentication state mechanisms. * * @return {@code true} if the constructed {@code Subject} should be considered authenticated, {@code false} - * otherwise. + * otherwise. */ boolean isAuthenticated(); @@ -204,7 +205,7 @@ public interface SubjectContext extends Map { * {@code false} otherwise. * * @param enabled whether or not the constructed {@code Subject} instance should be allowed to create a session, - * {@code false} otherwise. + * {@code false} otherwise. * @since 1.2 */ void setSessionCreationEnabled(boolean enabled); diff --git a/core/src/main/java/org/apache/shiro/subject/support/DefaultSubjectContext.java b/core/src/main/java/org/apache/shiro/subject/support/DefaultSubjectContext.java index 5e888258bd..b2d9d99986 100644 --- a/core/src/main/java/org/apache/shiro/subject/support/DefaultSubjectContext.java +++ b/core/src/main/java/org/apache/shiro/subject/support/DefaultSubjectContext.java @@ -46,6 +46,21 @@ */ public class DefaultSubjectContext extends MapContext implements SubjectContext { + /** + * session creation enabled key. + */ + public static final String SESSION_CREATION_ENABLED = DefaultSubjectContext.class.getName() + ".SESSION_CREATION_ENABLED"; + + /** + * The session key that is used to store subject principals. + */ + public static final String PRINCIPALS_SESSION_KEY = DefaultSubjectContext.class.getName() + "_PRINCIPALS_SESSION_KEY"; + + /** + * The session key that is used to store whether or not the user is authenticated. + */ + public static final String AUTHENTICATED_SESSION_KEY = DefaultSubjectContext.class.getName() + "_AUTHENTICATED_SESSION_KEY"; + private static final String SECURITY_MANAGER = DefaultSubjectContext.class.getName() + ".SECURITY_MANAGER"; private static final String SESSION_ID = DefaultSubjectContext.class.getName() + ".SESSION_ID"; @@ -64,19 +79,7 @@ public class DefaultSubjectContext extends MapContext implements SubjectContext private static final String HOST = DefaultSubjectContext.class.getName() + ".HOST"; - public static final String SESSION_CREATION_ENABLED = DefaultSubjectContext.class.getName() + ".SESSION_CREATION_ENABLED"; - - /** - * The session key that is used to store subject principals. - */ - public static final String PRINCIPALS_SESSION_KEY = DefaultSubjectContext.class.getName() + "_PRINCIPALS_SESSION_KEY"; - - /** - * The session key that is used to store whether or not the user is authenticated. - */ - public static final String AUTHENTICATED_SESSION_KEY = DefaultSubjectContext.class.getName() + "_AUTHENTICATED_SESSION_KEY"; - - private static final transient Logger log = LoggerFactory.getLogger(DefaultSubjectContext.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSubjectContext.class); public DefaultSubjectContext() { super(); @@ -97,15 +100,15 @@ public void setSecurityManager(SecurityManager securityManager) { public SecurityManager resolveSecurityManager() { SecurityManager securityManager = getSecurityManager(); if (securityManager == null) { - if (log.isDebugEnabled()) { - log.debug("No SecurityManager available in subject context map. " + - "Falling back to SecurityUtils.getSecurityManager() lookup."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No SecurityManager available in subject context map. " + + "Falling back to SecurityUtils.getSecurityManager() lookup."); } try { securityManager = SecurityUtils.getSecurityManager(); } catch (UnavailableSecurityManagerException e) { - if (log.isDebugEnabled()) { - log.debug("No SecurityManager available via SecurityUtils. Heuristics exhausted.", e); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("No SecurityManager available via SecurityUtils. Heuristics exhausted.", e); } } } diff --git a/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java b/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java index 5605da2d46..d5c19c440d 100644 --- a/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java +++ b/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java @@ -69,9 +69,10 @@ * * @since 0.1 */ +@SuppressWarnings("checkstyle:MethodCount") public class DelegatingSubject implements Subject { - private static final Logger log = LoggerFactory.getLogger(DelegatingSubject.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DelegatingSubject.class); private static final String RUN_AS_PRINCIPALS_SESSION_KEY = DelegatingSubject.class.getName() + ".RUN_AS_PRINCIPALS_SESSION_KEY"; @@ -193,14 +194,14 @@ public boolean isPermittedAll(Collection permissions) { protected void assertAuthzCheckPossible() throws AuthorizationException { if (!hasPrincipals()) { - String msg = "This subject is anonymous - it does not have any identifying principals and " + - "authorization operations require an identity to check against. A Subject instance will " + - "acquire these identifying principals automatically after a successful login is performed " + - "be executing " + Subject.class.getName() + ".login(AuthenticationToken) or when 'Remember Me' " + - "functionality is enabled by the SecurityManager. This exception can also occur when a " + - "previously logged-in Subject has logged out which " + - "makes it anonymous again. Because an identity is currently not known due to any of these " + - "conditions, authorization is denied."; + String msg = "This subject is anonymous - it does not have any identifying principals and " + + "authorization operations require an identity to check against. A Subject instance will " + + "acquire these identifying principals automatically after a successful login is performed " + + "be executing " + Subject.class.getName() + ".login(AuthenticationToken) or when 'Remember Me' " + + "functionality is enabled by the SecurityManager. This exception can also occur when a " + + "previously logged-in Subject has logged out which " + + "makes it anonymous again. Because an identity is currently not known due to any of these " + + "conditions, authorization is denied."; throw new UnauthenticatedException(msg); } } @@ -274,8 +275,8 @@ public void login(AuthenticationToken token) throws AuthenticationException { } if (principals == null || principals.isEmpty()) { - String msg = "Principals returned from securityManager.login( token ) returned a null or " + - "empty value. This value must be non null and populated with one or more elements."; + String msg = "Principals returned from securityManager.login( token ) returned a null or " + + "empty value. This value must be non null and populated with one or more elements."; throw new IllegalStateException(msg); } this.principals = principals; @@ -318,25 +319,25 @@ public Session getSession() { } public Session getSession(boolean create) { - if (log.isTraceEnabled()) { - log.trace("attempting to get session; create = " + create + - "; session is null = " + (this.session == null) + - "; session has id = " + (this.session != null && session.getId() != null)); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("attempting to get session; create = " + create + + "; session is null = " + (this.session == null) + + "; session has id = " + (this.session != null && session.getId() != null)); } if (this.session == null && create) { //added in 1.2: if (!isSessionCreationEnabled()) { - String msg = "Session creation has been disabled for the current subject. This exception indicates " + - "that there is either a programming error (using a session when it should never be " + - "used) or that Shiro's configuration needs to be adjusted to allow Sessions to be created " + - "for the current Subject. See the " + DisabledSessionException.class.getName() + " JavaDoc " + - "for more."; + String msg = "Session creation has been disabled for the current subject. This exception indicates " + + "that there is either a programming error (using a session when it should never be " + + "used) or that Shiro's configuration needs to be adjusted to allow Sessions to be created " + + "for the current Subject. See the " + DisabledSessionException.class.getName() + " JavaDoc " + + "for more."; throw new DisabledSessionException(msg); } - log.trace("Starting session for host {}", getHost()); + LOGGER.trace("Starting session for host {}", getHost()); SessionContext sessionContext = createSessionContext(); Session session = this.securityManager.start(sessionContext); this.session = decorate(session); @@ -357,8 +358,8 @@ private void clearRunAsIdentitiesInternal() { try { clearRunAsIdentities(); } catch (SessionException se) { - log.debug("Encountered session exception trying to clear 'runAs' identities during logout. This " + - "can generally safely be ignored.", se); + LOGGER.debug("Encountered session exception trying to clear 'runAs' identities during logout. This " + + "can generally safely be ignored.", se); } } @@ -402,16 +403,16 @@ public Callable associateWith(Callable callable) { public Runnable associateWith(Runnable runnable) { if (runnable instanceof Thread) { - String msg = "This implementation does not support Thread arguments because of JDK ThreadLocal " + - "inheritance mechanisms required by Shiro. Instead, the method argument should be a non-Thread " + - "Runnable and the return value from this method can then be given to an ExecutorService or " + - "another Thread."; + String msg = "This implementation does not support Thread arguments because of JDK ThreadLocal " + + "inheritance mechanisms required by Shiro. Instead, the method argument should be a non-Thread " + + "Runnable and the return value from this method can then be given to an ExecutorService or " + + "another Thread."; throw new UnsupportedOperationException(msg); } return new SubjectRunnable(this, runnable); } - private class StoppingAwareProxiedSession extends ProxiedSession { + private static final class StoppingAwareProxiedSession extends ProxiedSession { private final DelegatingSubject owner; @@ -433,10 +434,10 @@ public void stop() throws InvalidSessionException { public void runAs(PrincipalCollection principals) { if (!hasPrincipals()) { - String msg = "This subject does not yet have an identity. Assuming the identity of another " + - "Subject is only allowed for Subjects with an existing identity. Try logging this subject in " + - "first, or using the " + Subject.Builder.class.getName() + " to build ad hoc Subject instances " + - "with identities as necessary."; + String msg = "This subject does not yet have an identity. Assuming the identity of another " + + "Subject is only allowed for Subjects with an existing identity. Try logging this subject in " + + "first, or using the " + Subject.Builder.class.getName() + " to build ad hoc Subject instances " + + "with identities as necessary."; throw new IllegalStateException(msg); } pushIdentity(principals); @@ -478,7 +479,7 @@ private List getRunAsPrincipalsStack() { // this thread could throw this exception, so we catch it // similar issue as in clearRunAsIdentitiesInternal() // See https://issues.apache.org/jira/browse/SHIRO-512 - log.debug("Encountered session exception trying to get 'runAs' principal stack. This " + LOGGER.debug("Encountered session exception trying to get 'runAs' principal stack. This " + "can generally safely be ignored.", se); } } @@ -529,12 +530,12 @@ private PrincipalCollection popIdentity() { @Override public String toString() { return new StringJoiner(", ", "DelegatingSubject{", "}") - .add("principals=" + principals) - .add("authenticated=" + authenticated) - .add("host='******") - .add("session='******'") - .add("sessionCreationEnabled=" + sessionCreationEnabled) - .add("securityManager=" + securityManager) - .toString(); + .add("principals=" + principals) + .add("authenticated=" + authenticated) + .add("host='******") + .add("session='******'") + .add("sessionCreationEnabled=" + sessionCreationEnabled) + .add("securityManager=" + securityManager) + .toString(); } } diff --git a/core/src/main/java/org/apache/shiro/subject/support/SubjectCallable.java b/core/src/main/java/org/apache/shiro/subject/support/SubjectCallable.java index d23971b7b4..d6d1ecfcbd 100644 --- a/core/src/main/java/org/apache/shiro/subject/support/SubjectCallable.java +++ b/core/src/main/java/org/apache/shiro/subject/support/SubjectCallable.java @@ -44,7 +44,7 @@ * invocations. It also guarantees that the running thread remains 'clean' in any thread-pooled environments. * *

    Usage

    - * + *

    * 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 V * @see Subject#associateWith(Callable) * @see org.apache.shiro.concurrent.SubjectAwareExecutorService SubjectAwareExecutorService * @since 1.0 diff --git a/core/src/main/java/org/apache/shiro/subject/support/SubjectRunnable.java b/core/src/main/java/org/apache/shiro/subject/support/SubjectRunnable.java index 9e633dd411..42eeb61bdb 100644 --- a/core/src/main/java/org/apache/shiro/subject/support/SubjectRunnable.java +++ b/core/src/main/java/org/apache/shiro/subject/support/SubjectRunnable.java @@ -40,7 +40,7 @@ *

    * *

    Usage

    - * + *

    * 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 T * @since 1.0 */ public abstract class AbstractFactory implements Factory { diff --git a/core/src/main/java/org/apache/shiro/util/AntPathMatcher.java b/core/src/main/java/org/apache/shiro/util/AntPathMatcher.java index 29f1511806..0c31e306e4 100644 --- a/core/src/main/java/org/apache/shiro/util/AntPathMatcher.java +++ b/core/src/main/java/org/apache/shiro/util/AntPathMatcher.java @@ -80,7 +80,9 @@ public void setPathSeparator(String pathSeparator) { } /** - * Checks if {@code path} is a pattern (i.e. contains a '*', or '?'). For example the {@code /foo/**} would return {@code true}, while {@code /bar/} would return {@code false}. + * Checks if {@code path} is a pattern (i.e. contains a '*', or '?'). + * For example the {@code /foo/**} would return {@code true}, while {@code /bar/} would return {@code false}. + * * @param path the string to check * @return this method returns {@code true} if {@code path} contains a '*' or '?', otherwise, {@code false} */ @@ -103,7 +105,6 @@ public boolean matchStart(String pattern, String path) { return doMatch(pattern, path, false); } - /** * Actually match the given 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 Set asSet(E... elements) { if (elements == null || elements.length == 0) { @@ -57,7 +58,7 @@ public static Set asSet(E... elements) { * * @param c the collection to check * @return {@code true} if the specified {@code Collection} is {@code null} or {@link Collection#isEmpty empty}, - * {@code false} otherwise. + * {@code false} otherwise. * @since 1.0 */ public static boolean isEmpty(Collection c) { @@ -70,7 +71,7 @@ public static boolean isEmpty(Collection c) { * * @param m the {@code Map} to check * @return {@code true} if the specified {@code Map} is {@code null} or {@link Map#isEmpty empty}, - * {@code false} otherwise. + * {@code false} otherwise. * @since 1.0 */ public static boolean isEmpty(Map m) { @@ -106,7 +107,7 @@ public static int size(Map m) { * * @param principals the principals to check. * @return {@code true} if the specified {@code PrincipalCollection} is {@code null} or - * {@link PrincipalCollection#isEmpty empty}, {@code false} otherwise. + * {@link PrincipalCollection#isEmpty empty}, {@code false} otherwise. * @since 1.0 * @deprecated Use PrincipalCollection.isEmpty() directly. */ @@ -134,7 +135,7 @@ public static List asList(E... elements) { Collections.addAll(deque, elements); return deque; }*/ - + @SuppressWarnings("checkstyle:MagicNumber") static int computeListCapacity(int arraySize) { return (int) Math.min(5L + arraySize + (arraySize / 10), Integer.MAX_VALUE); } diff --git a/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java b/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java index 3a9e1bbef7..5d752d2789 100644 --- a/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java +++ b/core/src/main/java/org/apache/shiro/util/JavaEnvironment.java @@ -66,14 +66,16 @@ public abstract class JavaEnvironment { */ public static final int JAVA_18 = 5; - /** The virtual machine version, i.e. 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 E getTypedValue(String key, Class type) { Object o = backingMap.get(key); if (o != null) { if (!type.isAssignableFrom(o.getClass())) { - String msg = "Invalid object found in SubjectContext Map under key [" + key + "]. Expected type " + - "was [" + type.getName() + "], but the object under that key is of type " + - "[" + o.getClass().getName() + "]."; + String msg = "Invalid object found in SubjectContext Map under key [" + key + "]. Expected type " + + "was [" + type.getName() + "], but the object under that key is of type " + + "[" + o.getClass().getName() + "]."; throw new IllegalArgumentException(msg); } found = (E) o; diff --git a/core/src/main/java/org/apache/shiro/util/PatternMatcher.java b/core/src/main/java/org/apache/shiro/util/PatternMatcher.java index 436f693534..ac2d7a7649 100644 --- a/core/src/main/java/org/apache/shiro/util/PatternMatcher.java +++ b/core/src/main/java/org/apache/shiro/util/PatternMatcher.java @@ -24,7 +24,7 @@ * Different implementations can support different pattern types, for example, Ant style path expressions, or * regular expressions, or other types of text based patterns. * - * @see org.apache.shiro.lang.util.AntPathMatcher AntPathMatcher + * @see AntPathMatcher AntPathMatcher * @since 0.9 RC2 */ public interface PatternMatcher { @@ -36,7 +36,7 @@ public interface PatternMatcher { * @param pattern the pattern to match against * @param source the source to match * @return 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..f574b96487 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 resolveDelimitedPermissions(String s, PermissionResolver permissionResolver) { Set permStrings = toPermissionStrings(s); @@ -48,7 +51,8 @@ public static Set toPermissionStrings(String permissionsString) { return null; } - public static Set resolvePermissions(Collection permissionStrings, PermissionResolver permissionResolver) { + public static Set resolvePermissions(Collection permissionStrings, + PermissionResolver permissionResolver) { Set permissions = new LinkedHashSet<>(permissionStrings.size()); for (String permissionString : permissionStrings) { permissions.add(permissionResolver.resolvePermission(permissionString)); diff --git a/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java b/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java index b07ce3d03a..b03d96b3da 100644 --- a/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java +++ b/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java @@ -33,7 +33,7 @@ public class RegExPatternMatcher implements PatternMatcher { private static final int CASE_INSENSITIVE = DEFAULT | Pattern.CASE_INSENSITIVE; - private boolean caseInsensitive = false; + private boolean caseInsensitive; /** * Simple implementation that merely uses the default pattern comparison logic provided by the @@ -43,6 +43,7 @@ public class RegExPatternMatcher implements PatternMatcher { * Pattern p = Pattern.compile(pattern, Pattern.DOTALL); * Matcher m = p.matcher(source); * return m.matches(); + * * @param pattern the pattern to match against * @param source the source to match * @return {@code true} if the source matches the required pattern, {@code false} otherwise. @@ -58,6 +59,7 @@ public boolean matches(String pattern, String source) { /** * Returns true if regex match should be case-insensitive. + * * @return true if regex match should be case-insensitive. */ public boolean isCaseInsensitive() { @@ -66,6 +68,7 @@ public boolean isCaseInsensitive() { /** * Adds the Pattern.CASE_INSENSITIVE flag when compiling patterns. + * * @param caseInsensitive true if patterns should match case-insensitive. */ public void setCaseInsensitive(boolean caseInsensitive) { diff --git a/core/src/main/java/org/apache/shiro/util/ThreadContext.java b/core/src/main/java/org/apache/shiro/util/ThreadContext.java index 28488a3e26..267a7949b9 100644 --- a/core/src/main/java/org/apache/shiro/util/ThreadContext.java +++ b/core/src/main/java/org/apache/shiro/util/ThreadContext.java @@ -46,14 +46,21 @@ public abstract class ThreadContext { /** - * Private internal log instance. + * security manager key. */ - private static final Logger log = LoggerFactory.getLogger(ThreadContext.class); - public static final String SECURITY_MANAGER_KEY = ThreadContext.class.getName() + "_SECURITY_MANAGER_KEY"; + + /** + * subject key. + */ public static final String SUBJECT_KEY = ThreadContext.class.getName() + "_SUBJECT_KEY"; - private static final ThreadLocal> resources = new InheritableThreadLocalMap>(); + /** + * Private internal log instance. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(ThreadContext.class); + + private static final ThreadLocal> RESOURCES = new InheritableThreadLocalMap>(); /** * Default no-argument constructor. @@ -68,10 +75,10 @@ protected ThreadContext() { * @return the map of bound resources */ public static Map getResources() { - if (resources.get() == null){ + if (RESOURCES.get() == null) { return Collections.emptyMap(); } else { - return new HashMap(resources.get()); + return new HashMap(RESOURCES.get()); } } @@ -88,8 +95,8 @@ public static void setResources(Map newResources) { return; } ensureResourcesInitialized(); - resources.get().clear(); - resources.get().putAll(newResources); + RESOURCES.get().clear(); + RESOURCES.get().putAll(newResources); } /** @@ -98,17 +105,17 @@ public static void setResources(Map newResources) { * * @param key the map key to use to lookup the value * @return the value bound in the {@code ThreadContext} under the specified {@code key}, or {@code null} if there - * is no value for that {@code key}. + * is no value for that {@code key}. * @since 1.0 */ private static Object getValue(Object key) { - Map perThreadResources = resources.get(); + Map perThreadResources = RESOURCES.get(); return perThreadResources != null ? perThreadResources.get(key) : null; } - private static void ensureResourcesInitialized(){ - if (resources.get() == null){ - resources.set(new HashMap()); + private static void ensureResourcesInitialized() { + if (RESOURCES.get() == null) { + RESOURCES.set(new HashMap()); } } @@ -118,19 +125,19 @@ private static void ensureResourcesInitialized(){ * * @param key the key that identifies the value to return * @return the object keyed by key or null if - * no value exists for the specified key + * no value exists for the specified key */ public static Object get(Object key) { - if (log.isTraceEnabled()) { + if (LOGGER.isTraceEnabled()) { String msg = "get() - in thread [" + Thread.currentThread().getName() + "]"; - log.trace(msg); + LOGGER.trace(msg); } Object value = getValue(key); - if ((value != null) && log.isTraceEnabled()) { - String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + - key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]"; - log.trace(msg); + if ((value != null) && LOGGER.isTraceEnabled()) { + String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + + key + "] " + "bound to thread [" + Thread.currentThread().getName() + "]"; + LOGGER.trace(msg); } return value; } @@ -161,12 +168,12 @@ public static void put(Object key, Object value) { } ensureResourcesInitialized(); - resources.get().put(key, value); + RESOURCES.get().put(key, value); - if (log.isTraceEnabled()) { - String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + - key + "] to thread " + "[" + Thread.currentThread().getName() + "]"; - log.trace(msg); + if (LOGGER.isTraceEnabled()) { + String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + + key + "] to thread " + "[" + Thread.currentThread().getName() + "]"; + LOGGER.trace(msg); } } @@ -176,16 +183,16 @@ public static void put(Object key, Object value) { * * @param key The key identifying the value bound to the current thread. * @return the object unbound or null if there was nothing bound - * under the specified key name. + * under the specified key name. */ public static Object remove(Object key) { - Map perThreadResources = resources.get(); + Map perThreadResources = RESOURCES.get(); Object value = perThreadResources != null ? perThreadResources.remove(key) : null; - if ((value != null) && log.isTraceEnabled()) { - String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + - key + "]" + "from thread [" + Thread.currentThread().getName() + "]"; - log.trace(msg); + if ((value != null) && LOGGER.isTraceEnabled()) { + String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + + key + "]" + "from thread [" + Thread.currentThread().getName() + "]"; + LOGGER.trace(msg); } return value; @@ -200,7 +207,7 @@ public static Object remove(Object key) { * @since 1.0 */ public static void remove() { - resources.remove(); + RESOURCES.remove(); } /** @@ -257,7 +264,7 @@ public static void bind(SecurityManager securityManager) { * during thread execution), use the {@link #getSecurityManager() getSecurityManager()} method instead. * * @return the application's SecurityManager instance previously bound to the thread, or null if there - * was none bound. + * was none bound. * @since 0.9 */ public static SecurityManager unbindSecurityManager() { @@ -320,13 +327,15 @@ public static void bind(Subject subject) { public static Subject unbindSubject() { return (Subject) remove(SUBJECT_KEY); } - - private static final class InheritableThreadLocalMap> extends InheritableThreadLocal> { + + private static final class InheritableThreadLocalMap> + extends InheritableThreadLocal> { /** * This implementation was added to address a * * user-reported issue. + * * @param parentValue the parent value, a HashMap as defined in the {@link #initialValue()} method. * @return the HashMap to be used by any parent-spawned child threads (a clone of the parent HashMap). */ diff --git a/core/src/test/java/org/apache/shiro/ExceptionTest.java b/core/src/test/java/org/apache/shiro/ExceptionTest.java index 112f4089cd..c9fb1ebaf4 100644 --- a/core/src/test/java/org/apache/shiro/ExceptionTest.java +++ b/core/src/test/java/org/apache/shiro/ExceptionTest.java @@ -23,6 +23,7 @@ /** + * */ @SuppressWarnings({"ThrowableInstanceNeverThrown"}) public abstract class ExceptionTest { diff --git a/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java b/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java index 495d505617..a60f6f3259 100644 --- a/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java +++ b/core/src/test/java/org/apache/shiro/aop/AnnotationResolverTest.java @@ -1,75 +1,78 @@ -/* - * 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 static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.replay; - -import java.lang.reflect.Method; - -import org.apache.shiro.authz.annotation.RequiresRoles; +/* + * 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 static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.lang.reflect.Method; + +import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresUser; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +public class AnnotationResolverTest { + @SuppressWarnings("unused") + @RequiresRoles("root") + private static final class MyFixture { + public void operateThis() { + } + + @RequiresUser() + public void operateThat() { + } + } -public class AnnotationResolverTest { - @SuppressWarnings("unused") - @RequiresRoles("root") - private class MyFixture { - public void operateThis() {} - @RequiresUser() - public void operateThat() {} - } - DefaultAnnotationResolver annotationResolver = new DefaultAnnotationResolver(); @Test - void testAnnotationFoundFromClass() throws SecurityException, NoSuchMethodException { - MyFixture myFixture = new MyFixture(); - MethodInvocation methodInvocation = createMock(MethodInvocation.class); - Method method = MyFixture.class.getDeclaredMethod("operateThis"); - expect(methodInvocation.getMethod()).andReturn(method); - expect(methodInvocation.getThis()).andReturn(myFixture); - replay(methodInvocation); - assertNotNull(annotationResolver.getAnnotation(methodInvocation, RequiresRoles.class)); + void testAnnotationFoundFromClass() throws SecurityException, NoSuchMethodException { + MyFixture myFixture = new MyFixture(); + MethodInvocation methodInvocation = createMock(MethodInvocation.class); + Method method = MyFixture.class.getDeclaredMethod("operateThis"); + expect(methodInvocation.getMethod()).andReturn(method); + expect(methodInvocation.getThis()).andReturn(myFixture); + replay(methodInvocation); + assertNotNull(annotationResolver.getAnnotation(methodInvocation, RequiresRoles.class)); } @Test - void testAnnotationFoundFromMethod() throws SecurityException, NoSuchMethodException { - MethodInvocation methodInvocation = createMock(MethodInvocation.class); - Method method = MyFixture.class.getDeclaredMethod("operateThat"); - expect(methodInvocation.getMethod()).andReturn(method); - replay(methodInvocation); - assertNotNull(annotationResolver.getAnnotation(methodInvocation, RequiresUser.class)); + void testAnnotationFoundFromMethod() throws SecurityException, NoSuchMethodException { + MethodInvocation methodInvocation = createMock(MethodInvocation.class); + Method method = MyFixture.class.getDeclaredMethod("operateThat"); + expect(methodInvocation.getMethod()).andReturn(method); + replay(methodInvocation); + assertNotNull(annotationResolver.getAnnotation(methodInvocation, RequiresUser.class)); } @Test - void testNullMethodInvocation() throws SecurityException, NoSuchMethodException { - MethodInvocation methodInvocation = createMock(MethodInvocation.class); - Method method = MyFixture.class.getDeclaredMethod("operateThis"); - expect(methodInvocation.getMethod()).andReturn(method); - expect(methodInvocation.getThis()).andReturn(null); - replay(methodInvocation); - assertNull(annotationResolver.getAnnotation(methodInvocation, RequiresUser.class)); - } -} - + void testNullMethodInvocation() throws SecurityException, NoSuchMethodException { + MethodInvocation methodInvocation = createMock(MethodInvocation.class); + Method method = MyFixture.class.getDeclaredMethod("operateThis"); + expect(methodInvocation.getMethod()).andReturn(method); + expect(methodInvocation.getThis()).andReturn(null); + replay(methodInvocation); + assertNull(annotationResolver.getAnnotation(methodInvocation, RequiresUser.class)); + } +} + diff --git a/core/src/test/java/org/apache/shiro/authc/AbstractAuthenticatorTest.java b/core/src/test/java/org/apache/shiro/authc/AbstractAuthenticatorTest.java index daadfbfdf9..c03b5a608f 100644 --- a/core/src/test/java/org/apache/shiro/authc/AbstractAuthenticatorTest.java +++ b/core/src/test/java/org/apache/shiro/authc/AbstractAuthenticatorTest.java @@ -31,8 +31,11 @@ import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; -import static org.junit.jupiter.api.Assertions.*; - +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @since 0.1 @@ -46,7 +49,10 @@ public class AbstractAuthenticatorTest { @BeforeAll static void setUpLogger() { - LoggerContext loggerContext = (LoggerContext) LogManager.getContext(AbstractAuthenticatorTest.class.getClassLoader(), false, URI.create("log4j2-list.xml")); + LoggerContext loggerContext = + (LoggerContext) LogManager.getContext(AbstractAuthenticatorTest.class.getClassLoader(), + false, + URI.create("log4j2-list.xml")); Configuration configuration = loggerContext.getConfiguration(); listAppender = configuration.getAppender("List"); } @@ -179,7 +185,8 @@ protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws Au @Test void logExceptionAfterDoAuthenticateThrowsNonAuthenticationException() { // NOTE: log4j is a test dependency - final String expectedExceptionMessage = "exception thrown for test logExceptionAfterDoAuthenticateThrowsNonAuthenticationException"; + final String expectedExceptionMessage = "exception thrown" + + " for test logExceptionAfterDoAuthenticateThrowsNonAuthenticationException"; abstractAuthenticator = new AbstractAuthenticator() { protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException { @@ -188,15 +195,15 @@ protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws Au }; AuthenticationToken token = newToken(); - try{ + try { abstractAuthenticator.authenticate(token); fail("the expected AuthenticationException was not thrown"); - }catch(AuthenticationException expectedException){ + } catch (AuthenticationException ignored) { } String logMsg = String.join("\n", listAppender.getMessages()); assertTrue(logMsg.contains("WARN")); - assertTrue(logMsg.contains("java.lang.IllegalArgumentException: "+ expectedExceptionMessage)); + assertTrue(logMsg.contains("java.lang.IllegalArgumentException: " + expectedExceptionMessage)); } } diff --git a/core/src/test/java/org/apache/shiro/authc/SimpleAuthenticationInfoTest.java b/core/src/test/java/org/apache/shiro/authc/SimpleAuthenticationInfoTest.java index 22c29b402b..fefbdc42da 100644 --- a/core/src/test/java/org/apache/shiro/authc/SimpleAuthenticationInfoTest.java +++ b/core/src/test/java/org/apache/shiro/authc/SimpleAuthenticationInfoTest.java @@ -18,7 +18,6 @@ */ package org.apache.shiro.authc; -import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -53,39 +52,61 @@ void testMergeWithAggregateNullCredentials() { aggregate.merge(local); } - @SuppressWarnings("serial") + @SuppressWarnings({"serial", "checkstyle:AnonInnerLength"}) @Test void testMergeWithImmutablePrincipalCollection() { SimpleAuthenticationInfo aggregate = new SimpleAuthenticationInfo(); - // Make a quick test fixture that does *not* implement MutablePrincipalCollection + // Make a quick test fixture that does *not* implement MutablePrincipalCollection PrincipalCollection principalCollection = new PrincipalCollection() { - @SuppressWarnings("unchecked") - public List asList() { return null;} - @SuppressWarnings("unchecked") - public Set asSet() {return null;} - public Collection byType(Class type) {return null;} - @SuppressWarnings("unchecked") - public Collection fromRealm(String realmName) { - Collection principals = new HashSet(); - principals.add("testprincipal"); - return principals; - } - public Object getPrimaryPrincipal() {return null;} - public Set getRealmNames() { - Set realms = new HashSet(); - realms.add("testrealm"); - return realms; - } - public boolean isEmpty() {return false;} - public T oneByType(Class type) {return null;} - @SuppressWarnings("unchecked") - public Iterator iterator() {return null;} - + @SuppressWarnings("unchecked") + public List asList() { + return null; + } + + @SuppressWarnings("unchecked") + public Set asSet() { + return null; + } + + public Collection byType(Class type) { + return null; + } + + @SuppressWarnings("unchecked") + public Collection fromRealm(String realmName) { + Collection principals = new HashSet(); + principals.add("testprincipal"); + return principals; + } + + public Object getPrimaryPrincipal() { + return null; + } + + public Set getRealmNames() { + Set realms = new HashSet(); + realms.add("testrealm"); + return realms; + } + + public boolean isEmpty() { + return false; + } + + public T oneByType(Class type) { + return null; + } + + @SuppressWarnings("unchecked") + public Iterator iterator() { + return null; + } + }; aggregate.setPrincipals(principalCollection); SimpleAuthenticationInfo local = new SimpleAuthenticationInfo("username", "password", "testRealm"); aggregate.merge(local); assertEquals(2, aggregate.getPrincipals().asList().size()); } - + } diff --git a/core/src/test/java/org/apache/shiro/authc/credential/AbstractHashedCredentialsMatcherTest.java b/core/src/test/java/org/apache/shiro/authc/credential/AbstractHashedCredentialsMatcherTest.java index 38f5596057..50fdb3a58c 100644 --- a/core/src/test/java/org/apache/shiro/authc/credential/AbstractHashedCredentialsMatcherTest.java +++ b/core/src/test/java/org/apache/shiro/authc/credential/AbstractHashedCredentialsMatcherTest.java @@ -21,6 +21,7 @@ import org.apache.shiro.authc.AuthenticationInfo; import static org.junit.jupiter.api.Assertions.assertTrue; + import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; diff --git a/core/src/test/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategyTest.java b/core/src/test/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategyTest.java index aac94febb3..76785ecb46 100644 --- a/core/src/test/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategyTest.java +++ b/core/src/test/java/org/apache/shiro/authc/pam/FirstSuccessfulStrategyTest.java @@ -24,7 +24,9 @@ import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/org/apache/shiro/authz/ModularRealmAuthorizerTest.java b/core/src/test/java/org/apache/shiro/authz/ModularRealmAuthorizerTest.java index 15e3ee23c7..3b86168ae0 100644 --- a/core/src/test/java/org/apache/shiro/authz/ModularRealmAuthorizerTest.java +++ b/core/src/test/java/org/apache/shiro/authz/ModularRealmAuthorizerTest.java @@ -33,82 +33,72 @@ import org.apache.shiro.subject.PrincipalCollection; import org.junit.jupiter.api.Test; -public class ModularRealmAuthorizerTest -{ +public class ModularRealmAuthorizerTest { @Test - void testSettingOfRolePermissionResolver() - { + void testSettingOfRolePermissionResolver() { Collection realms = new ArrayList(); - - realms.add( new MockAuthorizingRealm() ); - realms.add( new MockAuthorizingRealm() ); - + + realms.add(new MockAuthorizingRealm()); + realms.add(new MockAuthorizingRealm()); + // its null to start with - for ( Realm realm : realms ) - { - assertNull( ((AuthorizingRealm)realm).getRolePermissionResolver() ); + for (Realm realm : realms) { + assertNull(((AuthorizingRealm) realm).getRolePermissionResolver()); } - + ModularRealmAuthorizer modRealmAuthz = new ModularRealmAuthorizer(); - modRealmAuthz.setRealms( realms ); - + modRealmAuthz.setRealms(realms); + // make sure they are still null - for ( Realm realm : realms ) - { - assertNull( ((AuthorizingRealm)realm).getRolePermissionResolver() ); + for (Realm realm : realms) { + assertNull(((AuthorizingRealm) realm).getRolePermissionResolver()); } - + // now set the RolePermissionResolver - RolePermissionResolver rolePermissionResolver = new RolePermissionResolver() - { - public Collection resolvePermissionsInRole( String roleString ) - { + RolePermissionResolver rolePermissionResolver = new RolePermissionResolver() { + public Collection resolvePermissionsInRole(String roleString) { return null; } }; - modRealmAuthz.setRolePermissionResolver( rolePermissionResolver ); - + modRealmAuthz.setRolePermissionResolver(rolePermissionResolver); + // make sure they are set - for ( Realm realm : realms ) - { + for (Realm realm : realms) { // check for same instance - assertTrue( ((AuthorizingRealm)realm).getRolePermissionResolver() == rolePermissionResolver ); + assertTrue(((AuthorizingRealm) realm).getRolePermissionResolver() == rolePermissionResolver); } - + // add a new realm and make sure the RolePermissionResolver is set MockAuthorizingRealm mockRealm = new MockAuthorizingRealm(); - realms.add( mockRealm ); - modRealmAuthz.setRealms( realms ); - assertTrue( ((AuthorizingRealm) mockRealm).getRolePermissionResolver() == rolePermissionResolver ); - - - // TODO: no way to unset them, not sure if that is a valid use case, but this is consistent with the PermissionResolver logic + realms.add(mockRealm); + modRealmAuthz.setRealms(realms); + assertTrue(((AuthorizingRealm) mockRealm).getRolePermissionResolver() == rolePermissionResolver); + + +// TODO: no way to unset them, not sure if that is a valid use case, but this is consistent with the PermissionResolver logic // // now just to be sure, unset them // modRealmAuthz.setRolePermissionResolver( null ); // for ( Realm realm : realms ) // { // assertNull( ((AuthorizingRealm)realm).getRolePermissionResolver() ); // } - - + + } - - class MockAuthorizingRealm extends AuthorizingRealm - { + + class MockAuthorizingRealm extends AuthorizingRealm { @Override - protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals ) - { + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } @Override - protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token ) - throws AuthenticationException - { + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) + throws AuthenticationException { return null; } - + } } diff --git a/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java b/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java index 50294b7a3f..9bad76553e 100644 --- a/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java +++ b/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java @@ -42,7 +42,7 @@ public void testGuestSinglePermissionAssertion() { Annotation requiresPermissionAnnotation = new RequiresPermissions() { @Override public String[] value() { - return new String[]{"test:test"}; + return new String[] {"test:test"}; } @Override @@ -50,10 +50,10 @@ public Class annotationType() { return RequiresPermissions.class; } - @Override - public Logical logical() { - return Logical.AND; - } + @Override + public Logical logical() { + return Logical.AND; + } }; runWithSubject(subject -> { @@ -70,18 +70,18 @@ public void testGuestMultiplePermissionAssertion() { Annotation requiresPermissionAnnotation = new RequiresPermissions() { @Override public String[] value() { - return new String[]{"test:test", "test2:test2"}; + return new String[] {"test:test", "test2:test2"}; } @Override public Class annotationType() { return RequiresPermissions.class; } - - @Override - public Logical logical() { - return Logical.AND; - } + + @Override + public Logical logical() { + return Logical.AND; + } }; runWithSubject(subject -> { diff --git a/core/src/test/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandlerTest.java b/core/src/test/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandlerTest.java index 5363df346b..cf28a64559 100644 --- a/core/src/test/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandlerTest.java +++ b/core/src/test/java/org/apache/shiro/authz/aop/PermitAllAnnotationHandlerTest.java @@ -18,7 +18,6 @@ */ package org.apache.shiro.authz.aop; -import org.apache.shiro.subject.Subject; import org.apache.shiro.test.SecurityManagerTestSupport; import org.junit.jupiter.api.Test; diff --git a/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java b/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java index 0f34001a4c..6c3fdcbcc1 100644 --- a/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java +++ b/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java @@ -47,7 +47,7 @@ public void testGuestSingleRoleAssertion() throws Throwable { Annotation requiresRolesAnnotation = new RequiresRoles() { @Override public String[] value() { - return new String[]{"blah"}; + return new String[] {"blah"}; } @Override @@ -75,7 +75,7 @@ public void testGuestMultipleRolesAssertion() throws Throwable { Annotation requiresRolesAnnotation = new RequiresRoles() { @Override public String[] value() { - return new String[]{"blah", "blah2"}; + return new String[] {"blah", "blah2"}; } @Override @@ -110,7 +110,7 @@ protected Subject getSubject() { Annotation requiresRolesAnnotation = new RequiresRoles() { @Override public String[] value() { - return new String[]{"blah", "blah2"}; + return new String[] {"blah", "blah2"}; } @Override diff --git a/core/src/test/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandlerTest.java b/core/src/test/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandlerTest.java index f642ba2051..9dec9db459 100644 --- a/core/src/test/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandlerTest.java +++ b/core/src/test/java/org/apache/shiro/authz/aop/RolesAllowedAnnotationHandlerTest.java @@ -53,7 +53,7 @@ protected Subject getSubject() { Annotation rolesAllowedAnnotation = new RolesAllowed() { @Override public String[] value() { - return new String[]{"blah"}; + return new String[] {"blah"}; } @Override @@ -85,7 +85,7 @@ protected Subject getSubject() { Annotation rolesAllowedAnnotation = new RolesAllowed() { @Override public String[] value() { - return new String[]{"blah", "blah2"}; + return new String[] {"blah", "blah2"}; } @Override @@ -114,7 +114,7 @@ protected Subject getSubject() { Annotation rolesAllowedAnnotation = new RolesAllowed() { @Override public String[] value() { - return new String[]{"blah", "blah2"}; + return new String[] {"blah", "blah2"}; } @Override diff --git a/core/src/test/java/org/apache/shiro/authz/permission/AllPermissionTest.java b/core/src/test/java/org/apache/shiro/authz/permission/AllPermissionTest.java index c4aab8127a..f9c9685dd3 100644 --- a/core/src/test/java/org/apache/shiro/authz/permission/AllPermissionTest.java +++ b/core/src/test/java/org/apache/shiro/authz/permission/AllPermissionTest.java @@ -24,6 +24,7 @@ /** + * */ public class AllPermissionTest { diff --git a/core/src/test/java/org/apache/shiro/authz/permission/DomainPermissionTest.java b/core/src/test/java/org/apache/shiro/authz/permission/DomainPermissionTest.java index e253594299..b5faee8205 100644 --- a/core/src/test/java/org/apache/shiro/authz/permission/DomainPermissionTest.java +++ b/core/src/test/java/org/apache/shiro/authz/permission/DomainPermissionTest.java @@ -24,7 +24,10 @@ import java.util.List; import java.util.Set; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * @since 1.3 diff --git a/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionResolverTest.java b/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionResolverTest.java index 66a5b17c47..4e4b151e47 100644 --- a/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionResolverTest.java +++ b/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionResolverTest.java @@ -20,52 +20,50 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class WildcardPermissionResolverTest { @Test - void testDefaultIsNonCaseSensitive() - { + void testDefaultIsNonCaseSensitive() { WildcardPermissionResolver resolver = new WildcardPermissionResolver(); - assertFalse( resolver.isCaseSensitive(), "Default sensitivity should be false"); - /* this is a round-about test as permissions don't store case sensitivity just lower case + assertFalse(resolver.isCaseSensitive(), "Default sensitivity should be false"); + /* this is a round-about test as permissions don't store case sensitivity just lower case the string. */ - WildcardPermission permission = (WildcardPermission) resolver.resolvePermission( "Foo:*" ); - assertEquals( "foo:*", permission.toString(), "string should be lowercase"); + WildcardPermission permission = (WildcardPermission) resolver.resolvePermission("Foo:*"); + assertEquals("foo:*", permission.toString(), "string should be lowercase"); } @Test - void testCaseSensitive() - { + void testCaseSensitive() { WildcardPermissionResolver resolver = new WildcardPermissionResolver(true); - assertTrue( resolver.isCaseSensitive(), "Sensitivity should be true"); - /* this is a round-about test as permissions don't store case sensitivity just lower case + assertTrue(resolver.isCaseSensitive(), "Sensitivity should be true"); + /* this is a round-about test as permissions don't store case sensitivity just lower case the string. */ - WildcardPermission permission = (WildcardPermission) resolver.resolvePermission( "Foo:*" ); - assertEquals( "Foo:*", permission.toString(), "string should be mixed case"); + WildcardPermission permission = (WildcardPermission) resolver.resolvePermission("Foo:*"); + assertEquals("Foo:*", permission.toString(), "string should be mixed case"); } @Test - void testCaseInsensitive() - { + void testCaseInsensitive() { WildcardPermissionResolver resolver = new WildcardPermissionResolver(false); - assertFalse( resolver.isCaseSensitive(), "Sensitivity should be false"); - /* this is a round-about test as permissions don't store case sensitivity just lower case + assertFalse(resolver.isCaseSensitive(), "Sensitivity should be false"); + /* this is a round-about test as permissions don't store case sensitivity just lower case the string. */ - WildcardPermission permission = (WildcardPermission) resolver.resolvePermission( "Foo:*" ); - assertEquals( "foo:*", permission.toString(), "string should be lowercase"); + WildcardPermission permission = (WildcardPermission) resolver.resolvePermission("Foo:*"); + assertEquals("foo:*", permission.toString(), "string should be lowercase"); } @Test - void testCaseSensitiveToggle() - { + void testCaseSensitiveToggle() { WildcardPermissionResolver resolver = new WildcardPermissionResolver(); - assertFalse( resolver.isCaseSensitive(), "Default sensitivity should be false"); - resolver.setCaseSensitive( true ); - assertTrue( resolver.isCaseSensitive(), "Sensitivity should be true"); - resolver.setCaseSensitive( false ); - assertFalse( resolver.isCaseSensitive(), "Sensitivity should be false"); + assertFalse(resolver.isCaseSensitive(), "Default sensitivity should be false"); + resolver.setCaseSensitive(true); + assertTrue(resolver.isCaseSensitive(), "Sensitivity should be true"); + resolver.setCaseSensitive(false); + assertFalse(resolver.isCaseSensitive(), "Sensitivity should be false"); } } diff --git a/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionTest.java b/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionTest.java index b619351d7b..b7914b9c2c 100644 --- a/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionTest.java +++ b/core/src/test/java/org/apache/shiro/authz/permission/WildcardPermissionTest.java @@ -20,8 +20,10 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; /** * @since 0.9 @@ -56,6 +58,7 @@ void testOnlyDelimiters() { }); } + @SuppressWarnings("checkstyle:MultipleVariableDeclarations") @Test void testNamed() { WildcardPermission p1, p2; @@ -98,6 +101,7 @@ void testNamed() { } + @SuppressWarnings("checkstyle:MultipleVariableDeclarations") @Test void testLists() { WildcardPermission p1, p2, p3; @@ -144,9 +148,10 @@ void testListDifferentOrder() { WildcardPermission p6 = new WildcardPermission("one,two:three,four"); WildcardPermission p6DiffOrder = new WildcardPermission("two,one:four,three"); - assertTrue(p6.equals(p6DiffOrder)); + assertEquals(p6, p6DiffOrder); } + @SuppressWarnings({"checkstyle:MultipleVariableDeclarations", "checkstyle:MethodLength"}) @Test void testWildcards() { WildcardPermission p1, p2, p3, p4, p5, p6, p7, p8, p9; @@ -236,18 +241,19 @@ void testToString() { WildcardPermission p4 = new WildcardPermission("one,two:three,four"); WildcardPermission p5 = new WildcardPermission("one,two:three,four,five:six:seven,eight"); - assertTrue("*".equals(p1.toString())); - assertTrue(p1.equals(new WildcardPermission(p1.toString()))); - assertTrue("one".equals(p2.toString())); - assertTrue(p2.equals(new WildcardPermission(p2.toString()))); - assertTrue("one:two".equals(p3.toString())); - assertTrue(p3.equals(new WildcardPermission(p3.toString()))); - assertTrue("one,two:three,four".equals(p4.toString())); - assertTrue(p4.equals(new WildcardPermission(p4.toString()))); - assertTrue("one,two:three,four,five:six:seven,eight".equals(p5.toString())); - assertTrue(p5.equals(new WildcardPermission(p5.toString()))); + assertEquals("*", p1.toString()); + assertEquals(p1, new WildcardPermission(p1.toString())); + assertEquals("one", p2.toString()); + assertEquals(p2, new WildcardPermission(p2.toString())); + assertEquals("one:two", p3.toString()); + assertEquals(p3, new WildcardPermission(p3.toString())); + assertEquals("one,two:three,four", p4.toString()); + assertEquals(p4, new WildcardPermission(p4.toString())); + assertEquals("one,two:three,four,five:six:seven,eight", p5.toString()); + assertEquals(p5, new WildcardPermission(p5.toString())); } + @SuppressWarnings("checkstyle:MultipleVariableDeclarations") @Test void testWildcardLeftTermination() { WildcardPermission p1, p2, p3, p4; @@ -273,4 +279,4 @@ void testWildcardLeftTermination() { assertFalse(p4.implies(p2)); assertFalse(p4.implies(p3)); } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/apache/shiro/concurrent/SubjectAwareExecutorServiceTest.java b/core/src/test/java/org/apache/shiro/concurrent/SubjectAwareExecutorServiceTest.java index 3b8e5ee66a..0f31f35f86 100644 --- a/core/src/test/java/org/apache/shiro/concurrent/SubjectAwareExecutorServiceTest.java +++ b/core/src/test/java/org/apache/shiro/concurrent/SubjectAwareExecutorServiceTest.java @@ -56,7 +56,7 @@ public void testSubmitRunnable() { }); } - private static class DummyFuture implements Future { + private static final class DummyFuture implements Future { @Override public boolean cancel(boolean b) { diff --git a/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java b/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java index c1c0895a83..853d1e7220 100644 --- a/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java +++ b/core/src/test/java/org/apache/shiro/config/HashMapCacheManager.java @@ -31,6 +31,7 @@ * * @since 1.0 */ +@SuppressWarnings("checkstyle:JavadocType") public class HashMapCacheManager extends AbstractCacheManager { @Override diff --git a/core/src/test/java/org/apache/shiro/lang/io/SerializationExceptionTest.java b/core/src/test/java/org/apache/shiro/lang/io/SerializationExceptionTest.java index 29340fe804..29fe20d1fc 100644 --- a/core/src/test/java/org/apache/shiro/lang/io/SerializationExceptionTest.java +++ b/core/src/test/java/org/apache/shiro/lang/io/SerializationExceptionTest.java @@ -22,6 +22,7 @@ /** + * */ public class SerializationExceptionTest extends ExceptionTest { diff --git a/core/src/test/java/org/apache/shiro/mgt/AbstractRememberMeManagerTest.java b/core/src/test/java/org/apache/shiro/mgt/AbstractRememberMeManagerTest.java index 236fe3a4b8..ec14a82984 100644 --- a/core/src/test/java/org/apache/shiro/mgt/AbstractRememberMeManagerTest.java +++ b/core/src/test/java/org/apache/shiro/mgt/AbstractRememberMeManagerTest.java @@ -56,6 +56,7 @@ protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) assertNull(principals); } + @SuppressWarnings("checkstyle:FinalClass") private static class DummyRememberMeManager extends AbstractRememberMeManager { public void forgetIdentity(SubjectContext subjectContext) { //do nothing diff --git a/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java b/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java index 064d9ce968..dc26793035 100644 --- a/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java +++ b/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java @@ -36,15 +36,19 @@ import java.io.Serializable; -import static org.junit.jupiter.api.Assertions.*; - +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; /** * @since 0.2 */ public class DefaultSecurityManagerTest extends AbstractSecurityManagerTest { - DefaultSecurityManager sm = null; + DefaultSecurityManager sm; @BeforeEach public void setup() { @@ -71,7 +75,7 @@ void testDefaultConfig() { AuthenticationToken token = new UsernamePasswordToken("guest", "guest"); subject.login(token); assertTrue(subject.isAuthenticated()); - assertTrue("guest".equals(subject.getPrincipal())); + assertEquals("guest", subject.getPrincipal()); assertTrue(subject.hasRole("guest")); Session session = subject.getSession(); @@ -89,11 +93,11 @@ void testDefaultConfig() { * Test that validates functionality for issue * JSEC-46 */ + @SuppressWarnings("checkstyle:MagicNumber") @Test void testAutoCreateSessionAfterInvalidation() { Subject subject = SecurityUtils.getSubject(); Session session = subject.getSession(); - Serializable origSessionId = session.getId(); String key = "foo"; String value1 = "bar"; @@ -126,7 +130,7 @@ void testSubjectReuseAfterLogout() { AuthenticationToken token = new UsernamePasswordToken("guest", "guest"); subject.login(token); assertTrue(subject.isAuthenticated()); - assertTrue("guest".equals(subject.getPrincipal())); + assertEquals("guest", subject.getPrincipal()); assertTrue(subject.hasRole("guest")); Session session = subject.getSession(); @@ -143,11 +147,11 @@ void testSubjectReuseAfterLogout() { subject.login(new UsernamePasswordToken("lonestarr", "vespa")); assertTrue(subject.isAuthenticated()); - assertTrue("lonestarr".equals(subject.getPrincipal())); + assertEquals("lonestarr", subject.getPrincipal()); assertTrue(subject.hasRole("goodguy")); assertNotNull(subject.getSession()); - assertFalse(firstSessionId.equals(subject.getSession().getId())); + assertNotEquals(firstSessionId, subject.getSession().getId()); subject.logout(); @@ -176,7 +180,7 @@ void testNewSubjectWithoutThreadSecurityManager() { // Specify sm to use and build subject with DelegatingSubject subject = - (DelegatingSubject)(new Subject.Builder(sm)).buildSubject(); + (DelegatingSubject) (new Subject.Builder(sm)).buildSubject(); // Login and verify specified sm is used and no error thrown AuthenticationToken token = new UsernamePasswordToken("guest", "guest"); diff --git a/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java b/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java index d53c9f36af..3f6d4f9cfb 100644 --- a/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; + import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; @@ -44,7 +45,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; /** @@ -54,13 +59,13 @@ */ public class AuthorizingRealmTest { - AuthorizingRealm realm; - private static final String USERNAME = "testuser"; private static final String PASSWORD = "password"; private static final int USER_ID = 12345; private static final String ROLE = "admin"; - private String localhost = "localhost"; + private final String localhost = "localhost"; + + private AuthorizingRealm realm; @BeforeEach public void setup() { @@ -84,13 +89,13 @@ void testDefaultConfig() { assertTrue(principal instanceof UserIdPrincipal); UsernamePrincipal usernamePrincipal = info.getPrincipals().oneByType(UsernamePrincipal.class); - assertTrue(usernamePrincipal.getUsername().equals(USERNAME)); + assertEquals(USERNAME, usernamePrincipal.getUsername()); UserIdPrincipal userIdPrincipal = info.getPrincipals().oneByType(UserIdPrincipal.class); - assertTrue(userIdPrincipal.getUserId() == USER_ID); + assertEquals(USER_ID, userIdPrincipal.getUserId()); String stringPrincipal = info.getPrincipals().oneByType(String.class); - assertTrue(stringPrincipal.equals(USER_ID + USERNAME)); + assertEquals(USER_ID + USERNAME, stringPrincipal); } @Test @@ -115,9 +120,10 @@ protected AuthenticationInfo buildAuthenticationInfo(Object principal, Object cr } + @SuppressWarnings("checkstyle:MethodLength") @Test void testNullAuthzInfo() { - AuthorizingRealm realm = new AuthorizingRealm() { + AuthorizingRealm realm = new AuthorizingRealm() { protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } @@ -186,42 +192,38 @@ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) assertFalse(realm.hasAllRoles(pCollection, roleList)); assertFalse(realm.hasRole(pCollection, "role1")); - assertArrayEquals(new boolean[]{false, false}, realm.hasRoles(pCollection, roleList)); + assertArrayEquals(new boolean[] {false, false}, realm.hasRoles(pCollection, roleList)); assertFalse(realm.isPermitted(pCollection, "perm1")); assertFalse(realm.isPermitted(pCollection, new WildcardPermission("perm1"))); - assertArrayEquals(new boolean[]{false, false}, realm.isPermitted(pCollection, "perm1", "perm2")); - assertArrayEquals(new boolean[]{false, false}, realm.isPermitted(pCollection, permList)); + assertArrayEquals(new boolean[] {false, false}, realm.isPermitted(pCollection, "perm1", "perm2")); + assertArrayEquals(new boolean[] {false, false}, realm.isPermitted(pCollection, permList)); assertFalse(realm.isPermittedAll(pCollection, "perm1", "perm2")); assertFalse(realm.isPermittedAll(pCollection, permList)); } @Test - void testRealmWithRolePermissionResolver() - { + void testRealmWithRolePermissionResolver() { Principal principal = new UsernamePrincipal("rolePermResolver"); PrincipalCollection pCollection = new SimplePrincipalCollection(principal, "testRealmWithRolePermissionResolver"); - + AuthorizingRealm realm = new AllowAllRealm(); - realm.setRolePermissionResolver( new RolePermissionResolver() - { - public Collection resolvePermissionsInRole( String roleString ) - { + realm.setRolePermissionResolver(new RolePermissionResolver() { + public Collection resolvePermissionsInRole(String roleString) { Collection permissions = new HashSet(); - if( roleString.equals( ROLE )) - { - permissions.add( new WildcardPermission( ROLE + ":perm1" ) ); - permissions.add( new WildcardPermission( ROLE + ":perm2" ) ); - permissions.add( new WildcardPermission( "other:*:foo" ) ); + if (roleString.equals(ROLE)) { + permissions.add(new WildcardPermission(ROLE + ":perm1")); + permissions.add(new WildcardPermission(ROLE + ":perm2")); + permissions.add(new WildcardPermission("other:*:foo")); } return permissions; } }); - - assertTrue( realm.hasRole( pCollection, ROLE ) ); - assertTrue( realm.isPermitted( pCollection, ROLE + ":perm1" ) ); - assertTrue( realm.isPermitted( pCollection, ROLE + ":perm2" ) ); - assertFalse( realm.isPermitted( pCollection, ROLE + ":perm3" ) ); - assertTrue( realm.isPermitted( pCollection, "other:bar:foo" ) ); + + assertTrue(realm.hasRole(pCollection, ROLE)); + assertTrue(realm.isPermitted(pCollection, ROLE + ":perm1")); + assertTrue(realm.isPermitted(pCollection, ROLE + ":perm2")); + assertFalse(realm.isPermitted(pCollection, ROLE + ":perm3")); + assertTrue(realm.isPermitted(pCollection, "other:bar:foo")); } @Test @@ -230,18 +232,15 @@ void testRealmWithEmptyOrNullPermissions() { PrincipalCollection pCollection = new SimplePrincipalCollection(principal, "testRealmWithRolePermissionResolver"); AuthorizingRealm realm = new AllowAllRealm(); - realm.setRolePermissionResolver( new RolePermissionResolver() - { - public Collection resolvePermissionsInRole( String roleString ) - { + realm.setRolePermissionResolver(new RolePermissionResolver() { + public Collection resolvePermissionsInRole(String roleString) { Collection permissions = new HashSet(); - if( roleString.equals( ROLE )) - { - permissions.add( new WildcardPermission( ROLE + ":perm1" ) ); - permissions.add( new WildcardPermission( ROLE + ":perm2" ) ); - permissions.add( new WildcardPermission( ROLE + ": " ) ); - permissions.add( new WildcardPermission( ROLE + ":\t" ) ); - permissions.add( new WildcardPermission( "other:*:foo" ) ); + if (roleString.equals(ROLE)) { + permissions.add(new WildcardPermission(ROLE + ":perm1")); + permissions.add(new WildcardPermission(ROLE + ":perm2")); + permissions.add(new WildcardPermission(ROLE + ": ")); + permissions.add(new WildcardPermission(ROLE + ":\t")); + permissions.add(new WildcardPermission("other:*:foo")); } return permissions; } @@ -269,7 +268,7 @@ private void assertArrayEquals(boolean[] expected, boolean[] actual) { } } - public class AllowAllRealm extends AuthorizingRealm { + public static class AllowAllRealm extends AuthorizingRealm { public AllowAllRealm() { super(); diff --git a/core/src/test/java/org/apache/shiro/realm/UserIdPrincipal.java b/core/src/test/java/org/apache/shiro/realm/UserIdPrincipal.java index 09d2f49670..1ddc709317 100644 --- a/core/src/test/java/org/apache/shiro/realm/UserIdPrincipal.java +++ b/core/src/test/java/org/apache/shiro/realm/UserIdPrincipal.java @@ -36,4 +36,4 @@ public int getUserId() { public String getName() { return String.valueOf(userId); } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java b/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java index 4fe9e415e5..f480160cbf 100644 --- a/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/activedirectory/ActiveDirectoryRealmTest.java @@ -19,7 +19,12 @@ package org.apache.shiro.realm.activedirectory; import org.apache.shiro.SecurityUtils; -import org.apache.shiro.authc.*; + +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.SimpleAccount; +import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; @@ -55,9 +60,10 @@ import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Simple test case for ActiveDirectoryRealm. @@ -66,18 +72,17 @@ * heart of ActiveDirectoryRealm (no meaningful implementation of queryForLdapAccount, etc.) it obviously should. * This version was intended to mimic my current usage scenario in an effort to debug upgrade issues which were not related * to LDAP connectivity. - * */ public class ActiveDirectoryRealmTest { - DefaultSecurityManager securityManager = null; - AuthorizingRealm realm; - private static final String USERNAME = "testuser"; private static final String PASSWORD = "password"; private static final int USER_ID = 12345; private static final String ROLE = "admin"; + DefaultSecurityManager securityManager; + AuthorizingRealm realm; + @BeforeEach public void setup() { ThreadContext.remove(); @@ -115,7 +120,8 @@ void testDefaultConfig() { @Test void testExistingUserSuffix() throws Exception { - assertExistingUserSuffix(USERNAME, "testuser@ExAmple.COM"); // suffix case matches configure suffix + // suffix case matches configure suffix + assertExistingUserSuffix(USERNAME, "testuser@ExAmple.COM"); // suffix matches user entry assertExistingUserSuffix(USERNAME + "@example.com", "testuser@example.com"); @@ -127,7 +133,8 @@ public void assertExistingUserSuffix(String username, String expectedPrincipalNa LdapContext ldapContext = createMock(LdapContext.class); NamingEnumeration results = createMock(NamingEnumeration.class); Capture captureArgs = Capture.newInstance(CaptureType.ALL); - expect(ldapContext.search(anyString(), anyString(), capture(captureArgs), anyObject(SearchControls.class))).andReturn(results); + expect(ldapContext.search(anyString(), anyString(), capture(captureArgs), anyObject(SearchControls.class))) + .andReturn(results); replay(ldapContext); ActiveDirectoryRealm activeDirectoryRealm = new ActiveDirectoryRealm() {{ @@ -150,7 +157,7 @@ public void assertExistingUserSuffix(String username, String expectedPrincipalNa assertThat(args[0], is(expectedPrincipalName)); } - public class TestActiveDirectoryRealm extends ActiveDirectoryRealm { + public static class TestActiveDirectoryRealm extends ActiveDirectoryRealm { /*-------------------------------------------- | C O N S T R U C T O R S | @@ -195,10 +202,11 @@ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal } // override ldap query because i don't care about testing that piece in this case - protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException { + protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) + throws NamingException { return new SimpleAccount(token.getPrincipal(), token.getCredentials(), getName()); } } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java b/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java index 04f9110835..2ff5dcec46 100644 --- a/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java @@ -36,9 +36,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInfo; import javax.sql.DataSource; @@ -56,20 +54,20 @@ */ public class JDBCRealmTest { - protected DefaultSecurityManager securityManager = null; + protected DefaultSecurityManager securityManager; protected AuthorizingRealm realm; protected final String username = "testUser"; protected final String plainTextPassword = "testPassword"; - protected final String salt = username; //Default impl of getSaltForUser returns username + //Default impl of getSaltForUser returns username + protected final String salt = username; protected final String testRole = "testRole"; protected final String testPermissionString = "testDomain:testTarget:testAction"; - + // Maps keyed on test method name so setup/teardown can manage per test resources protected HashMap realmMap = new HashMap(); protected HashMap dsMap = new HashMap(); - - public String name; + private String name; @BeforeEach public void setup(TestInfo testInfo) { @@ -80,7 +78,9 @@ public void setup(TestInfo testInfo) { ThreadContext.remove(); Ini config = new Ini(); config.setSectionProperty("main", "myRealm", "org.apache.shiro.realm.jdbc.JdbcRealm"); - config.setSectionProperty("main", "myRealmCredentialsMatcher", "org.apache.shiro.authc.credential.Sha256CredentialsMatcher"); + config.setSectionProperty("main", + "myRealmCredentialsMatcher", + "org.apache.shiro.authc.credential.Sha256CredentialsMatcher"); config.setSectionProperty("main", "myRealm.credentialsMatcher", "$myRealmCredentialsMatcher"); config.setSectionProperty("main", "securityManager.sessionManager.sessionValidationSchedulerEnabled", "false"); @@ -89,7 +89,7 @@ public void setup(TestInfo testInfo) { SecurityUtils.setSecurityManager(securityManager); // Create a database and realm for the test - createRealm( name); + createRealm(name); } @AfterEach @@ -107,7 +107,7 @@ void testUnSaltedSuccess() throws Exception { JdbcRealm realm = realmMap.get(testMethodName); createDefaultSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); @@ -121,7 +121,7 @@ void testUnSaltedWrongPassword() throws Exception { JdbcRealm realm = realmMap.get(testMethodName); createDefaultSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd"); @@ -141,7 +141,7 @@ void testUnSaltedMultipleRows() throws Exception { Connection conn = dsMap.get(testMethodName).getConnection(); Statement sql = conn.createStatement(); sql.executeUpdate("insert into users values ('" + username + "', 'dupe')"); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd"); @@ -159,7 +159,7 @@ void testSaltColumnSuccess() throws Exception { createSaltColumnSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.COLUMN); realm.setSaltIsBase64Encoded(false); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); @@ -188,7 +188,7 @@ void testSaltColumnWrongPassword() throws Exception { createSaltColumnSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.COLUMN); realm.setSaltIsBase64Encoded(false); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd"); @@ -223,7 +223,7 @@ void testExternalSuccess() throws Exception { JdbcRealm realm = realmMap.get(testMethodName); createDefaultSchema(testMethodName, true); realm.setSaltStyle(JdbcRealm.SaltStyle.EXTERNAL); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); @@ -237,7 +237,7 @@ void testExternalWrongPassword() throws Exception { JdbcRealm realm = realmMap.get(testMethodName); createDefaultSchema(testMethodName, true); realm.setSaltStyle(JdbcRealm.SaltStyle.EXTERNAL); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd"); @@ -254,7 +254,7 @@ void testRolePresent() throws Exception { JdbcRealm realm = realmMap.get(testMethodName); createDefaultSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); @@ -268,7 +268,7 @@ void testRoleNotPresent() throws Exception { JdbcRealm realm = realmMap.get(testMethodName); createDefaultSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); @@ -283,7 +283,7 @@ void testPermissionPresent() throws Exception { createDefaultSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT); realm.setPermissionsLookupEnabled(true); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); @@ -298,14 +298,14 @@ void testPermissionNotPresent() throws Exception { createDefaultSchema(testMethodName, false); realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT); realm.setPermissionsLookupEnabled(true); - + Subject.Builder builder = new Subject.Builder(securityManager); Subject currentUser = builder.buildSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword); currentUser.login(token); Assertions.assertFalse(currentUser.isPermitted("testDomain:testTarget:specialAction")); } - + /** * Creates a realm for a test method and puts it in the realMap. */ @@ -313,7 +313,7 @@ protected void createRealm(String testMethodName) { JdbcRealm realm = (JdbcRealm) securityManager.getRealms().iterator().next(); realmMap.put(testMethodName, realm); } - + /** * Shuts down the database and removes the realm from the realm map. */ @@ -334,7 +334,7 @@ protected void shutDown(String testName) { realmMap.remove(testName); } } - + /** * Creates a test database with the default (no separate salt column) schema, salting with * username if salted is true. Sets the DataSource of the realm associated with the test @@ -352,8 +352,8 @@ protected void createDefaultSchema(String testName, boolean salted) { conn = ds.getConnection(); sql = conn.createStatement(); sql.executeUpdate("create table users (username varchar(20), password varchar(100))"); - Sha256Hash sha256Hash = salted ? new Sha256Hash(plainTextPassword, salt) : - new Sha256Hash(plainTextPassword); + Sha256Hash sha256Hash = salted ? new Sha256Hash(plainTextPassword, salt) + : new Sha256Hash(plainTextPassword); String password = sha256Hash.toHex(); sql.executeUpdate("insert into users values ('" + username + "', '" + password + "')"); } catch (SQLException ex) { @@ -366,12 +366,13 @@ protected void createDefaultSchema(String testName, boolean salted) { realmMap.get(testName).setDataSource(ds); dsMap.put(testName, ds); } - + /** * Creates a test database with a separate salt column in the users table. Sets the * DataSource of the realm associated with the test to a DataSource connected to the database. - * @param The name of the test which is used as the key when saving the created realm in the realmMap - * @param base64EncodeSalt if true, the salt will be base64 encoded before it's stored in the database + * + * @param testName name of the test which is used as the key when saving the created realm in the realmMap + * @param base64EncodeSalt if true, the salt will be base64 encoded before it's stored in the database */ protected void createSaltColumnSchema(String testName, boolean base64EncodeSalt) { JDBCDataSource ds = new JDBCDataSource(); @@ -388,7 +389,9 @@ protected void createSaltColumnSchema(String testName, boolean base64EncodeSalt) Sha256Hash sha256Hash = new Sha256Hash(plainTextPassword, salt); String password = sha256Hash.toHex(); String maybeBase64EncodedSalt = base64EncodeSalt ? Base64.encodeToString(CodecSupport.toBytes(salt)) : salt; - sql.executeUpdate("insert into users values ('" + username + "', '" + password + "', '" + maybeBase64EncodedSalt + "')"); + sql.executeUpdate( + "insert into users values ('" + username + "', '" + password + "', '" + + maybeBase64EncodedSalt + "')"); } catch (SQLException ex) { Assertions.fail("Exception creating test database"); } finally { @@ -399,12 +402,12 @@ protected void createSaltColumnSchema(String testName, boolean base64EncodeSalt) realmMap.get(testName).setDataSource(ds); dsMap.put(testName, ds); } - + /** * Creates and adds test data to user_role and roles_permissions tables. */ protected void createRolesAndPermissions(DataSource ds) { - Connection conn = null;; + Connection conn = null; Statement sql = null; try { conn = ds.getConnection(); diff --git a/core/src/test/java/org/apache/shiro/realm/ldap/DefaultLdapRealmTest.java b/core/src/test/java/org/apache/shiro/realm/ldap/DefaultLdapRealmTest.java index 9974a2ca27..6e4d5146fd 100644 --- a/core/src/test/java/org/apache/shiro/realm/ldap/DefaultLdapRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/ldap/DefaultLdapRealmTest.java @@ -1,63 +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.realm.ldap; - -import org.apache.shiro.authc.AuthenticationException; -import org.apache.shiro.authc.AuthenticationToken; -import org.apache.shiro.authc.UsernamePasswordToken; +/* + * 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.AuthenticationToken; +import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import javax.naming.NamingException; -import javax.naming.ldap.LdapContext; - -import java.util.UUID; - -import static org.easymock.EasyMock.*; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Tests for the {@link DefaultLdapRealm} class. - * - * @since 1.3 - */ -@SuppressWarnings({"ThrowableInstanceNeverThrown"}) -public class DefaultLdapRealmTest { - - private DefaultLdapRealm realm; - - // this method can be collapsed back into setUp once the JndiLdapRealm has been removed in 2.0 - protected DefaultLdapRealm getNewRealmUnderTest() { - return new DefaultLdapRealm(); - } - - @BeforeEach - public void setUp() { - realm = getNewRealmUnderTest(); +import org.junit.jupiter.api.Test; + +import javax.naming.NamingException; +import javax.naming.ldap.LdapContext; +import java.util.UUID; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests for the {@link DefaultLdapRealm} class. + * + * @since 1.3 + */ +@SuppressWarnings({"ThrowableInstanceNeverThrown"}) +public class DefaultLdapRealmTest { + + private DefaultLdapRealm realm; + + // this method can be collapsed back into setUp once the JndiLdapRealm has been removed in 2.0 + protected DefaultLdapRealm getNewRealmUnderTest() { + return new DefaultLdapRealm(); + } + + @BeforeEach + public void setUp() { + realm = getNewRealmUnderTest(); } @Test - void testDefaultInstance() { - assertTrue(realm.getCredentialsMatcher() instanceof AllowAllCredentialsMatcher); - assertEquals(AuthenticationToken.class, realm.getAuthenticationTokenClass()); - assertTrue(realm.getContextFactory() instanceof JndiLdapContextFactory); + void testDefaultInstance() { + assertTrue(realm.getCredentialsMatcher() instanceof AllowAllCredentialsMatcher); + assertEquals(AuthenticationToken.class, realm.getAuthenticationTokenClass()); + assertTrue(realm.getContextFactory() instanceof JndiLdapContextFactory); } @Test @@ -82,25 +89,26 @@ void testSetUserDnTemplateWithoutToken() { } @Test - void testUserDnTemplate() { - String template = "uid={0},ou=users,dc=mycompany,dc=com"; - realm.setUserDnTemplate(template); - assertEquals(template, realm.getUserDnTemplate()); + void testUserDnTemplate() { + String template = "uid={0},ou=users,dc=mycompany,dc=com"; + realm.setUserDnTemplate(template); + assertEquals(template, realm.getUserDnTemplate()); } @Test - void testUserDnTemplateSubstitution() throws NamingException { - realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com"); - LdapContextFactory factory = createMock(LdapContextFactory.class); - realm.setContextFactory(factory); - - Object expectedPrincipal = "uid=jsmith,ou=users,dc=mycompany,dc=com"; - - expect(factory.getLdapContext(eq(expectedPrincipal), isA(Object.class))).andReturn(createNiceMock(LdapContext.class)); - replay(factory); - - realm.getAuthenticationInfo(new UsernamePasswordToken("jsmith", "secret") ); - verify(factory); + void testUserDnTemplateSubstitution() throws NamingException { + realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com"); + LdapContextFactory factory = createMock(LdapContextFactory.class); + realm.setContextFactory(factory); + + Object expectedPrincipal = "uid=jsmith,ou=users,dc=mycompany,dc=com"; + + expect(factory.getLdapContext(eq(expectedPrincipal), isA(Object.class))) + .andReturn(createNiceMock(LdapContext.class)); + replay(factory); + + realm.getAuthenticationInfo(new UsernamePasswordToken("jsmith", "secret")); + verify(factory); } @Test @@ -141,27 +149,27 @@ void testGetAuthenticationInfoNamingException() throws NamingException { * @throws NamingException not thrown */ @Test - void testGetAuthenticationInfoNonSimpleToken() throws NamingException { - realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com"); - LdapContextFactory factory = createMock(LdapContextFactory.class); - realm.setContextFactory(factory); - - final UUID userId = UUID.randomUUID(); - - //ensure the userId is passed as-is: - expect(factory.getLdapContext(eq(userId), isA(Object.class))).andReturn(createNiceMock(LdapContext.class)); - replay(factory); - - realm.getAuthenticationInfo(new AuthenticationToken() { - public Object getPrincipal() { - return userId; - } - - public Object getCredentials() { - return "secret"; - } - }); - verify(factory); + void testGetAuthenticationInfoNonSimpleToken() throws NamingException { + realm.setUserDnTemplate("uid={0},ou=users,dc=mycompany,dc=com"); + LdapContextFactory factory = createMock(LdapContextFactory.class); + realm.setContextFactory(factory); + + final UUID userId = UUID.randomUUID(); + + //ensure the userId is passed as-is: + expect(factory.getLdapContext(eq(userId), isA(Object.class))).andReturn(createNiceMock(LdapContext.class)); + replay(factory); + + realm.getAuthenticationInfo(new AuthenticationToken() { + public Object getPrincipal() { + return userId; + } + + public Object getCredentials() { + return "secret"; + } + }); + verify(factory); } @Test @@ -172,20 +180,20 @@ void testGetUserDnNullArgument() { } @Test - void testGetUserDnWithOutPrefixAndSuffix() { - realm = new DefaultLdapRealm() { - @Override - protected String getUserDnPrefix() { - return null; - } - - @Override - protected String getUserDnSuffix() { - return null; - } - }; - String principal = "foo"; - String userDn = realm.getUserDn(principal); - assertEquals(principal, userDn); - } -} + void testGetUserDnWithOutPrefixAndSuffix() { + realm = new DefaultLdapRealm() { + @Override + protected String getUserDnPrefix() { + return null; + } + + @Override + protected String getUserDnSuffix() { + return null; + } + }; + String principal = "foo"; + String userDn = realm.getUserDn(principal); + assertEquals(principal, userDn); + } +} diff --git a/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapContextFactoryTest.java b/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapContextFactoryTest.java index fa3955696b..98a86bc7ee 100644 --- a/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapContextFactoryTest.java +++ b/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapContextFactoryTest.java @@ -1,56 +1,60 @@ -/* - * 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; - +/* + * 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.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import javax.naming.AuthenticationException; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.ldap.LdapContext; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; -import java.util.UUID; - -import static org.easymock.EasyMock.*; -import static org.junit.jupiter.api.Assertions.*; - -/** - * Tests for the {@link JndiLdapContextFactory} class. - * - * @since 1.1 - */ -public class JndiLdapContextFactoryTest { - - private JndiLdapContextFactory factory; - - @BeforeEach - public void setUp() { - factory = new JndiLdapContextFactory() { - //Fake a JNDI environment for the tests: - @Override - protected LdapContext createLdapContext(Hashtable env) throws NamingException { - return createNiceMock(LdapContext.class); - } - }; +import org.junit.jupiter.api.Test; + +import javax.naming.AuthenticationException; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.ldap.LdapContext; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.UUID; + +import static org.easymock.EasyMock.createNiceMock; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +/** + * Tests for the {@link JndiLdapContextFactory} class. + * + * @since 1.1 + */ +public class JndiLdapContextFactoryTest { + + private JndiLdapContextFactory factory; + + @BeforeEach + public void setUp() { + factory = new JndiLdapContextFactory() { + //Fake a JNDI environment for the tests: + @Override + protected LdapContext createLdapContext(Hashtable env) throws NamingException { + return createNiceMock(LdapContext.class); + } + }; } /** @@ -70,37 +74,37 @@ void testGetLdapContext() throws NamingException { } @Test - void testAuthenticationMechanism() { - String mech = "MD5-DIGEST"; - factory.setAuthenticationMechanism(mech); - assertEquals(mech, factory.getAuthenticationMechanism()); + void testAuthenticationMechanism() { + String mech = "MD5-DIGEST"; + factory.setAuthenticationMechanism(mech); + assertEquals(mech, factory.getAuthenticationMechanism()); } @Test - void testReferral() { - String referral = "throw"; - factory.setReferral(referral); - assertEquals(referral, factory.getReferral()); + void testReferral() { + String referral = "throw"; + factory.setReferral(referral); + assertEquals(referral, factory.getReferral()); } @Test - void testGetContextFactoryClassName() { - assertEquals(JndiLdapContextFactory.DEFAULT_CONTEXT_FACTORY_CLASS_NAME, factory.getContextFactoryClassName()); + void testGetContextFactoryClassName() { + assertEquals(JndiLdapContextFactory.DEFAULT_CONTEXT_FACTORY_CLASS_NAME, factory.getContextFactoryClassName()); } @Test - void testSetEnvironmentPropertyNull() { - factory.setAuthenticationMechanism("MD5-DIGEST"); - factory.setAuthenticationMechanism(null); - assertNull(factory.getAuthenticationMechanism()); + void testSetEnvironmentPropertyNull() { + factory.setAuthenticationMechanism("MD5-DIGEST"); + factory.setAuthenticationMechanism(null); + assertNull(factory.getAuthenticationMechanism()); } @Test - void testCustomEnvironment() { - Map map = new HashMap(); - map.put("foo", "bar"); - factory.setEnvironment(map); - assertEquals("bar", factory.getEnvironment().get("foo")); + void testCustomEnvironment() { + Map map = new HashMap(); + map.put("foo", "bar"); + factory.setEnvironment(map); + assertEquals("bar", factory.getEnvironment().get("foo")); } @Test @@ -111,81 +115,81 @@ void testGetLdapContextWithoutUrl() throws NamingException { } @Test - void testGetLdapContextDefault() throws NamingException { - factory = new JndiLdapContextFactory() { - @Override - protected LdapContext createLdapContext(Hashtable env) throws NamingException { - assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); - assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); - assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); - assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); - assertNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); - return createNiceMock(LdapContext.class); - } - }; - - factory.setUrl("ldap://localhost:389"); - factory.getLdapContext("foo", "bar"); + void testGetLdapContextDefault() throws NamingException { + factory = new JndiLdapContextFactory() { + @Override + protected LdapContext createLdapContext(Hashtable env) throws NamingException { + assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); + assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); + assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); + assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); + assertNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); + return createNiceMock(LdapContext.class); + } + }; + + factory.setUrl("ldap://localhost:389"); + factory.getLdapContext("foo", "bar"); } @SuppressWarnings({"deprecation"}) @Test - void testGetLdapContextStringArguments() throws NamingException { - factory = new JndiLdapContextFactory() { - @Override - protected LdapContext createLdapContext(Hashtable env) throws NamingException { - assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); - assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); - assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); - assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); - assertNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); - return createNiceMock(LdapContext.class); - } - }; - - factory.setUrl("ldap://localhost:389"); - factory.getLdapContext("foo", "bar"); + void testGetLdapContextStringArguments() throws NamingException { + factory = new JndiLdapContextFactory() { + @Override + protected LdapContext createLdapContext(Hashtable env) throws NamingException { + assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); + assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); + assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); + assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); + assertNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); + return createNiceMock(LdapContext.class); + } + }; + + factory.setUrl("ldap://localhost:389"); + factory.getLdapContext("foo", "bar"); } @Test - void testGetSystemLdapContext() throws NamingException { - factory = new JndiLdapContextFactory() { - @Override - protected LdapContext createLdapContext(Hashtable env) throws NamingException { - assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); - assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); - assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); - assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); - assertNotNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); - return createNiceMock(LdapContext.class); - } - }; - - factory.setSystemUsername("foo"); - factory.setSystemPassword("bar"); - factory.setUrl("ldap://localhost:389"); - factory.getSystemLdapContext(); + void testGetSystemLdapContext() throws NamingException { + factory = new JndiLdapContextFactory() { + @Override + protected LdapContext createLdapContext(Hashtable env) throws NamingException { + assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); + assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); + assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); + assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); + assertNotNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); + return createNiceMock(LdapContext.class); + } + }; + + factory.setSystemUsername("foo"); + factory.setSystemPassword("bar"); + factory.setUrl("ldap://localhost:389"); + factory.getSystemLdapContext(); } @Test - void testGetSystemLdapContextPoolingDisabled() throws NamingException { - factory = new JndiLdapContextFactory() { - @Override - protected LdapContext createLdapContext(Hashtable env) throws NamingException { - assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); - assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); - assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); - assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); - assertNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); - return createNiceMock(LdapContext.class); - } - }; - - factory.setSystemUsername("foo"); - factory.setSystemPassword("bar"); - factory.setPoolingEnabled(false); - factory.setUrl("ldap://localhost:389"); - factory.getSystemLdapContext(); + void testGetSystemLdapContextPoolingDisabled() throws NamingException { + factory = new JndiLdapContextFactory() { + @Override + protected LdapContext createLdapContext(Hashtable env) throws NamingException { + assertEquals("ldap://localhost:389", env.get(Context.PROVIDER_URL)); + assertEquals("foo", env.get(Context.SECURITY_PRINCIPAL)); + assertEquals("bar", env.get(Context.SECURITY_CREDENTIALS)); + assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION)); + assertNull(env.get(SUN_CONNECTION_POOLING_PROPERTY)); + return createNiceMock(LdapContext.class); + } + }; + + factory.setSystemUsername("foo"); + factory.setSystemPassword("bar"); + factory.setPoolingEnabled(false); + factory.setUrl("ldap://localhost:389"); + factory.getSystemLdapContext(); } @Test @@ -218,8 +222,7 @@ void testEmptyNullCredentials() throws NamingException { factory.setUrl("ldap://localhost:389"); factory.getLdapContext("jcoder", null); }); - } - - - -} + } + + +} diff --git a/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapRealmTest.java b/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapRealmTest.java index 80bae44e76..03f3c6c9f2 100644 --- a/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/ldap/JndiLdapRealmTest.java @@ -1,55 +1,55 @@ -/* - * 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.junit.jupiter.api.Test; - +/* + * 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.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.assertEquals; -/** - * Tests for the {@link JndiLdapRealm} class. - * - * @since 1.1 - * @deprecated Replaced by {@link DefaultLdapRealmTest} - */ -@SuppressWarnings({"ThrowableInstanceNeverThrown", "deprecation"}) -public class JndiLdapRealmTest extends DefaultLdapRealmTest { - - protected DefaultLdapRealm getNewRealmUnderTest() { - return new JndiLdapRealm(); - } - - @Test - public void testGetUserDnWithOutPrefixAndSuffix() { - JndiLdapRealm realm = new JndiLdapRealm() { - @Override - protected String getUserDnPrefix() { - return null; - } - - @Override - protected String getUserDnSuffix() { - return null; - } - }; - String principal = "foo"; - String userDn = realm.getUserDn(principal); - assertEquals(principal, userDn); - } -} +/** + * Tests for the {@link JndiLdapRealm} class. + * + * @since 1.1 + * @deprecated Replaced by {@link DefaultLdapRealmTest} + */ +@SuppressWarnings({"ThrowableInstanceNeverThrown", "deprecation"}) +public class JndiLdapRealmTest extends DefaultLdapRealmTest { + + protected DefaultLdapRealm getNewRealmUnderTest() { + return new JndiLdapRealm(); + } + + @Test + public void testGetUserDnWithOutPrefixAndSuffix() { + JndiLdapRealm realm = new JndiLdapRealm() { + @Override + protected String getUserDnPrefix() { + return null; + } + + @Override + protected String getUserDnSuffix() { + return null; + } + }; + String principal = "foo"; + String userDn = realm.getUserDn(principal); + assertEquals(principal, userDn); + } +} diff --git a/core/src/test/java/org/apache/shiro/realm/text/IniRealmTest.java b/core/src/test/java/org/apache/shiro/realm/text/IniRealmTest.java index 76430f172d..3ccb596ced 100644 --- a/core/src/test/java/org/apache/shiro/realm/text/IniRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/text/IniRealmTest.java @@ -23,7 +23,9 @@ import org.apache.shiro.config.Ini; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * Unit tests for the {@link IniRealm} class. diff --git a/core/src/test/java/org/apache/shiro/realm/text/TextConfigurationRealmTest.java b/core/src/test/java/org/apache/shiro/realm/text/TextConfigurationRealmTest.java index 86d1cb4b89..a0d9e13cbe 100644 --- a/core/src/test/java/org/apache/shiro/realm/text/TextConfigurationRealmTest.java +++ b/core/src/test/java/org/apache/shiro/realm/text/TextConfigurationRealmTest.java @@ -26,8 +26,11 @@ import java.text.ParseException; import java.util.Arrays; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +@SuppressWarnings("checkstyle:MagicNumber") public class TextConfigurationRealmTest { private TestRealm realm; @@ -55,9 +58,9 @@ private void setUpForReadConfigurationTest() { */ public void test(Thread runnable) throws InterruptedException { // Obtain the realm's locks - USERS_LOCK.writeLock().lock(); + usersLock.writeLock().lock(); try { - ROLES_LOCK.writeLock().lock(); + rolesLock.writeLock().lock(); try { // Any read threads attempting to obtain the realms lock will block runnable.start(); @@ -66,10 +69,10 @@ public void test(Thread runnable) throws InterruptedException { realm.onInit(); } finally { - ROLES_LOCK.writeLock().unlock(); + rolesLock.writeLock().unlock(); } } finally { - USERS_LOCK.writeLock().unlock(); + usersLock.writeLock().unlock(); } } }; @@ -90,7 +93,7 @@ private void executeTest(Runnable runnable) throws InterruptedException { } /* - * Tests that roles and account can't be tested while the realm is being loaded. + * Tests that roles and account can't be tested while the realm is being loaded. */ @Test void testRoleAndUserAccount() throws InterruptedException { @@ -104,7 +107,7 @@ public void run() { } /* - * Tests that roles can't be read while the realm is being loaded. + * Tests that roles can't be read while the realm is being loaded. */ @Test void testHasRole() throws InterruptedException { @@ -114,14 +117,14 @@ public void run() { PrincipalCollection principalCollection = new SimplePrincipalCollection("user1", "realm1"); assertTrue(realm.hasRole(principalCollection, "role2"), "principal doesn't have role when it should"); - assertTrue(realm.hasAllRoles(principalCollection, Arrays.asList(new String[]{"role1", "role2"})), + assertTrue(realm.hasAllRoles(principalCollection, Arrays.asList(new String[] {"role1", "role2"})), "principal doesn't have all roles when it should"); } }); } /* - * Tests that roles can't be checked while the realm is being loaded. + * Tests that roles can't be checked while the realm is being loaded. */ @Test void testCheckRole() throws InterruptedException { @@ -130,7 +133,7 @@ void testCheckRole() throws InterruptedException { public void run() { PrincipalCollection principalCollection = new SimplePrincipalCollection("user1", "realm1"); try { - realm.checkRoles(principalCollection, new String[]{"role1", "role2"}); + realm.checkRoles(principalCollection, new String[] {"role1", "role2"}); } catch (AuthorizationException ae) { fail("principal doesn't have all roles when it should"); } @@ -139,7 +142,7 @@ public void run() { } /* - * Tests that a principal's permissions can't be checked while the realm is being loaded. + * Tests that a principal's permissions can't be checked while the realm is being loaded. */ @Test void testCheckPermission() throws InterruptedException { @@ -149,7 +152,7 @@ public void run() { PrincipalCollection principalCollection = new SimplePrincipalCollection("user1", "realm1"); try { realm.checkPermission(principalCollection, "role1_permission1"); - realm.checkPermissions(principalCollection, new String[]{"role1_permission1", "role2_permission2"}); + realm.checkPermissions(principalCollection, new String[] {"role1_permission1", "role2_permission2"}); } catch (AuthorizationException ae) { fail("principal doesn't have permission when it should"); } @@ -158,17 +161,21 @@ public void run() { } /* - * Tests that a principal's permissions can't be checked while the realm is being loaded. + * Tests that a principal's permissions can't be checked while the realm is being loaded. */ @Test void testIsPermitted() throws InterruptedException { setUpForReadConfigurationTest(); executeTest(new Runnable() { + public void run() { PrincipalCollection principalCollection = new SimplePrincipalCollection("user1", "realm1"); - assertTrue(realm.isPermitted(principalCollection, "role1_permission1"), "permission not permitted when it should be"); - assertTrue(realm.isPermittedAll(principalCollection, new String[]{"role1_permission1", "role2_permission2"}), + assertTrue(realm.isPermitted(principalCollection, + "role1_permission1"), "permission not permitted when it should be"); + assertTrue(realm.isPermittedAll(principalCollection, + "role1_permission1", "role2_permission2"), + "permission not permitted when it should be"); } }); } @@ -182,14 +189,14 @@ void testProcessRoleDefinitions() throws InterruptedException { public void test(Thread runnable) throws InterruptedException { // While the realm's lock is held by this thread role definitions cannot be processed // Obtain the realm's locks - ROLES_LOCK.writeLock().lock(); + rolesLock.writeLock().lock(); try { runnable.start(); Thread.sleep(500); // No role until lock is released and role definitions are processed assertFalse(realm.roleExists("role1"), "role exists when it shouldn't"); } finally { - ROLES_LOCK.writeLock().unlock(); + rolesLock.writeLock().unlock(); } } }; @@ -220,14 +227,14 @@ void testProcessUserDefinitions() throws InterruptedException { public void test(Thread runnable) throws InterruptedException { // While the realm's lock is held by this thread user definitions cannot be processed // Obtain the realm's locks - USERS_LOCK.writeLock().lock(); + usersLock.writeLock().lock(); try { runnable.start(); Thread.sleep(500); // No account until lock is released and user definitions are processed assertFalse(realm.accountExists("user1"), "account exists when it shouldn't"); } finally { - USERS_LOCK.writeLock().unlock(); + usersLock.writeLock().unlock(); } } }; @@ -255,7 +262,7 @@ private class TestThread implements Runnable { private Runnable test; private volatile AssertionError ae; - public TestThread(Runnable test) { + TestThread(Runnable test) { this.test = test; } @@ -268,15 +275,17 @@ public void run() { } public void test() { - if (ae != null) + if (ae != null) { throw ae; + } } } /* * Provides an additional method that has access to the realm's lock for mutual exclusion. */ - private abstract class TestRealm extends TextConfigurationRealm { - abstract public void test(Thread runnable) throws InterruptedException; + private abstract static class TestRealm extends TextConfigurationRealm { + + public abstract void test(Thread runnable) throws InterruptedException; } } diff --git a/core/src/test/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManagerTest.java b/core/src/test/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManagerTest.java index 46662d80f2..10f928467a 100644 --- a/core/src/test/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManagerTest.java +++ b/core/src/test/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManagerTest.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.session.mgt; - -import org.apache.shiro.authz.AuthorizationException; -import org.apache.shiro.session.Session; -import org.apache.shiro.session.SessionListener; -import org.apache.shiro.session.SessionListenerAdapter; +/* + * 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.session.mgt; + +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.SessionListener; +import org.apache.shiro.session.SessionListenerAdapter; import org.apache.shiro.session.UnknownSessionException; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.concurrent.atomic.AtomicInteger; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * Unit tests for the {@link org.apache.shiro.session.mgt.AbstractValidatingSessionManager} class. - */ +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Unit tests for the {@link org.apache.shiro.session.mgt.AbstractValidatingSessionManager} class. + */ public class AbstractValidatingSessionManagerTest { /** @@ -44,53 +44,53 @@ public class AbstractValidatingSessionManagerTest { * Verifies SHIRO-199. */ @Test - void testValidateSessions() { - - final SimpleSession validSession = new SimpleSession(); - validSession.setId(1); - final SimpleSession invalidSession = new SimpleSession(); - //set to a time in the past: - Calendar cal = Calendar.getInstance(); - Long expiredTimeout = AbstractSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT + 1; - cal.add(Calendar.MILLISECOND, -(expiredTimeout.intValue()) ); - Date past = cal.getTime(); - invalidSession.setStartTimestamp(past); - invalidSession.setLastAccessTime(past); - invalidSession.setId(2); - - final AtomicInteger expirationCount = new AtomicInteger(); - - SessionListener sessionListener = new SessionListenerAdapter() { - @Override - public void onExpiration(Session session) { - expirationCount.incrementAndGet(); - } - }; - - AbstractValidatingSessionManager sessionManager = new AbstractValidatingSessionManager() { - @Override - protected Session retrieveSession(SessionKey key) throws UnknownSessionException { - throw new UnsupportedOperationException("Should not be called in this test."); - } - - @Override - protected Session doCreateSession(SessionContext initData) throws AuthorizationException { - throw new UnsupportedOperationException("Should not be called in this test."); - } - - @Override - protected Collection getActiveSessions() { - Collection sessions = new ArrayList(2); - sessions.add(validSession); - sessions.add(invalidSession); - return sessions; - } - }; - - sessionManager.setSessionListeners(Arrays.asList(sessionListener)); - sessionManager.validateSessions(); - - assertEquals(1, expirationCount.intValue()); + void testValidateSessions() { + + final SimpleSession validSession = new SimpleSession(); + validSession.setId(1); + final SimpleSession invalidSession = new SimpleSession(); + //set to a time in the past: + Calendar cal = Calendar.getInstance(); + long expiredTimeout = AbstractSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT + 1; + cal.add(Calendar.MILLISECOND, -((int) expiredTimeout)); + Date past = cal.getTime(); + invalidSession.setStartTimestamp(past); + invalidSession.setLastAccessTime(past); + invalidSession.setId(2); + + final AtomicInteger expirationCount = new AtomicInteger(); + + SessionListener sessionListener = new SessionListenerAdapter() { + @Override + public void onExpiration(Session session) { + expirationCount.incrementAndGet(); + } + }; + + AbstractValidatingSessionManager sessionManager = new AbstractValidatingSessionManager() { + @Override + protected Session retrieveSession(SessionKey key) throws UnknownSessionException { + throw new UnsupportedOperationException("Should not be called in this test."); + } + + @Override + protected Session doCreateSession(SessionContext initData) throws AuthorizationException { + throw new UnsupportedOperationException("Should not be called in this test."); + } + + @Override + protected Collection getActiveSessions() { + Collection sessions = new ArrayList(2); + sessions.add(validSession); + sessions.add(invalidSession); + return sessions; + } + }; + + sessionManager.setSessionListeners(Arrays.asList(sessionListener)); + sessionManager.validateSessions(); + + assertEquals(1, expirationCount.intValue()); } @@ -99,40 +99,40 @@ protected Collection getActiveSessions() { * Verifies SHIRO-399. */ @Test - void testNoMemoryLeakOnInvalidSessions() throws Exception { - SessionListener sessionListener = new SessionListener() { - public void onStart(Session session) { - session.setAttribute("I love", "Romania"); - } - - public void onStop(Session session) { - tryToCleanSession(session); - } - - public void onExpiration(Session session) { - tryToCleanSession(session); - } - - private void tryToCleanSession(Session session) { - Collection keys = session.getAttributeKeys(); - for (Object key : keys) { - session.removeAttribute(key); - } - } - }; - - DefaultSessionManager sessionManager = new DefaultSessionManager(); - sessionManager.setSessionListeners(Arrays.asList(sessionListener)); - - Session session = sessionManager.start(null); - assertEquals(1, sessionManager.getActiveSessions().size()); - - session.setTimeout(0L); - //last access timestamp needs to be older than the current timestamp when validating, so ensure a delay: - Thread.sleep(1); - - sessionManager.validateSessions(); - - assertEquals(0, sessionManager.getActiveSessions().size()); - } -} + void testNoMemoryLeakOnInvalidSessions() throws Exception { + SessionListener sessionListener = new SessionListener() { + public void onStart(Session session) { + session.setAttribute("I love", "Romania"); + } + + public void onStop(Session session) { + tryToCleanSession(session); + } + + public void onExpiration(Session session) { + tryToCleanSession(session); + } + + private void tryToCleanSession(Session session) { + Collection keys = session.getAttributeKeys(); + for (Object key : keys) { + session.removeAttribute(key); + } + } + }; + + DefaultSessionManager sessionManager = new DefaultSessionManager(); + sessionManager.setSessionListeners(Arrays.asList(sessionListener)); + + Session session = sessionManager.start(null); + assertEquals(1, sessionManager.getActiveSessions().size()); + + session.setTimeout(0L); + //last access timestamp needs to be older than the current timestamp when validating, so ensure a delay: + Thread.sleep(1); + + sessionManager.validateSessions(); + + assertEquals(0, sessionManager.getActiveSessions().size()); + } +} diff --git a/core/src/test/java/org/apache/shiro/session/mgt/DefaultSessionManagerTest.java b/core/src/test/java/org/apache/shiro/session/mgt/DefaultSessionManagerTest.java index 42554f2d9b..cc8628db27 100644 --- a/core/src/test/java/org/apache/shiro/session/mgt/DefaultSessionManagerTest.java +++ b/core/src/test/java/org/apache/shiro/session/mgt/DefaultSessionManagerTest.java @@ -33,15 +33,24 @@ import java.util.UUID; -import static org.easymock.EasyMock.*; -import static org.junit.jupiter.api.Assertions.*; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.easymock.EasyMock.verify; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * Unit test for the {@link DefaultSessionManager DefaultSessionManager} implementation. */ public class DefaultSessionManagerTest { - DefaultSessionManager sm = null; + DefaultSessionManager sm; @BeforeEach public void setup() { @@ -63,6 +72,7 @@ public void sleep(long millis) { } } + @SuppressWarnings("checkstyle:MagicNumber") @Test void testGlobalTimeout() { long timeout = 1000; @@ -110,7 +120,7 @@ void testSessionListenerStopNotificationWithReadAttribute() { SessionListener listener = new SessionListenerAdapter() { public void onStop(Session session) { stopped[0] = true; - value[0] = (String)session.getAttribute("foo"); + value[0] = (String) session.getAttribute("foo"); } }; sm.getSessionListeners().add(listener); @@ -123,6 +133,7 @@ public void onStop(Session session) { assertEquals("bar", value[0]); } + @SuppressWarnings("checkstyle:MagicNumber") @Test void testSessionListenerExpiredNotification() { final boolean[] expired = new boolean[1]; @@ -144,6 +155,7 @@ public void onExpiration(Session session) { assertTrue(expired[0]); } + @SuppressWarnings("checkstyle:MagicNumber") @Test void testSessionDeleteOnExpiration() { sm.setGlobalSessionTimeout(100); @@ -155,7 +167,7 @@ void testSessionDeleteOnExpiration() { final SimpleSession session1 = new SimpleSession(); session1.setId(sessionId1); - final Session[] activeSession = new SimpleSession[]{session1}; + final Session[] activeSession = new SimpleSession[] {session1}; sm.setSessionFactory(new SessionFactory() { public Session createSession(SessionContext initData) { return activeSession[0]; @@ -181,7 +193,8 @@ public Session createSession(SessionContext initData) { sleep(20); expect(sessionDAO.readSession(sessionId1)).andReturn(session1); - sessionDAO.update(eq(session1)); //update's the stop timestamp + //update's the stop timestamp + sessionDAO.update(eq(session1)); sessionDAO.delete(session1); replay(sessionDAO); @@ -193,7 +206,8 @@ public Session createSession(SessionContext initData) { //expected } - verify(sessionDAO); //verify that the delete call was actually made on the DAO + //verify that the delete call was actually made on the DAO + verify(sessionDAO); } /** @@ -214,8 +228,7 @@ void testEnablingOfCustomSessionValidationScheduler() { // now sessionValidationScheduler should be enabled assertTrue(sessionValidationScheduler.isEnabled(), "sessionValidationScheduler was not enabled"); - } - finally { + } finally { // cleanup after test sessionManager.destroy(); } @@ -230,7 +243,7 @@ private static class SessionTimeoutMatcher implements IArgumentMatcher { private final long timeout; - public SessionTimeoutMatcher(long timeout) { + SessionTimeoutMatcher(long timeout) { this.timeout = timeout; } diff --git a/core/src/test/java/org/apache/shiro/session/mgt/DelegatingSessionTest.java b/core/src/test/java/org/apache/shiro/session/mgt/DelegatingSessionTest.java index 8df9bb22e0..334972835a 100644 --- a/core/src/test/java/org/apache/shiro/session/mgt/DelegatingSessionTest.java +++ b/core/src/test/java/org/apache/shiro/session/mgt/DelegatingSessionTest.java @@ -34,8 +34,8 @@ */ public class DelegatingSessionTest { - DelegatingSession session = null; - DefaultSessionManager sm = null; + DelegatingSession session; + DefaultSessionManager sm; @BeforeEach public void setup() { @@ -58,6 +58,7 @@ public void sleep(long millis) { } } + @SuppressWarnings("checkstyle:MagicNumber") @Test void testTimeout() { Serializable origId = session.getId(); diff --git a/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java b/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java index 6694b18f5c..98c482a930 100644 --- a/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java +++ b/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java @@ -24,6 +24,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +@SuppressWarnings("checkstyle:MagicNumber") public class ExecutorServiceSessionValidationSchedulerTest { ExecutorServiceSessionValidationScheduler executorServiceSessionValidationScheduler; @@ -96,7 +97,7 @@ public void tearDown() throws Exception { executorServiceSessionValidationScheduler.disableSessionValidation(); } - private class FakeDefaultSessionManager extends DefaultSessionManager { + private static final class FakeDefaultSessionManager extends DefaultSessionManager { public void validateSessions() throws RuntimeException { throw new RuntimeException("Session test exception"); } diff --git a/core/src/test/java/org/apache/shiro/session/mgt/SimpleSessionTest.java b/core/src/test/java/org/apache/shiro/session/mgt/SimpleSessionTest.java index 81c9675add..c231cde553 100644 --- a/core/src/test/java/org/apache/shiro/session/mgt/SimpleSessionTest.java +++ b/core/src/test/java/org/apache/shiro/session/mgt/SimpleSessionTest.java @@ -1,66 +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.session.mgt; - -import org.junit.jupiter.api.Test; - -import java.io.*; -import java.util.Date; - +/* + * 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.session.mgt; + +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Date; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class SimpleSessionTest { @Test - void testDefaultSerialization() throws Exception { - SimpleSession session = new SimpleSession(); - - long timeout = session.getTimeout(); - Date start = session.getStartTimestamp(); - Date lastAccess = session.getLastAccessTime(); - - SimpleSession deserialized = serializeAndDeserialize(session); - - assertEquals(timeout, deserialized.getTimeout()); - assertEquals(start, deserialized.getStartTimestamp()); - assertEquals(lastAccess, deserialized.getLastAccessTime()); + void testDefaultSerialization() throws Exception { + SimpleSession session = new SimpleSession(); + + long timeout = session.getTimeout(); + Date start = session.getStartTimestamp(); + Date lastAccess = session.getLastAccessTime(); + + SimpleSession deserialized = serializeAndDeserialize(session); + + assertEquals(timeout, deserialized.getTimeout()); + assertEquals(start, deserialized.getStartTimestamp()); + assertEquals(lastAccess, deserialized.getLastAccessTime()); } @Test - void serializeHost() throws IOException, ClassNotFoundException { - SimpleSession session = new SimpleSession("localhost"); - assertEquals("localhost", serializeAndDeserialize(session).getHost()); + void serializeHost() throws IOException, ClassNotFoundException { + SimpleSession session = new SimpleSession("localhost"); + assertEquals("localhost", serializeAndDeserialize(session).getHost()); } @Test - void serializeExpired() throws IOException, ClassNotFoundException { - SimpleSession session = new SimpleSession(); - session.setExpired(true); - assertTrue(serializeAndDeserialize(session).isExpired()); - } - - private SimpleSession serializeAndDeserialize(SimpleSession session) throws IOException, ClassNotFoundException { - ByteArrayOutputStream serialized = new ByteArrayOutputStream(); - ObjectOutputStream serializer = new ObjectOutputStream(serialized); - serializer.writeObject(session); - serializer.close(); - return (SimpleSession) new ObjectInputStream(new ByteArrayInputStream(serialized.toByteArray())).readObject(); - } -} + void serializeExpired() throws IOException, ClassNotFoundException { + SimpleSession session = new SimpleSession(); + session.setExpired(true); + assertTrue(serializeAndDeserialize(session).isExpired()); + } + + private SimpleSession serializeAndDeserialize(SimpleSession session) throws IOException, ClassNotFoundException { + ByteArrayOutputStream serialized = new ByteArrayOutputStream(); + ObjectOutputStream serializer = new ObjectOutputStream(serialized); + serializer.writeObject(session); + serializer.close(); + return (SimpleSession) new ObjectInputStream(new ByteArrayInputStream(serialized.toByteArray())).readObject(); + } +} diff --git a/core/src/test/java/org/apache/shiro/subject/DelegatingSubjectTest.java b/core/src/test/java/org/apache/shiro/subject/DelegatingSubjectTest.java index 748e0507b1..311b3591d8 100644 --- a/core/src/test/java/org/apache/shiro/subject/DelegatingSubjectTest.java +++ b/core/src/test/java/org/apache/shiro/subject/DelegatingSubjectTest.java @@ -36,8 +36,11 @@ import java.util.concurrent.Callable; import static org.easymock.EasyMock.createNiceMock; -import static org.junit.jupiter.api.Assertions.*; - +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @since Aug 1, 2008 2:11:17 PM @@ -158,7 +161,8 @@ void testRunAs() { assertTrue(subject.hasRole("role1")); assertFalse(subject.hasRole("role2")); assertFalse(subject.hasRole("role3")); - assertNull(subject.getPreviousPrincipals()); //no previous principals since we haven't called runAs yet + //no previous principals since we haven't called runAs yet + assertNull(subject.getPreviousPrincipals()); //runAs user2: subject.runAs(new SimplePrincipalCollection("user2", IniSecurityManagerFactory.INI_REALM_NAME)); @@ -210,7 +214,8 @@ void testRunAs() { assertTrue(subject.hasRole("role1")); assertFalse(subject.hasRole("role2")); assertFalse(subject.hasRole("role3")); - assertNull(subject.getPreviousPrincipals()); //no previous principals in orig state + //no previous principals in orig state + assertNull(subject.getPreviousPrincipals()); subject.logout(); diff --git a/core/src/test/java/org/apache/shiro/subject/SimplePrincipalCollectionTest.java b/core/src/test/java/org/apache/shiro/subject/SimplePrincipalCollectionTest.java index 5aec0f635d..a38c32f5a1 100644 --- a/core/src/test/java/org/apache/shiro/subject/SimplePrincipalCollectionTest.java +++ b/core/src/test/java/org/apache/shiro/subject/SimplePrincipalCollectionTest.java @@ -30,8 +30,7 @@ public class SimplePrincipalCollectionTest { private static final Logger LOG = LoggerFactory.getLogger(SimplePrincipalCollectionTest.class); @Test - void multiplePrincipalsTest() - { + void multiplePrincipalsTest() { SimplePrincipalCollection principalCollection = new SimplePrincipalCollection(); principalCollection.add("frank", "realm1"); principalCollection.add("johnny", "realm1"); diff --git a/core/src/test/java/org/apache/shiro/test/AbstractShiroTest.java b/core/src/test/java/org/apache/shiro/test/AbstractShiroTest.java index 93944074bf..2e6e66ad3f 100644 --- a/core/src/test/java/org/apache/shiro/test/AbstractShiroTest.java +++ b/core/src/test/java/org/apache/shiro/test/AbstractShiroTest.java @@ -1,96 +1,96 @@ -/* - * 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.test; - -import org.apache.shiro.SecurityUtils; -import org.apache.shiro.UnavailableSecurityManagerException; -import org.apache.shiro.mgt.SecurityManager; -import org.apache.shiro.subject.Subject; -import org.apache.shiro.subject.support.SubjectThreadState; -import org.apache.shiro.lang.util.LifecycleUtils; +/* + * 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.test; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.UnavailableSecurityManagerException; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.subject.support.SubjectThreadState; +import org.apache.shiro.lang.util.LifecycleUtils; import org.apache.shiro.util.ThreadState; import org.junit.jupiter.api.AfterAll; -/** - * Abstract test case showing how to use Shiro in testing environments. - * - * @since 1.2 - */ -public abstract class AbstractShiroTest { - - private static ThreadState subjectThreadState; - - public AbstractShiroTest() { - } - - /** - * Allows subclasses to set the currently executing {@link Subject} instance. - * - * @param subject the Subject instance - */ - protected void setSubject(Subject subject) { - clearSubject(); - subjectThreadState = createThreadState(subject); - subjectThreadState.bind(); - } - - protected Subject getSubject() { - return SecurityUtils.getSubject(); - } - - protected ThreadState createThreadState(Subject subject) { - return new SubjectThreadState(subject); - } - - /** - * Clears Shiro's thread state, ensuring the thread remains clean for future test execution. - */ - protected void clearSubject() { - doClearSubject(); - } - - private static void doClearSubject() { - if (subjectThreadState != null) { - subjectThreadState.clear(); - subjectThreadState = null; - } - } - - protected static void setSecurityManager(SecurityManager securityManager) { - SecurityUtils.setSecurityManager(securityManager); - } - - protected static SecurityManager getSecurityManager() { - return SecurityUtils.getSecurityManager(); - } - - @AfterAll - public static void tearDownShiro() { - doClearSubject(); - try { - SecurityManager securityManager = getSecurityManager(); - LifecycleUtils.destroy(securityManager); - } catch (UnavailableSecurityManagerException e) { - //we don't care about this when cleaning up the test environment - //(for example, maybe the subclass is a unit test and it didn't - // need a SecurityManager instance because it was using only mock Subject instances) - } - setSecurityManager(null); - } -} +/** + * Abstract test case showing how to use Shiro in testing environments. + * + * @since 1.2 + */ +public abstract class AbstractShiroTest { + + private static ThreadState subjectThreadState; + + public AbstractShiroTest() { + } + + /** + * Allows subclasses to set the currently executing {@link Subject} instance. + * + * @param subject the Subject instance + */ + protected void setSubject(Subject subject) { + clearSubject(); + subjectThreadState = createThreadState(subject); + subjectThreadState.bind(); + } + + protected Subject getSubject() { + return SecurityUtils.getSubject(); + } + + protected ThreadState createThreadState(Subject subject) { + return new SubjectThreadState(subject); + } + + /** + * Clears Shiro's thread state, ensuring the thread remains clean for future test execution. + */ + protected void clearSubject() { + doClearSubject(); + } + + private static void doClearSubject() { + if (subjectThreadState != null) { + subjectThreadState.clear(); + subjectThreadState = null; + } + } + + protected static void setSecurityManager(SecurityManager securityManager) { + SecurityUtils.setSecurityManager(securityManager); + } + + protected static SecurityManager getSecurityManager() { + return SecurityUtils.getSecurityManager(); + } + + @AfterAll + public static void tearDownShiro() { + doClearSubject(); + try { + SecurityManager securityManager = getSecurityManager(); + LifecycleUtils.destroy(securityManager); + } catch (UnavailableSecurityManagerException e) { + //we don't care about this when cleaning up the test environment + //(for example, maybe the subclass is a unit test and it didn't + // need a SecurityManager instance because it was using only mock Subject instances) + } + setSecurityManager(null); + } +} diff --git a/core/src/test/java/org/apache/shiro/test/ExampleShiroIntegrationTest.java b/core/src/test/java/org/apache/shiro/test/ExampleShiroIntegrationTest.java index c01b9b80ab..202d1dc62d 100644 --- a/core/src/test/java/org/apache/shiro/test/ExampleShiroIntegrationTest.java +++ b/core/src/test/java/org/apache/shiro/test/ExampleShiroIntegrationTest.java @@ -1,63 +1,63 @@ -/* - * 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.test; - -import org.apache.shiro.ini.IniSecurityManagerFactory; -import org.apache.shiro.mgt.SecurityManager; -import org.apache.shiro.subject.Subject; +/* + * 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.test; + +import org.apache.shiro.ini.IniSecurityManagerFactory; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.subject.Subject; import org.apache.shiro.lang.util.Factory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -/** - * Simple example test class to be used to show how one might write Shiro-compatible unit tests. - * - * @since 1.2 - */ -public class ExampleShiroIntegrationTest extends AbstractShiroTest { - - @BeforeAll - public static void beforeClass() { - //0. Build and set the SecurityManager used to build Subject instances used in your tests - // This typically only needs to be done once per class if your shiro.ini doesn't change, - // otherwise, you'll need to do this logic in each test that is different - Factory factory = new IniSecurityManagerFactory("classpath:test.shiro.ini"); - setSecurityManager(factory.getInstance()); +/** + * Simple example test class to be used to show how one might write Shiro-compatible unit tests. + * + * @since 1.2 + */ +public class ExampleShiroIntegrationTest extends AbstractShiroTest { + + @BeforeAll + public static void beforeClass() { + //0. Build and set the SecurityManager used to build Subject instances used in your tests + // This typically only needs to be done once per class if your shiro.ini doesn't change, + // otherwise, you'll need to do this logic in each test that is different + Factory factory = new IniSecurityManagerFactory("classpath:test.shiro.ini"); + setSecurityManager(factory.getInstance()); } @Test - void testSimple() { - //1. Build the Subject instance for the test to run: - Subject subjectUnderTest = new Subject.Builder(getSecurityManager()).buildSubject(); - - //2. Bind the subject to the current thread: - setSubject(subjectUnderTest); - - //perform test logic here. Any call to - //SecurityUtils.getSubject() directly (or nested in the - //call stack) will work properly. - } - - @AfterEach - public void tearDownSubject() { - //3. Unbind the subject from the current thread: - clearSubject(); - } -} + void testSimple() { + //1. Build the Subject instance for the test to run: + Subject subjectUnderTest = new Subject.Builder(getSecurityManager()).buildSubject(); + + //2. Bind the subject to the current thread: + setSubject(subjectUnderTest); + + //perform test logic here. Any call to + //SecurityUtils.getSubject() directly (or nested in the + //call stack) will work properly. + } + + @AfterEach + public void tearDownSubject() { + //3. Unbind the subject from the current thread: + clearSubject(); + } +} diff --git a/core/src/test/java/org/apache/shiro/test/SecurityManagerTestSupport.java b/core/src/test/java/org/apache/shiro/test/SecurityManagerTestSupport.java index 2bbbc788a8..a793337045 100644 --- a/core/src/test/java/org/apache/shiro/test/SecurityManagerTestSupport.java +++ b/core/src/test/java/org/apache/shiro/test/SecurityManagerTestSupport.java @@ -72,7 +72,8 @@ protected Subject createSubject() { /** * Associates the {@code consumer} with the {@code subject} and executes. If an exeception was thrown by the * consumer, it is re-thrown by this method. - * @param subject The subject to bind to the current thread. + * + * @param subject The subject to bind to the current thread. * @param consumer The block of code to run under the context of the subject. * @throws Exception propagates any exception thrown by the consumer. */ diff --git a/core/src/test/java/org/apache/shiro/util/AntPathMatcherTests.java b/core/src/test/java/org/apache/shiro/util/AntPathMatcherTests.java index 12046c30a4..c01154d61f 100644 --- a/core/src/test/java/org/apache/shiro/util/AntPathMatcherTests.java +++ b/core/src/test/java/org/apache/shiro/util/AntPathMatcherTests.java @@ -21,17 +21,23 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +@SuppressWarnings("checkstyle:LineLength") /** * Unit tests for {@link AntPathMatcher}. - * - * Adapted from Spring Framework's similar AntPathMatcherTests + *

    + * Adapted from + * + * Spring Framework's similar AntPathMatcherTests */ public class AntPathMatcherTests { private final AntPathMatcher pathMatcher = new AntPathMatcher(); + @SuppressWarnings("checkstyle:MethodLength") @Test void match() { // test exact matching @@ -125,6 +131,7 @@ void matchWithNullPath() { assertFalse(pathMatcher.match(null, null)); } + @SuppressWarnings("checkstyle:MethodLength") @Test void matchStart() { // test exact matching @@ -325,4 +332,4 @@ void matches() { void isPatternWithNullPath() { assertFalse(pathMatcher.isPattern(null)); } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/apache/shiro/util/PermissionUtilsTest.java b/core/src/test/java/org/apache/shiro/util/PermissionUtilsTest.java index b33e0718f5..0a449eca9a 100644 --- a/core/src/test/java/org/apache/shiro/util/PermissionUtilsTest.java +++ b/core/src/test/java/org/apache/shiro/util/PermissionUtilsTest.java @@ -35,6 +35,7 @@ class PermissionUtilsTest { private static final PermissionResolver RESOLVER = new WildcardPermissionResolver(true); + @SuppressWarnings("checkstyle:MethodName") @Test void SHIRO_902_quoted_permissions() { // given diff --git a/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java b/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java index 9bf0315f3e..bace343840 100644 --- a/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java +++ b/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java @@ -20,7 +20,8 @@ import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Unit tests for the {@link RegExPatternMatcher}. @@ -61,7 +62,7 @@ private void assertPatternMatch(String pattern, String path) { } private void assertPatternMatch(String pattern, String path, PatternMatcher pm) { - assertTrue(pm.matches(pattern, path), "Expected path '" + path + "' to match pattern '" + pattern + "'" ); + assertTrue(pm.matches(pattern, path), "Expected path '" + path + "' to match pattern '" + pattern + "'"); } private void assertPatternNotMatch(String pattern, String path) { @@ -69,6 +70,6 @@ private void assertPatternNotMatch(String pattern, String path) { } private void assertPatternNotMatch(String pattern, String path, PatternMatcher pm) { - assertFalse(pm.matches(pattern, path), "Expected path '" + path + "' to NOT match pattern '" + pattern + "'" ); + assertFalse(pm.matches(pattern, path), "Expected path '" + path + "' to NOT match pattern '" + pattern + "'"); } } diff --git a/core/src/test/java/org/apache/shiro/util/StringUtilsTest.java b/core/src/test/java/org/apache/shiro/util/StringUtilsTest.java index 66bc894913..5dc352777c 100644 --- a/core/src/test/java/org/apache/shiro/util/StringUtilsTest.java +++ b/core/src/test/java/org/apache/shiro/util/StringUtilsTest.java @@ -18,11 +18,12 @@ */ package org.apache.shiro.util; -import static org.junit.jupiter.api.Assertions.*; - import org.apache.shiro.lang.util.StringUtils; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; /** * @since 0.9 @@ -41,7 +42,7 @@ void splitWithCommas() { String line = "shall,we,play,a,game?"; String[] split = StringUtils.split(line); assertNotNull(split); - assertTrue(split.length == 5); + assertEquals(5, split.length); assertEquals("shall", split[0]); assertEquals("we", split[1]); assertEquals("play", split[2]); @@ -54,7 +55,7 @@ void splitWithCommasAndSpaces() { String line = "shall,we , play, a,game?"; String[] split = StringUtils.split(line); assertNotNull(split); - assertTrue(split.length == 5); + assertEquals(5, split.length); assertEquals("shall", split[0]); assertEquals("we", split[1]); assertEquals("play", split[2]); @@ -67,7 +68,7 @@ void splitWithQuotedCommasAndSpaces() { String line = "shall, \"we, play\", a, game?"; String[] split = StringUtils.split(line); assertNotNull(split); - assertTrue(split.length == 4); + assertEquals(4, split.length); assertEquals("shall", split[0]); assertEquals("we, play", split[1]); assertEquals("a", split[2]); @@ -79,7 +80,7 @@ void splitWithQuotedCommasAndSpacesAndDifferentQuoteChars() { String line = "authc, test[blah], test[1,2,3], test[]"; String[] split = StringUtils.split(line, ',', '[', ']', false, true); assertNotNull(split); - assertTrue(split.length == 4); + assertEquals(4, split.length); assertEquals("authc", split[0]); assertEquals("testblah", split[1]); assertEquals("test1,2,3", split[2]); @@ -91,7 +92,7 @@ void splitWithQuotedCommasAndSpacesAndDifferentQuoteCharsWhileRetainingQuotes() String line = "authc, test[blah], test[1,2,3], test[]"; String[] split = StringUtils.split(line, ',', '[', ']', true, true); assertNotNull(split); - assertTrue(split.length == 4); + assertEquals(4, split.length); assertEquals("authc", split[0]); assertEquals("test[blah]", split[1]); assertEquals("test[1,2,3]", split[2]); @@ -103,7 +104,7 @@ void splitTestWithQuotedCommas() { String line = "authc, test[blah], test[\"1,2,3\"], test[]"; String[] split = StringUtils.split(line); assertNotNull(split); - assertTrue(split.length == 4); + assertEquals(4, split.length); assertEquals("authc", split[0]); assertEquals("test[blah]", split[1]); assertEquals("test[1,2,3]", split[2]); @@ -115,7 +116,7 @@ void splitWithQuotedCommasAndSpacesAndEscapedQuotes() { String line = "shall, \"\"\"we, play\", a, \"\"\"game?"; String[] split = StringUtils.split(line); assertNotNull(split); - assertTrue(split.length == 4); + assertEquals(4, split.length); assertEquals("shall", split[0]); assertEquals("\"we, play", split[1]); assertEquals("a", split[2]); diff --git a/crypto/cipher/pom.xml b/crypto/cipher/pom.xml index 43d96b292d..5a85da05a4 100644 --- a/crypto/cipher/pom.xml +++ b/crypto/cipher/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.apache.shiro diff --git a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/AesCipherService.java b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/AesCipherService.java index 3b1a0585b5..5d402336dd 100644 --- a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/AesCipherService.java +++ b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/AesCipherService.java @@ -27,10 +27,12 @@ * The AES algorithm can support key sizes of {@code 128}, {@code 192} and {@code 256} bits*. This implementation * defaults to 128 bits. *

    - * Note that this class retains changes the parent class's default {@link OperationMode#CBC CBC} mode to {@link OperationMode#GCM GCM} of operation - * instead of the typical JDK default of {@link OperationMode#ECB ECB}. {@code ECB} should not be used in - * security-sensitive environments because {@code ECB} does not allow for initialization vectors, which are - * considered necessary for strong encryption. See the {@link DefaultBlockCipherService parent class}'s JavaDoc and the + * Note that this class retains changes the parent class's default + * {@link OperationMode#CBC CBC} modeto {@link OperationMode#GCM GCM} of operation + * instead of the typical JDK default of {@link OperationMode#ECB ECB}. + * {@code ECB} should not be used in security-sensitive environments because {@code ECB} + * does not allow for initialization vectors, which are considered necessary for strong encryption. + * See the {@link DefaultBlockCipherService parent class}'s JavaDoc and the * {@link JcaCipherService JcaCipherService} JavaDoc for more on why the JDK default should not be used and is not * used in this implementation. *

    @@ -91,6 +93,7 @@ public class AesCipherService extends DefaultBlockCipherService { * {@code AES/GCM/NoPadding}. *

    * NOTE: As of Java 14, setting a streaming padding for the above example will throw a NoSuchAlgorithmException + * * @see JDK-8180392 */ public AesCipherService() { @@ -105,7 +108,7 @@ public AesCipherService() { protected AlgorithmParameterSpec createParameterSpec(byte[] iv, boolean streaming) { if ((streaming && OperationMode.GCM.name().equals(getStreamingModeName())) - || (!streaming && OperationMode.GCM.name().equals(getModeName()))) { + || (!streaming && OperationMode.GCM.name().equals(getModeName()))) { return new GCMParameterSpec(getKeySize(), iv); } diff --git a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/BlowfishCipherService.java b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/BlowfishCipherService.java index 894193d37a..45e47e55cb 100644 --- a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/BlowfishCipherService.java +++ b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/BlowfishCipherService.java @@ -87,6 +87,7 @@ public class BlowfishCipherService extends DefaultBlockCipherService { */ public BlowfishCipherService() { super(ALGORITHM_NAME); - setInitializationVectorSize(BLOCK_SIZE); //like most block ciphers, the IV size is the same as the block size + //like most block ciphers, the IV size is the same as the block size + setInitializationVectorSize(BLOCK_SIZE); } } diff --git a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/DefaultBlockCipherService.java b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/DefaultBlockCipherService.java index d147938e75..7496159fdf 100644 --- a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/DefaultBlockCipherService.java +++ b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/DefaultBlockCipherService.java @@ -122,7 +122,8 @@ * *

    * These attributes have the same meaning as the {@code mode}, {@code blockSize}, and {@code paddingScheme} attributes - * described above, but they are applied during streaming method invocations only ({@link #encrypt(java.io.InputStream, java.io.OutputStream, byte[])} + * described above, but they are applied during streaming method invocations only + * ({@link #encrypt(java.io.InputStream, java.io.OutputStream, byte[])} * and {@link #decrypt(java.io.InputStream, java.io.OutputStream, byte[])}). * * @see BlowfishCipherService @@ -135,18 +136,30 @@ public class DefaultBlockCipherService extends AbstractSymmetricCipherService { private static final int DEFAULT_BLOCK_SIZE = 0; private static final String TRANSFORMATION_STRING_DELIMITER = "/"; - private static final int DEFAULT_STREAMING_BLOCK_SIZE = 8; //8 bits (1 byte) + //8 bits (1 byte) + private static final int DEFAULT_STREAMING_BLOCK_SIZE = 8; private String modeName; - private int blockSize; //size in bits (not bytes) - i.e. a blockSize of 8 equals 1 byte. negative or zero value = use system default + + /** + * size in bits (not bytes) - i.e. a blockSize of 8 equals 1 byte. negative or zero value = use system default + */ + private int blockSize; private String paddingSchemeName; private String streamingModeName; private int streamingBlockSize; private String streamingPaddingSchemeName; - private String transformationString; //cached value - rebuilt whenever any of its constituent parts change - private String streamingTransformationString; //cached value - rebuilt whenever any of its constituent parts change + /** + * cached value - rebuilt whenever any of its constituent parts change. + */ + private String transformationString; + + /** + * cached value - rebuilt whenever any of its constituent parts change. + */ + private String streamingTransformationString; /** @@ -166,7 +179,8 @@ public DefaultBlockCipherService(String algorithmName) { this.modeName = OperationMode.CBC.name(); this.paddingSchemeName = PaddingScheme.PKCS5.getTransformationName(); - this.blockSize = DEFAULT_BLOCK_SIZE; //0 = use the JCA provider's default + //0 = use the JCA provider's default + this.blockSize = DEFAULT_BLOCK_SIZE; this.streamingModeName = OperationMode.CBC.name(); this.streamingPaddingSchemeName = PaddingScheme.PKCS5.getTransformationName(); @@ -186,8 +200,8 @@ public DefaultBlockCipherService(String algorithmName) { * The default value is {@code null} to retain the JCA Provider default. * * @return the cipher operation mode name (as a String) to be used when constructing the - * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default - * mode for the specified {@link #getAlgorithmName() algorithm} should be used. + * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default + * mode for the specified {@link #getAlgorithmName() algorithm} should be used. */ public String getModeName() { return modeName; @@ -256,8 +270,8 @@ public void setMode(OperationMode mode) { * The default value is {@code null} to retain the JCA Provider default. * * @return the padding scheme name (as a String) to be used when constructing the - * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default - * padding scheme for the specified {@link #getAlgorithmName() algorithm} should be used. + * {@link javax.crypto.Cipher Cipher} transformation string, or {@code null} if the JCA Provider default + * padding scheme for the specified {@link #getAlgorithmName() algorithm} should be used. */ public String getPaddingSchemeName() { return paddingSchemeName; @@ -328,8 +342,8 @@ public void setPaddingScheme(PaddingScheme paddingScheme) { * The default value is {@code 0} which retains the JCA Provider default. * * @return the block cipher block size to be used when constructing the - * {@link javax.crypto.Cipher Cipher} transformation string, or {@code 0} if the JCA Provider default - * block size for the specified {@link #getAlgorithmName() algorithm} should be used. + * {@link javax.crypto.Cipher Cipher} transformation string, or {@code 0} if the JCA Provider default + * block size for the specified {@link #getAlgorithmName() algorithm} should be used. */ public int getBlockSize() { return blockSize; @@ -376,9 +390,9 @@ public String getStreamingModeName() { } private boolean isModeStreamingCompatible(String modeName) { - return modeName != null && - !modeName.equalsIgnoreCase(OperationMode.ECB.name()) && - !modeName.equalsIgnoreCase(OperationMode.NONE.name()); + return modeName != null + && !modeName.equalsIgnoreCase(OperationMode.ECB.name()) + && !modeName.equalsIgnoreCase(OperationMode.NONE.name()); } /** @@ -483,12 +497,12 @@ private String buildTransformationString(String modeName, String paddingSchemeNa * * @param modeName the raw text name of the mode of operation * @return {@code true} if the specified cipher operation mode name supports initialization vectors, - * {@code false} otherwise. + * {@code false} otherwise. */ private boolean isModeInitializationVectorCompatible(String modeName) { - return modeName != null && - !modeName.equalsIgnoreCase(OperationMode.ECB.name()) && - !modeName.equalsIgnoreCase(OperationMode.NONE.name()); + return modeName != null + && !modeName.equalsIgnoreCase(OperationMode.ECB.name()) + && !modeName.equalsIgnoreCase(OperationMode.NONE.name()); } /** @@ -500,7 +514,7 @@ private boolean isModeInitializationVectorCompatible(String modeName) { * * @param streaming whether or not streaming is being performed * @return {@code true} if streaming or a value computed based on if the currently configured mode is compatible - * with initialization vectors. + * with initialization vectors. */ @Override protected boolean isGenerateInitializationVectors(boolean streaming) { @@ -512,17 +526,17 @@ protected byte[] generateInitializationVector(boolean streaming) { if (streaming) { String streamingModeName = getStreamingModeName(); if (!isModeInitializationVectorCompatible(streamingModeName)) { - String msg = "streamingMode attribute value [" + streamingModeName + "] does not support " + - "Initialization Vectors. Ensure the streamingMode value represents an operation mode " + - "that is compatible with initialization vectors."; + String msg = "streamingMode attribute value [" + streamingModeName + "] does not support " + + "Initialization Vectors. Ensure the streamingMode value represents an operation mode " + + "that is compatible with initialization vectors."; throw new IllegalStateException(msg); } } else { String modeName = getModeName(); if (!isModeInitializationVectorCompatible(modeName)) { - String msg = "mode attribute value [" + modeName + "] does not support " + - "Initialization Vectors. Ensure the mode value represents an operation mode " + - "that is compatible with initialization vectors."; + String msg = "mode attribute value [" + modeName + "] does not support " + + "Initialization Vectors. Ensure the mode value represents an operation mode " + + "that is compatible with initialization vectors."; throw new IllegalStateException(msg); } } diff --git a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/JcaCipherService.java b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/JcaCipherService.java index 49d738b0fa..fb832d201b 100644 --- a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/JcaCipherService.java +++ b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/JcaCipherService.java @@ -67,12 +67,13 @@ * * @since 1.0 */ +@SuppressWarnings("checkstyle:MethodCount") public abstract class JcaCipherService implements CipherService { /** * Internal private log instance. */ - private static final Logger log = LoggerFactory.getLogger(JcaCipherService.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JcaCipherService.class); /** * Default key size (in bits) for generated keys. @@ -129,7 +130,8 @@ protected JcaCipherService(String algorithmName) { } this.algorithmName = algorithmName; this.keySize = DEFAULT_KEY_SIZE; - this.initializationVectorSize = DEFAULT_KEY_SIZE; //default to same size as the key size (a common algorithm practice) + //default to same size as the key size (a common algorithm practice) + this.initializationVectorSize = DEFAULT_KEY_SIZE; this.streamingBufferSize = DEFAULT_STREAMING_BUFFER_SIZE; this.generateInitializationVectors = true; } @@ -189,8 +191,8 @@ public int getInitializationVectorSize() { */ public void setInitializationVectorSize(int initializationVectorSize) throws IllegalArgumentException { if (initializationVectorSize % BITS_PER_BYTE != 0) { - String msg = "Initialization vector sizes are specified in bits, but must be a multiple of 8 so they " + - "can be easily represented as a byte array."; + String msg = "Initialization vector sizes are specified in bits, but must be a multiple of 8 so they " + + "can be easily represented as a byte array."; throw new IllegalArgumentException(msg); } this.initializationVectorSize = initializationVectorSize; @@ -208,7 +210,7 @@ protected boolean isGenerateInitializationVectors(boolean streaming) { * Default size is {@code 512} bytes. * * @return the size of the internal buffer used to transfer data from one stream to another during stream - * operations + * operations */ public int getStreamingBufferSize() { return streamingBufferSize; @@ -233,7 +235,7 @@ public void setStreamingBufferSize(int streamingBufferSize) { * algorithm needs one, the JDK {@code SHA1PRNG} instance will be used by default. * * @return a source of randomness for encryption operations. If one is not configured, and the underlying - * algorithm needs one, the JDK {@code SHA1PRNG} instance will be used by default. + * algorithm needs one, the JDK {@code SHA1PRNG} instance will be used by default. */ public SecureRandom getSecureRandom() { return secureRandom; @@ -254,8 +256,8 @@ protected static SecureRandom getDefaultSecureRandom() { try { return java.security.SecureRandom.getInstance(RANDOM_NUM_GENERATOR_ALGORITHM_NAME); } catch (java.security.NoSuchAlgorithmException e) { - log.debug("The SecureRandom SHA1PRNG algorithm is not available on the current platform. Using the " + - "platform's default SecureRandom algorithm.", e); + LOGGER.debug("The SecureRandom SHA1PRNG algorithm is not available on the current platform. Using the " + + "platform's default SecureRandom algorithm.", e); return new java.security.SecureRandom(); } } @@ -276,7 +278,7 @@ protected SecureRandom ensureSecureRandom() { * * @param streaming if the transformation string is going to be used for a Cipher for stream-based encryption or not. * @return the transformation string to use with the {@link javax.crypto.Cipher#getInstance} invocation when - * creating a new {@code Cipher} instance. + * creating a new {@code Cipher} instance. */ protected String getTransformationString(boolean streaming) { return getAlgorithmName(); @@ -285,9 +287,9 @@ protected String getTransformationString(boolean streaming) { protected byte[] generateInitializationVector(boolean streaming) { int size = getInitializationVectorSize(); if (size <= 0) { - String msg = "initializationVectorSize property must be greater than zero. This number is " + - "typically set in the " + CipherService.class.getSimpleName() + " subclass constructor. " + - "Also check your configuration to ensure that if you are setting a value, it is positive."; + String msg = "initializationVectorSize property must be greater than zero. This number is " + + "typically set in the " + CipherService.class.getSimpleName() + " subclass constructor. " + + "Also check your configuration to ensure that if you are setting a value, it is positive."; throw new IllegalStateException(msg); } if (size % BITS_PER_BYTE != 0) { @@ -307,8 +309,8 @@ public ByteSource encrypt(byte[] plaintext, byte[] key) { if (generate) { ivBytes = generateInitializationVector(false); if (ivBytes == null || ivBytes.length == 0) { - throw new IllegalStateException("Initialization vector generation is enabled - generated vector " + - "cannot be null or empty."); + throw new IllegalStateException("Initialization vector generation is enabled - generated vector " + + "cannot be null or empty."); } } return encrypt(plaintext, key, ivBytes, generate); @@ -316,13 +318,13 @@ public ByteSource encrypt(byte[] plaintext, byte[] key) { private ByteSource encrypt(byte[] plaintext, byte[] key, byte[] iv, boolean prependIv) throws CryptoException { - final int MODE = javax.crypto.Cipher.ENCRYPT_MODE; + final int mode = javax.crypto.Cipher.ENCRYPT_MODE; byte[] output; if (prependIv && iv != null && iv.length > 0) { - byte[] encrypted = crypt(plaintext, key, iv, MODE); + byte[] encrypted = crypt(plaintext, key, iv, mode); output = new byte[iv.length + encrypted.length]; @@ -334,12 +336,12 @@ private ByteSource encrypt(byte[] plaintext, byte[] key, byte[] iv, boolean prep // + encrypted bytes: System.arraycopy(encrypted, 0, output, iv.length, encrypted.length); } else { - output = crypt(plaintext, key, iv, MODE); + output = crypt(plaintext, key, iv, mode); } - if (log.isTraceEnabled()) { - log.trace("Incoming plaintext of size " + (plaintext != null ? plaintext.length : 0) + ". Ciphertext " + - "byte array is size " + (output != null ? output.length : 0)); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Incoming plaintext of size " + (plaintext != null ? plaintext.length : 0) + ". Ciphertext " + + "byte array is size " + (output != null ? output.length : 0)); } return ByteSource.Util.bytes(output); @@ -388,9 +390,9 @@ ByteSource decryptInternal(byte[] ciphertext, byte[] key) throws CryptoException } private ByteSource decryptInternal(byte[] ciphertext, byte[] key, byte[] iv) throws CryptoException { - if (log.isTraceEnabled()) { - log.trace("Attempting to decrypt incoming byte array of length " + - (ciphertext != null ? ciphertext.length : 0)); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Attempting to decrypt incoming byte array of length " + + (ciphertext != null ? ciphertext.length : 0)); } byte[] decrypted = crypt(ciphertext, key, iv, javax.crypto.Cipher.DECRYPT_MODE); return decrypted == null ? null : ByteSource.Util.bytes(decrypted); @@ -412,10 +414,10 @@ private javax.crypto.Cipher newCipherInstance(boolean streaming) throws CryptoEx try { return javax.crypto.Cipher.getInstance(transformationString); } catch (Exception e) { - String msg = "Unable to acquire a Java JCA Cipher instance using " + - javax.crypto.Cipher.class.getName() + ".getInstance( \"" + transformationString + "\" ). " + - getAlgorithmName() + " under this configuration is required for the " + - getClass().getName() + " instance to function."; + String msg = "Unable to acquire a Java JCA Cipher instance using " + + javax.crypto.Cipher.class.getName() + ".getInstance( \"" + transformationString + "\" ). " + + getAlgorithmName() + " under this configuration is required for the " + + getClass().getName() + " instance to function."; throw new CryptoException(msg, e); } } @@ -508,8 +510,8 @@ public void encrypt(InputStream in, OutputStream out, byte[] key) throws CryptoE if (generate) { iv = generateInitializationVector(true); if (iv == null || iv.length == 0) { - throw new IllegalStateException("Initialization vector generation is enabled - generated vector " + - "cannot be null or empty."); + throw new IllegalStateException("Initialization vector generation is enabled - generated vector " + + "cannot be null or empty."); } } encrypt(in, out, key, iv, generate); @@ -552,9 +554,8 @@ private void decrypt(InputStream in, OutputStream out, byte[] key, boolean ivPre } if (read != ivByteSize) { - throw new CryptoException("Unable to read initialization vector bytes from the InputStream. " + - "This is required when initialization vectors are autogenerated during an encryption " + - "operation."); + throw new CryptoException("Unable to read initialization vector bytes from the InputStream. " + + "This is required when initialization vectors are autogenerated during an encryption operation."); } } diff --git a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/PaddingScheme.java b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/PaddingScheme.java index 2d7264cdb6..5a3e16b401 100644 --- a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/PaddingScheme.java +++ b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/PaddingScheme.java @@ -147,7 +147,7 @@ public enum PaddingScheme { private final String transformationName; - private PaddingScheme(String transformationName) { + PaddingScheme(String transformationName) { this.transformationName = transformationName; } @@ -156,7 +156,7 @@ private PaddingScheme(String transformationName) { * {@code transformation string}. * * @return the actual string name to use when building the {@link javax.crypto.Cipher Cipher} - * {@code transformation string}. + * {@code transformation string}. * @see javax.crypto.Cipher#getInstance(String) */ public String getTransformationName() { diff --git a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/SimpleByteSourceBroker.java b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/SimpleByteSourceBroker.java index c5f7625b75..8e872f558c 100644 --- a/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/SimpleByteSourceBroker.java +++ b/crypto/cipher/src/main/java/org/apache/shiro/crypto/cipher/SimpleByteSourceBroker.java @@ -23,6 +23,7 @@ import org.apache.shiro.lang.util.Destroyable; import java.io.IOException; + import org.apache.shiro.lang.util.ByteSourceWrapper; import org.apache.shiro.lang.util.ByteUtils; @@ -34,7 +35,7 @@ public class SimpleByteSourceBroker implements ByteSourceBroker, Destroyable { private JcaCipherService cipherService; private byte[] ciphertext; private byte[] key; - private boolean destroyed = false; + private boolean destroyed; public SimpleByteSourceBroker(JcaCipherService cipherService, byte[] ciphertext, byte[] key) { this.cipherService = cipherService; @@ -58,7 +59,8 @@ public synchronized void useBytes(ByteSourceUser user) { public byte[] getClonedBytes() { ByteSource byteSource = cipherService.decryptInternal(ciphertext, key); - return byteSource.getBytes(); // this's a newly created byte array + // this's a newly created byte array + return byteSource.getBytes(); } public void destroy() throws Exception { diff --git a/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/AesCipherServiceTest.groovy b/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/AesCipherServiceTest.groovy index 6188804a12..7da9895fbe 100644 --- a/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/AesCipherServiceTest.groovy +++ b/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/AesCipherServiceTest.groovy @@ -38,8 +38,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue class AesCipherServiceTest { private static final String[] PLAINTEXTS = [ - "Hello, this is a test.", - "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + "Hello, this is a test.", + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." ] AesCipherServiceTest() { diff --git a/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/BlowfishCipherServiceTest.groovy b/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/BlowfishCipherServiceTest.groovy index edac0b6523..bbb0b8f58b 100644 --- a/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/BlowfishCipherServiceTest.groovy +++ b/crypto/cipher/src/test/groovy/org/apache/shiro/crypto/cipher/BlowfishCipherServiceTest.groovy @@ -34,8 +34,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue public class BlowfishCipherServiceTest { private static final String[] PLAINTEXTS = [ - "Hello, this is a test.", - "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + "Hello, this is a test.", + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." ]; @Test diff --git a/crypto/core/pom.xml b/crypto/core/pom.xml index 6105d06b10..2e5e210e54 100644 --- a/crypto/core/pom.xml +++ b/crypto/core/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.apache.shiro diff --git a/crypto/core/src/main/java/org/apache/shiro/crypto/RandomNumberGenerator.java b/crypto/core/src/main/java/org/apache/shiro/crypto/RandomNumberGenerator.java index 080d2f7a47..7a5a85a1e5 100644 --- a/crypto/core/src/main/java/org/apache/shiro/crypto/RandomNumberGenerator.java +++ b/crypto/core/src/main/java/org/apache/shiro/crypto/RandomNumberGenerator.java @@ -1,72 +1,72 @@ -/* - * 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: - *

      - *
    • It is an interface rather than the JDK's {@code SecureRandom} concrete implementation. Implementation details - * can be customized as necessary based on the application's needs
    • - *
    • Default per-instance behavior can be customized on implementations, typically via JavaBeans mutators.
    • - *
    • Perhaps most important for Shiro end-users, tt can more easily be used as a source of cryptographic seed data, - * and the data returned is already in a more convenient {@link ByteSource ByteSource} format in case that data needs - * to be {@link org.apache.shiro.lang.util.ByteSource#toHex() hex} or - * {@link org.apache.shiro.lang.util.ByteSource#toBase64() base64}-encoded.
    • - *
    - * For example, consider the following example generating password salts for new user accounts: - *
    - * 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: + *

      + *
    • It is an interface rather than the JDK's {@code SecureRandom} concrete implementation. Implementation details + * can be customized as necessary based on the application's needs
    • + *
    • Default per-instance behavior can be customized on implementations, typically via JavaBeans mutators.
    • + *
    • Perhaps most important for Shiro end-users, tt can more easily be used as a source of cryptographic seed data, + * and the data returned is already in a more convenient {@link ByteSource ByteSource} format in case that data needs + * to be {@link org.apache.shiro.lang.util.ByteSource#toHex() hex} or + * {@link org.apache.shiro.lang.util.ByteSource#toBase64() base64}-encoded.
    • + *
    + * For example, consider the following example generating password salts for new user accounts: + *
    + * 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 1c3e1add5a..0528254b5d 100644 --- a/crypto/hash/pom.xml +++ b/crypto/hash/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.apache.shiro diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractCryptHash.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractCryptHash.java index f056c617ff..631505b8d9 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractCryptHash.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/AbstractCryptHash.java @@ -47,10 +47,10 @@ */ public abstract class AbstractCryptHash implements Hash, Serializable { - private static final long serialVersionUID = 2483214646921027859L; - protected static final Pattern DELIMITER = Pattern.compile("\\$"); + private static final long serialVersionUID = 2483214646921027859L; + private final String algorithmName; private final byte[] hashedData; private final ByteSource salt; @@ -70,8 +70,8 @@ public abstract class AbstractCryptHash implements Hash, Serializable { *

    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 getSalt(); @@ -94,11 +94,11 @@ public interface HashRequest { * @see SimpleHashRequest * @since 1.2 */ - public static class Builder { + class Builder { private ByteSource source; private ByteSource salt = SimpleByteSource.empty(); - private Map parameters = new ConcurrentHashMap<>(); + private final Map parameters = new ConcurrentHashMap<>(); private String algorithmName; /** diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashService.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashService.java index 126c2e982b..30e4e9807b 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashService.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/HashService.java @@ -56,7 +56,7 @@ public interface HashService { * Computes a hash based on the given request. * *

    Salt Notice

    - * + *

    * 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 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); - 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 Set IMPLEMENTED_ALGORITHMS = Arrays.stream(new String[]{ - Sha256Hash.ALGORITHM_NAME, - Sha384Hash.ALGORITHM_NAME, - Sha512Hash.ALGORITHM_NAME - }) + private static final Set IMPLEMENTED_ALGORITHMS = Arrays.stream(new String[] { + Sha256Hash.ALGORITHM_NAME, + Sha384Hash.ALGORITHM_NAME, + Sha512Hash.ALGORITHM_NAME + }) .collect(toSet()); @Override @@ -72,7 +73,7 @@ static class SimpleHashFactory implements HashSpi.HashFactory { private final Random random; - public SimpleHashFactory(Random random) { + SimpleHashFactory(Random random) { this.random = random; } @@ -113,6 +114,7 @@ protected ByteSource getPublicSalt(HashRequest request) { } // generate salt if absent from the request. + @SuppressWarnings("checkstyle:MagicNumber") byte[] ps = new byte[16]; random.nextBytes(ps); @@ -129,7 +131,8 @@ private ByteSource getSecretSalt(HashRequest request) { .orElse(null); } - private SimpleHash createSimpleHash(String algorithmName, ByteSource source, int iterations, ByteSource publicSalt, ByteSource salt) { + private SimpleHash createSimpleHash(String algorithmName, ByteSource source, + int iterations, ByteSource publicSalt, ByteSource salt) { Hash computed = new SimpleHash(algorithmName, source, salt, iterations); SimpleHash result = new SimpleHash(algorithmName); @@ -203,7 +206,8 @@ static final class Parameters { /** * A secret part added to the salt. Sometimes also referred to as {@literal "Pepper"}. * - *

    For 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 Map parameters = new ConcurrentHashMap<>(); /** * Creates a new SimpleHashRequest instance. * * @param algorithmName the name of the hash algorithm to use. This is often null as the - * {@link HashService} implementation is usually configured with an appropriate algorithm name, but this - * can be non-null if the hash service's algorithm should be overridden with a specific one for the duration - * of the request. + * {@link HashService} implementation is usually configured with an + * appropriate algorithm name, but this can be non-null + * if the hash service's algorithm should be overridden with a + * specific one for the duration of the request. * @param source the source to be hashed * @param salt any public salt which should be used when computing the hash * @param parameters e.g. the number of hash iterations to execute or other parameters. diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/DefaultHashFormatFactory.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/DefaultHashFormatFactory.java index ae09b13bce..d4f26d2c04 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/DefaultHashFormatFactory.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/DefaultHashFormatFactory.java @@ -18,6 +18,9 @@ */ package org.apache.shiro.crypto.hash.format; +import java.util.Iterator; +import java.util.stream.Stream; + import org.apache.shiro.lang.util.ClassUtils; import org.apache.shiro.lang.util.StringUtils; import org.apache.shiro.lang.util.UnknownClassException; @@ -36,9 +39,11 @@ */ public class DefaultHashFormatFactory implements HashFormatFactory { - private Map formatClassNames; //id - to - fully qualified class name + //id - to - fully qualified class name + private Map formatClassNames; - private Set searchPackages; //packages to search for HashFormat implementations + //packages to search for HashFormat implementations + private Set searchPackages; public DefaultHashFormatFactory() { this.searchPackages = new HashSet(); @@ -279,51 +284,30 @@ protected Class getHashFormatClass(String token) { * @param token the string token from which a class name will be heuristically determined. * @return the discovered HashFormat class implementation or {@code null} if no class could be heuristically determined. */ - protected Class getHashFormatClass(String packageName, String token) { + protected Class getHashFormatClass(String packageName, String token) { String test = token; - Class clazz = null; + Class clazz; String pkg = packageName == null ? "" : packageName; //1. Assume the arg is a fully qualified class name in the classpath: clazz = lookupHashFormatClass(test); - if (clazz == null) { - test = pkg + "." + token; - clazz = lookupHashFormatClass(test); - } - - if (clazz == null) { - test = pkg + "." + StringUtils.uppercaseFirstChar(token) + "Format"; - clazz = lookupHashFormatClass(test); - } - - if (clazz == null) { - test = pkg + "." + token + "Format"; - clazz = lookupHashFormatClass(test); - } - - if (clazz == null) { - test = pkg + "." + StringUtils.uppercaseFirstChar(token) + "HashFormat"; - clazz = lookupHashFormatClass(test); - } - - if (clazz == null) { - test = pkg + "." + token + "HashFormat"; - clazz = lookupHashFormatClass(test); + final Iterator iterator = Stream.of( + pkg + "." + token, + pkg + "." + StringUtils.uppercaseFirstChar(token) + "Format", + pkg + "." + token + "Format", + pkg + "." + StringUtils.uppercaseFirstChar(token) + "HashFormat", + pkg + "." + token + "HashFormat", + pkg + "." + StringUtils.uppercaseFirstChar(token) + "CryptFormat", + pkg + "." + token + "CryptFormat").iterator(); + + while (clazz == null && iterator.hasNext()) { + clazz = lookupHashFormatClass(iterator.next()); } if (clazz == null) { - test = pkg + "." + StringUtils.uppercaseFirstChar(token) + "CryptFormat"; - clazz = lookupHashFormatClass(test); - } - - if (clazz == null) { - test = pkg + "." + token + "CryptFormat"; - clazz = lookupHashFormatClass(test); - } - - if (clazz == null) { - return null; //ran out of options + //ran out of options + return null; } assertHashFormatImpl(clazz); @@ -331,7 +315,7 @@ protected Class getHashFormatClass(String packageName, String token) { return clazz; } - protected Class lookupHashFormatClass(String name) { + protected Class lookupHashFormatClass(String name) { try { return ClassUtils.forName(name); } catch (UnknownClassException ignored) { @@ -342,8 +326,8 @@ protected Class lookupHashFormatClass(String name) { protected final void assertHashFormatImpl(Class clazz) { if (!HashFormat.class.isAssignableFrom(clazz) || clazz.isInterface()) { - throw new IllegalArgumentException("Discovered class [" + clazz.getName() + "] is not a " + - HashFormat.class.getName() + " implementation."); + throw new IllegalArgumentException("Discovered class [" + clazz.getName() + "] is not a " + + HashFormat.class.getName() + " implementation."); } } diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ModularCryptFormat.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ModularCryptFormat.java index ce4917556e..78ba41eebd 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ModularCryptFormat.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ModularCryptFormat.java @@ -28,7 +28,10 @@ */ public interface ModularCryptFormat extends HashFormat { - public static final String TOKEN_DELIMITER = "$"; + /** + * token delimiter. + */ + String TOKEN_DELIMITER = "$"; /** * Returns the Modular Crypt Format identifier that indicates how the formatted String should be parsed. This id diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ParsableHashFormat.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ParsableHashFormat.java index 045756805b..cd4b901846 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ParsableHashFormat.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/ParsableHashFormat.java @@ -28,7 +28,6 @@ * (like Unix Crypt(3)) only support one way conversion and therefore wouldn't implement this interface. * * @see Shiro1CryptFormat - * * @since 1.2 */ public interface ParsableHashFormat extends HashFormat { diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/Shiro1CryptFormat.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/Shiro1CryptFormat.java index 1428f3abd9..e706488e39 100644 --- a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/Shiro1CryptFormat.java +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/Shiro1CryptFormat.java @@ -83,12 +83,18 @@ * * @see ModularCryptFormat * @see ParsableHashFormat - * * @since 1.2 */ public class Shiro1CryptFormat implements ModularCryptFormat, ParsableHashFormat { + /** + * shiro1 crypt id. + */ public static final String ID = "shiro1"; + + /** + * shiro1 crypt format prefix + */ public static final String MCF_PREFIX = TOKEN_DELIMITER + ID + TOKEN_DELIMITER; public Shiro1CryptFormat() { @@ -108,7 +114,11 @@ public String format(final Hash hash) { String algorithmName = hash.getAlgorithmName(); ByteSource salt = hash.getSalt(); int iterations = hash.getIterations(); - StringBuilder sb = new StringBuilder(MCF_PREFIX).append(algorithmName).append(TOKEN_DELIMITER).append(iterations).append(TOKEN_DELIMITER); + StringBuilder sb = new StringBuilder(MCF_PREFIX) + .append(algorithmName) + .append(TOKEN_DELIMITER) + .append(iterations) + .append(TOKEN_DELIMITER); if (salt != null) { sb.append(salt.toBase64()); diff --git a/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/package-info.java b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/package-info.java new file mode 100644 index 0000000000..e3c5042348 --- /dev/null +++ b/crypto/hash/src/main/java/org/apache/shiro/crypto/hash/format/package-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +/** + * Cryptographic Hashing components that greatly simplify one-way data hashing in an application. + *

    + * The {@link org.apache.shiro.crypto.hash.Hash Hash} interface and its implementations are significantly + * easier to understand and use compared to the JDK's MessageDigest mechanism. + */ +package org.apache.shiro.crypto.hash.format; 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. --> - + 4.0.0 diff --git a/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2Hash.java b/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2Hash.java index 86bcdcac6a..67d2d8ba33 100644 --- a/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2Hash.java +++ b/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2Hash.java @@ -51,17 +51,26 @@ * argon2-cffi.readthedocs.io. * The RFC suggests to use 1 GiB of memory for frontend and 4 GiB for backend authentication.

    * - *

    Example crypt string is: {@code $argon2i$v=19$m=16384,t=100,p=2$M3ByeyZKLjFRREJqQi87WQ$5kRCtDjL6RoIWGq9bL27DkFNunucg1hW280PmP0XDtY}.

    + *

    Example crypt string is: + * {@code $argon2i$v=19$m=16384,t=100,p=2$M3ByeyZKLjFRREJqQi87WQ$5kRCtDjL6RoIWGq9bL27DkFNunucg1hW280PmP0XDtY}.

    * - *

    Default values are taken from draft-irtf-cfrg-argon2-13. + *

    Default values are taken from + * draft-irtf-cfrg-argon2-13. * This implementation is using the parameters from section 4, paragraph 2 (memory constrained environment).

    * * @since 2.0 */ class Argon2Hash extends AbstractCryptHash { - private static final long serialVersionUID = 2647354947284558921L; - private static final Logger LOG = LoggerFactory.getLogger(Argon2Hash.class); + /** + * Number of default lanes, p=4 is the default recommendation, taken from draft-irtf-cfrg-argon2-13, 4.2. + */ + public static final int DEFAULT_PARALLELISM = 4; + + /** + * 256 bits tag size is the default recommendation, taken from draft-irtf-cfrg-argon2-13, 4.2. + */ + public static final int DEFAULT_OUTPUT_LENGTH_BITS = 256; public static final String DEFAULT_ALGORITHM_NAME = "argon2id"; @@ -77,20 +86,13 @@ class Argon2Hash extends AbstractCryptHash { */ public static final int DEFAULT_MEMORY_KIB = 64 * 1024; - private static final Set ALGORITHMS_ARGON2 = new HashSet<>(Arrays.asList("argon2id", "argon2i", "argon2d")); - - private static final Pattern DELIMITER_COMMA = Pattern.compile(","); + private static final long serialVersionUID = 2647354947284558921L; - /** - * Number of default lanes, p=4 is the default recommendation, taken from draft-irtf-cfrg-argon2-13, 4.2. - */ - public static final int DEFAULT_PARALLELISM = 4; + private static final Logger LOG = LoggerFactory.getLogger(Argon2Hash.class); - /** - * 256 bits tag size is the default recommendation, taken from draft-irtf-cfrg-argon2-13, 4.2. - */ - public static final int DEFAULT_OUTPUT_LENGTH_BITS = 256; + private static final Set ALGORITHMS_ARGON2 = new HashSet<>(Arrays.asList("argon2id", "argon2i", "argon2d")); + private static final Pattern DELIMITER_COMMA = Pattern.compile(","); /** * 128 bits of salt is the recommended salt length, taken from draft-irtf-cfrg-argon2-13, 4.2. @@ -105,7 +107,8 @@ class Argon2Hash extends AbstractCryptHash { private final int parallelism; - public Argon2Hash(String algorithmName, int argonVersion, byte[] hashedData, ByteSource salt, int iterations, int memoryAsKB, int parallelism) { + Argon2Hash(String algorithmName, int argonVersion, byte[] hashedData, + ByteSource salt, int iterations, int memoryAsKB, int parallelism) { super(algorithmName, hashedData, salt); this.argonVersion = argonVersion; this.iterations = iterations; @@ -123,6 +126,7 @@ protected static ByteSource createSalt() { return createSalt(new SecureRandom()); } + @SuppressWarnings("checkstyle:MagicNumber") public static ByteSource createSalt(SecureRandom random) { return new SimpleByteSource(random.generateSeed(SALT_LENGTH_BITS / 8)); } @@ -138,7 +142,8 @@ public static Argon2Hash fromString(String input) { final String algorithmName = parts[0].trim(); if (!ALGORITHMS_ARGON2.contains(algorithmName)) { - throw new UnsupportedOperationException("Unsupported algorithm: " + algorithmName + ". Expected one of: " + ALGORITHMS_ARGON2); + throw new UnsupportedOperationException("Unsupported algorithm: " + algorithmName + + ". Expected one of: " + ALGORITHMS_ARGON2); } final int version = parseVersion(parts[1]); @@ -156,7 +161,8 @@ private static int parseParallelism(String parameters) { String parameter = DELIMITER_COMMA.splitAsStream(parameters) .filter(parm -> parm.startsWith("p=")) .findAny() - .orElseThrow(() -> new IllegalArgumentException("Did not found memory parameter 'p='. Got: [" + parameters + "].")); + .orElseThrow(() -> new IllegalArgumentException("Did not found memory parameter 'p='. Got: [" + + parameters + "].")); return Integer.parseInt(parameter.substring(2)); } @@ -164,7 +170,8 @@ private static int parseIterations(String parameters) { String parameter = DELIMITER_COMMA.splitAsStream(parameters) .filter(parm -> parm.startsWith("t=")) .findAny() - .orElseThrow(() -> new IllegalArgumentException("Did not found memory parameter 't='. Got: [" + parameters + "].")); + .orElseThrow(() -> new IllegalArgumentException("Did not found memory parameter 't='. Got: [" + + parameters + "].")); return Integer.parseInt(parameter.substring(2)); } @@ -173,7 +180,8 @@ private static int parseMemory(String parameters) { String parameter = DELIMITER_COMMA.splitAsStream(parameters) .filter(parm -> parm.startsWith("m=")) .findAny() - .orElseThrow(() -> new IllegalArgumentException("Did not found memory parameter 'm='. Got: [" + parameters + "].")); + .orElseThrow(() -> new IllegalArgumentException("Did not found memory parameter 'm='. Got: [" + + parameters + "].")); return Integer.parseInt(parameter.substring(2)); } @@ -195,7 +203,8 @@ public static Argon2Hash generate(final ByteSource source, final ByteSource salt } public static Argon2Hash generate(String algorithmName, ByteSource source, ByteSource salt, int iterations) { - return generate(algorithmName, DEFAULT_ALGORITHM_VERSION, source, salt, iterations, DEFAULT_MEMORY_KIB, DEFAULT_PARALLELISM, DEFAULT_OUTPUT_LENGTH_BITS); + return generate(algorithmName, DEFAULT_ALGORITHM_VERSION, source, salt, iterations, + DEFAULT_MEMORY_KIB, DEFAULT_PARALLELISM, DEFAULT_OUTPUT_LENGTH_BITS); } public static Argon2Hash generate( @@ -236,7 +245,7 @@ public static Argon2Hash generate( final Argon2BytesGenerator gen = new Argon2BytesGenerator(); gen.init(parameters); - final byte[] hash = new byte[outputLengthBits / 8]; + @SuppressWarnings("checkstyle:MagicNumber") final byte[] hash = new byte[outputLengthBits / 8]; gen.generateBytes(source.getBytes(), hash); return new Argon2Hash(algorithmName, argonVersion, hash, new SimpleByteSource(salt), iterations, memoryAsKB, parallelism); @@ -247,8 +256,8 @@ protected void checkValidAlgorithm() { if (!ALGORITHMS_ARGON2.contains(getAlgorithmName())) { final String message = String.format( Locale.ENGLISH, - "Given algorithm name [%s] not valid for argon2. " + - "Valid algorithms: [%s].", + "Given algorithm name [%s] not valid for argon2. " + + "Valid algorithms: [%s].", getAlgorithmName(), ALGORITHMS_ARGON2 ); @@ -276,6 +285,7 @@ public int getIterations() { @Override public boolean matchesPassword(ByteSource plaintextBytes) { try { + @SuppressWarnings("checkstyle:MagicNumber") Argon2Hash compare = generate( this.getAlgorithmName(), this.argonVersion, @@ -295,6 +305,7 @@ public boolean matchesPassword(ByteSource plaintextBytes) { } @Override + @SuppressWarnings("checkstyle:MagicNumber") public int getSaltLength() { return SALT_LENGTH_BITS / 8; } @@ -350,7 +361,8 @@ public boolean equals(Object other) { return false; } Argon2Hash that = (Argon2Hash) other; - return argonVersion == that.argonVersion && iterations == that.iterations && memoryKiB == that.memoryKiB && parallelism == that.parallelism; + return argonVersion == that.argonVersion && iterations == that.iterations + && memoryKiB == that.memoryKiB && parallelism == that.parallelism; } @Override diff --git a/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2HashProvider.java b/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2HashProvider.java index 2a8fdee40b..5f1266036c 100644 --- a/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2HashProvider.java +++ b/crypto/support/hashes/argon2/src/main/java/org/apache/shiro/crypto/support/hashes/argon2/Argon2HashProvider.java @@ -67,7 +67,7 @@ static class Argon2HashFactory implements HashSpi.HashFactory { private final SecureRandom random; - public Argon2HashFactory(Random random) { + Argon2HashFactory(Random random) { if (!(random instanceof SecureRandom)) { throw new IllegalArgumentException("Only SecureRandom instances are supported at the moment!"); } @@ -99,7 +99,8 @@ public Argon2Hash generate(HashRequest hashRequest) { .flatMap(algoV -> intOrEmpty(algoV, Parameters.PARAMETER_PARALLELISM)) .orElse(Parameters.DEFAULT_PARALLELISM); - final int outputLengthBits = Optional.ofNullable(hashRequest.getParameters().get(Parameters.PARAMETER_OUTPUT_LENGTH_BITS)) + final int outputLengthBits = Optional.ofNullable(hashRequest.getParameters() + .get(Parameters.PARAMETER_OUTPUT_LENGTH_BITS)) .flatMap(algoV -> intOrEmpty(algoV, Parameters.PARAMETER_OUTPUT_LENGTH_BITS)) .orElse(Parameters.DEFAULT_OUTPUT_LENGTH_BITS); @@ -123,6 +124,7 @@ private ByteSource parseSalt(HashRequest hashRequest) { .orElseGet(() -> Argon2Hash.createSalt(random)); } + @SuppressWarnings("checkstyle:MagicNumber") private Optional lengthValidOrEmpty(ByteSource bytes) { if (bytes.getBytes().length != 16) { return Optional.empty(); @@ -131,6 +133,7 @@ private Optional lengthValidOrEmpty(ByteSource bytes) { return Optional.of(bytes); } + @SuppressWarnings("checkstyle:MagicNumber") private Optional intOrEmpty(Object maybeInt, String parameterName) { try { return Optional.of(Integer.parseInt((String) maybeInt, 10)); @@ -157,11 +160,34 @@ private Optional intOrEmpty(Object maybeInt, String parameterName) { */ public static final class Parameters { + /** + * Default algorithm name. + */ public static final String DEFAULT_ALGORITHM_NAME = Argon2Hash.DEFAULT_ALGORITHM_NAME; + + /** + * Default algorithm version. + */ public static final int DEFAULT_ALGORITHM_VERSION = Argon2Hash.DEFAULT_ALGORITHM_VERSION; + + /** + * Default iterations. + */ public static final int DEFAULT_ITERATIONS = Argon2Hash.DEFAULT_ITERATIONS; + + /** + * Default memory kib. + */ public static final int DEFAULT_MEMORY_KIB = Argon2Hash.DEFAULT_MEMORY_KIB; + + /** + * Default parallelism number. + */ public static final int DEFAULT_PARALLELISM = Argon2Hash.DEFAULT_PARALLELISM; + + /** + * Default output length bits. + */ public static final int DEFAULT_OUTPUT_LENGTH_BITS = Argon2Hash.DEFAULT_OUTPUT_LENGTH_BITS; /** @@ -174,6 +200,10 @@ public static final class Parameters { *

    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 ALGORITHMS_BCRYPT = new HashSet<>(Arrays.asList("2", "2a", "2b", "2y")); private final int cost; private final int iterations; - public BCryptHash(final String version, final byte[] hashedData, final ByteSource salt, final int cost) { + BCryptHash(final String version, final byte[] hashedData, final ByteSource salt, final int cost) { super(version, hashedData, salt); this.cost = cost; this.iterations = (int) Math.pow(2, cost); @@ -69,8 +69,8 @@ protected final void checkValidAlgorithm() { if (!ALGORITHMS_BCRYPT.contains(getAlgorithmName())) { final String message = String.format( Locale.ENGLISH, - "Given algorithm name [%s] not valid for bcrypt. " + - "Valid algorithms: [%s].", + "Given algorithm name [%s] not valid for bcrypt. " + + "Valid algorithms: [%s].", getAlgorithmName(), ALGORITHMS_BCRYPT ); @@ -82,6 +82,7 @@ protected final void checkValidCost() { checkValidCost(this.cost); } + @SuppressWarnings("checkstyle:MagicNumber") public static int checkValidCost(final int cost) { if (cost < 4 || cost > 31) { final String message = String.format( @@ -179,7 +180,10 @@ public int getIterations() { @Override public boolean matchesPassword(ByteSource plaintextBytes) { try { - final String cryptString = OpenBSDBCrypt.generate(this.getAlgorithmName(), plaintextBytes.getBytes(), this.getSalt().getBytes(), this.getCost()); + final String cryptString = OpenBSDBCrypt.generate(this.getAlgorithmName(), + plaintextBytes.getBytes(), + this.getSalt().getBytes(), + this.getCost()); BCryptHash other = fromString(cryptString); return this.equals(other); diff --git a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptProvider.java b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptProvider.java index 74961564b3..6a31c432d8 100644 --- a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptProvider.java +++ b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/BCryptProvider.java @@ -61,7 +61,7 @@ static class BCryptHashFactory implements HashSpi.HashFactory { private final SecureRandom random; - public BCryptHashFactory(Random random) { + BCryptHashFactory(Random random) { if (!(random instanceof SecureRandom)) { throw new IllegalArgumentException("Only SecureRandom instances are supported at the moment!"); } @@ -96,6 +96,7 @@ private int getCost(HashRequest hashRequest) { String costStr = optCostStr.orElseThrow(NoSuchElementException::new); try { + @SuppressWarnings("checkstyle:MagicNumber") int cost = Integer.parseInt(costStr, 10); BCryptHash.checkValidCost(cost); return cost; @@ -132,9 +133,20 @@ private ByteSource getSalt(HashRequest hashRequest) { } public static final class Parameters { + + /** + * Set BCryptHash algorithm name to default. + */ public static final String DEFAULT_ALGORITHM_NAME = BCryptHash.DEFAULT_ALGORITHM_NAME; + /** + * BCrypt salt param. + */ public static final String PARAMETER_SALT = "BCrypt.salt"; + + /** + * BCrypt cost param. + */ public static final String PARAMETER_COST = "BCrypt.cost"; private Parameters() { diff --git a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/OpenBSDBase64.java b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/OpenBSDBase64.java index ad05fe853b..27199e1679 100644 --- a/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/OpenBSDBase64.java +++ b/crypto/support/hashes/bcrypt/src/main/java/org/apache/shiro/crypto/support/hashes/bcrypt/OpenBSDBase64.java @@ -28,12 +28,15 @@ * *
    * 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. --> - + org.apache.shiro diff --git a/event/src/main/java/org/apache/shiro/event/Event.java b/event/src/main/java/org/apache/shiro/event/Event.java index 9fecf8a516..ac5e5e5e76 100644 --- a/event/src/main/java/org/apache/shiro/event/Event.java +++ b/event/src/main/java/org/apache/shiro/event/Event.java @@ -27,7 +27,10 @@ */ public abstract class Event extends EventObject { - private final long timestamp; //millis since Epoch (UTC time zone). + /** + * millis since Epoch (UTC time zone). + */ + private final long timestamp; public Event(Object source) { super(source); diff --git a/event/src/main/java/org/apache/shiro/event/package-info.java b/event/src/main/java/org/apache/shiro/event/package-info.java new file mode 100644 index 0000000000..177e091ddc --- /dev/null +++ b/event/src/main/java/org/apache/shiro/event/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; diff --git a/event/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java b/event/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java index 9a4fe1d7a1..3ab39f9cd2 100644 --- a/event/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java +++ b/event/src/main/java/org/apache/shiro/event/support/AnnotationEventListenerResolver.java @@ -51,7 +51,7 @@ public AnnotationEventListenerResolver() { * * @param instance the instance to inspect for annotated event handler methods. * @return a new collection of {@link EventListener} instances, each instance corresponding to an annotated - * method discovered on the specified {@code instance} argument. + * method discovered on the specified {@code instance} argument. */ public List getEventListeners(Object instance) { if (instance == null) { @@ -77,7 +77,7 @@ public List getEventListeners(Object instance) { * defaults to {@link Subscribe}. * * @return the type of annotation that indicates a method that should be represented as an {@link EventListener}, - * defaults to {@link Subscribe}. + * defaults to {@link Subscribe}. */ public Class getAnnotationClass() { return annotationClass; diff --git a/event/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java b/event/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java index d4d5e8c1e6..b4f62459bf 100644 --- a/event/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java +++ b/event/src/main/java/org/apache/shiro/event/support/DefaultEventBus.java @@ -23,7 +23,6 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -62,22 +61,22 @@ * * After registering the component, when when an event of a respective type is published, the component's * {@code Subscribe}-annotated method(s) will be invoked as expected. - * + *

    * 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(); //not thread safe, so we need locks: + //not thread safe, so we need locks: + this.registry = new LinkedHashMap(); ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); this.registryReadLock = rwl.readLock(); this.registryWriteLock = rwl.writeLock(); @@ -120,7 +120,7 @@ public void setEventListenerResolver(EventListenerResolver eventListenerResolver public void publish(Object event) { if (event == null) { - log.info("Received null event for publishing. Ignoring and returning."); + LOGGER.info("Received null event for publishing. Ignoring and returning."); return; } @@ -149,7 +149,7 @@ public void publish(Object event) { public void register(Object instance) { if (instance == null) { - log.info("Received null instance for event listener registration. Ignoring registration request."); + LOGGER.info("Received null instance for event listener registration. Ignoring registration request."); return; } @@ -158,7 +158,7 @@ public void register(Object instance) { List listeners = getEventListenerResolver().getEventListeners(instance); if (listeners == null || listeners.isEmpty()) { - log.warn("Unable to resolve event listeners for subscriber instance [{}]. Ignoring registration request.", + LOGGER.warn("Unable to resolve event listeners for subscriber instance [{}]. Ignoring registration request.", instance); return; } @@ -185,13 +185,13 @@ public void unregister(Object instance) { } } - private class Subscription { + private static class Subscription { private final List listeners; - public Subscription(List listeners) { + Subscription(List listeners) { List toSort = new ArrayList(listeners); - Collections.sort(toSort, EVENT_LISTENER_COMPARATOR); + toSort.sort(EVENT_LISTENER_COMPARATOR); this.listeners = toSort; } @@ -209,7 +209,7 @@ public void onEvent(Object event) { try { listener.onEvent(event); } catch (Throwable t) { - log.warn(EVENT_LISTENER_ERROR_MSG, t); + LOGGER.warn(EVENT_LISTENER_ERROR_MSG, t); } delivered.add(target); } diff --git a/event/src/main/java/org/apache/shiro/event/support/EventClassComparator.java b/event/src/main/java/org/apache/shiro/event/support/EventClassComparator.java index 4a6ba71eb2..0fcbba3b4a 100644 --- a/event/src/main/java/org/apache/shiro/event/support/EventClassComparator.java +++ b/event/src/main/java/org/apache/shiro/event/support/EventClassComparator.java @@ -37,7 +37,7 @@ * @Subscribe * public void onEvent(B b) { ... } * - * + *

    * 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/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. --> - - 4.0.0 + + 4.0.0 - - org.apache.shiro.integrationtests - shiro-integration-tests - 2.0.0-SNAPSHOT - + + org.apache.shiro.integrationtests + shiro-integration-tests + 2.0.0-SNAPSHOT + - shiro-its-guice3 - Apache Shiro :: ITs :: Guice 3 - war + shiro-its-guice3 + Apache Shiro :: ITs :: Guice 3 + war - - 3.0 - + + 3.0 + - - - - org.eclipse.jetty - jetty-maven-plugin - - - + + + + org.eclipse.jetty + jetty-maven-plugin + + + - - - org.apache.taglibs - taglibs-standard-spec - compile - - - org.apache.taglibs - taglibs-standard-impl - compile - - - javax.servlet - javax.servlet-api - provided - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.shiro - shiro-core - - - org.apache.shiro - shiro-web - - - org.apache.shiro - shiro-guice - - - com.google.inject.extensions - guice-servlet - - - org.slf4j - jcl-over-slf4j - runtime - + + + org.apache.taglibs + taglibs-standard-spec + compile + + + org.apache.taglibs + taglibs-standard-impl + compile + + + javax.servlet + javax.servlet-api + provided + + + org.apache.logging.log4j + log4j-slf4j2-impl + runtime + + + org.apache.logging.log4j + log4j-core + runtime + + + org.apache.shiro + shiro-core + + + org.apache.shiro + shiro-web + + + org.apache.shiro + shiro-guice + + + com.google.inject.extensions + guice-servlet + + + org.slf4j + jcl-over-slf4j + runtime + - - org.apache.shiro - shiro-guice - ${project.version} - tests - test-jar - test - + + org.apache.shiro + shiro-guice + ${project.version} + tests + test-jar + test + org.htmlunit htmlunit @@ -120,32 +121,32 @@ org.apache.shiro.integrationtests shiro-its-support - test + test - + - - - jdk16 - - [16,) - - - - --illegal-access=permit - --illegal-access=permit - - - - jdk17 - - [17,) - - - - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.lang=ALL-UNNAMED - - - + + + jdk16 + + [16,) + + + + --illegal-access=permit + --illegal-access=permit + + + + jdk17 + + [17,) + + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED + + + diff --git a/integration-tests/guice3/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java b/integration-tests/guice3/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java index 9e6af33c12..6254a0d1db 100644 --- a/integration-tests/guice3/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java +++ b/integration-tests/guice3/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java @@ -68,23 +68,19 @@ Ini loadShiroIni() throws MalformedURLException { } @Override - protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) - { - try - { - String cipherKey = loadShiroIni().getSectionProperty( "main", "securityManager.rememberMeManager.cipherKey" ); + protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) { + try { + String cipherKey = loadShiroIni().getSectionProperty("main", "securityManager.rememberMeManager.cipherKey"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); CookieRememberMeManager rememberMeManager = new CookieRememberMeManager(); - rememberMeManager.setCipherKey( Base64.decode( cipherKey ) ); + rememberMeManager.setCipherKey(Base64.decode(cipherKey)); securityManager.setRememberMeManager(rememberMeManager); bind.toInstance(securityManager); - } - catch ( MalformedURLException e ) - { + } catch (MalformedURLException e) { // for now just throw, you could just call // super.bindWebSecurityManager(bind) if you do not need rememberMe functionality - throw new ConfigurationException( "securityManager.rememberMeManager.cipherKey must be set in shiro.ini." ); + throw new ConfigurationException("securityManager.rememberMeManager.cipherKey must be set in shiro.ini."); } diff --git a/integration-tests/guice3/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java b/integration-tests/guice3/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java index fe9d7a1502..550b9e2298 100644 --- a/integration-tests/guice3/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java +++ b/integration-tests/guice3/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java @@ -40,8 +40,7 @@ public void logOut() throws IOException { final HtmlPage homePage = webClient.getPage(getBaseUri()); try { homePage.getAnchorByHref("/logout").click(); - } - catch (ElementNotFoundException e) { + } catch (ElementNotFoundException e) { //Ignore } } diff --git a/integration-tests/guice4/pom.xml b/integration-tests/guice4/pom.xml index 51e27429a1..e3dc2e706f 100644 --- a/integration-tests/guice4/pom.xml +++ b/integration-tests/guice4/pom.xml @@ -17,93 +17,94 @@ ~ specific language governing permissions and limitations ~ under the License. --> - - 4.0.0 + + 4.0.0 - - org.apache.shiro.integrationtests - shiro-integration-tests - 2.0.0-SNAPSHOT - + + org.apache.shiro.integrationtests + shiro-integration-tests + 2.0.0-SNAPSHOT + - shiro-its-guice4 - Apache Shiro :: ITs :: Guice 4 - war + shiro-its-guice4 + Apache Shiro :: ITs :: Guice 4 + war - - - - org.eclipse.jetty - jetty-maven-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - org.apache.shiro:shiro-guice - - - - - + + + + org.eclipse.jetty + jetty-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.shiro:shiro-guice + + + + + - - - org.apache.taglibs - taglibs-standard-spec - compile - - - org.apache.taglibs - taglibs-standard-impl - compile - - - javax.servlet - javax.servlet-api - provided - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.shiro - shiro-core - - - org.apache.shiro - shiro-web - - - org.apache.shiro - shiro-guice - - - com.google.inject.extensions - guice-servlet - - - org.slf4j - jcl-over-slf4j - runtime - + + + org.apache.taglibs + taglibs-standard-spec + compile + + + org.apache.taglibs + taglibs-standard-impl + compile + + + javax.servlet + javax.servlet-api + provided + + + org.apache.logging.log4j + log4j-slf4j2-impl + runtime + + + org.apache.logging.log4j + log4j-core + runtime + + + org.apache.shiro + shiro-core + + + org.apache.shiro + shiro-web + + + org.apache.shiro + shiro-guice + + + com.google.inject.extensions + guice-servlet + + + org.slf4j + jcl-over-slf4j + runtime + - - org.apache.shiro - shiro-guice - ${project.version} - tests - test-jar - test - + + org.apache.shiro + shiro-guice + ${project.version} + tests + test-jar + test + org.htmlunit htmlunit @@ -127,30 +128,30 @@ shiro-its-support test - + - - - jdk16 - - [16,) - - - - --illegal-access=permit - --illegal-access=permit - - - - jdk17 - - [17,) - - - - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.lang=ALL-UNNAMED - - - + + + jdk16 + + [16,) + + + + --illegal-access=permit + --illegal-access=permit + + + + jdk17 + + [17,) + + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED + + + diff --git a/integration-tests/guice4/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java b/integration-tests/guice4/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java index 312a59326c..48c714fb8a 100644 --- a/integration-tests/guice4/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java +++ b/integration-tests/guice4/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java @@ -57,7 +57,10 @@ protected void configureShiroWeb() { this.addFilterChain("/logout", LOGOUT); this.addFilterChain("/account/**", AUTHC); - this.addFilterChain("/remoting/**", filterConfig(AUTHC), filterConfig(ROLES, "b2bClient"), filterConfig(PERMS, "remote:invoke:lan,wan")); + this.addFilterChain("/remoting/**", + filterConfig(AUTHC), + filterConfig(ROLES, "b2bClient"), + filterConfig(PERMS, "remote:invoke:lan,wan")); } @Provides @@ -68,23 +71,19 @@ Ini loadShiroIni() throws MalformedURLException { } @Override - protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) - { - try - { - String cipherKey = loadShiroIni().getSectionProperty( "main", "securityManager.rememberMeManager.cipherKey" ); + protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) { + try { + String cipherKey = loadShiroIni().getSectionProperty("main", "securityManager.rememberMeManager.cipherKey"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); CookieRememberMeManager rememberMeManager = new CookieRememberMeManager(); - rememberMeManager.setCipherKey( Base64.decode( cipherKey ) ); + rememberMeManager.setCipherKey(Base64.decode(cipherKey)); securityManager.setRememberMeManager(rememberMeManager); bind.toInstance(securityManager); - } - catch ( MalformedURLException e ) - { + } catch (MalformedURLException e) { // for now just throw, you could just call // super.bindWebSecurityManager(bind) if you do not need rememberMe functionality - throw new ConfigurationException( "securityManager.rememberMeManager.cipherKey must be set in shiro.ini." ); + throw new ConfigurationException("securityManager.rememberMeManager.cipherKey must be set in shiro.ini."); } diff --git a/integration-tests/guice4/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java b/integration-tests/guice4/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java index fe9d7a1502..550b9e2298 100644 --- a/integration-tests/guice4/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java +++ b/integration-tests/guice4/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java @@ -40,8 +40,7 @@ public void logOut() throws IOException { final HtmlPage homePage = webClient.getPage(getBaseUri()); try { homePage.getAnchorByHref("/logout").click(); - } - catch (ElementNotFoundException e) { + } catch (ElementNotFoundException e) { //Ignore } } diff --git a/integration-tests/jakarta-ee-support/pom.xml b/integration-tests/jakarta-ee-support/pom.xml index 228cc9a06e..c6c4f50b19 100644 --- a/integration-tests/jakarta-ee-support/pom.xml +++ b/integration-tests/jakarta-ee-support/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + 4.0.0 org.apache.shiro.integrationtests jakarta-ee-support diff --git a/integration-tests/jakarta-ee/pom.xml b/integration-tests/jakarta-ee/pom.xml index 197319c6e6..a69d693c8d 100644 --- a/integration-tests/jakarta-ee/pom.xml +++ b/integration-tests/jakarta-ee/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + 4.0.0 org.apache.shiro.integrationtests shiro-its-jakarta-ee @@ -392,7 +393,8 @@ pre-integration-test create-domain --nopassword --checkports=false - --portbase ${payara.portbase} ${domain.name} + --portbase ${payara.portbase} ${domain.name} + ${create-domain-skip} @@ -407,7 +409,8 @@ -i ${mac-backup-file} -e 's/jvm-options>\[17|/jvm-options>\[16|/g' -e 's/property name="HZ_LISTENER_PORT" value="5900/property name="HZ_LISTENER_PORT" value="5920/g' -e 's/hazelcast-runtime-configuration start-port="5900/hazelcast-runtime-configuration start-port="5920/g' - ${project.build.directory}/dependency/payara5/glassfish/domains/${domain.name}/config/domain.xml + ${project.build.directory}/dependency/payara5/glassfish/domains/${domain.name}/config/domain.xml + ${unix-sed-skip} @@ -443,7 +446,9 @@ payara-config-tmpdir pre-integration-test - -p ${payara.adminport} create-system-properties java.io.tmpdir=${project.build.directory}/payara_tmp + -p ${payara.adminport} create-system-properties + java.io.tmpdir=${project.build.directory}/payara_tmp + ${payara.restart.skip} @@ -476,10 +481,6 @@ - - org.apache.maven.plugins - maven-checkstyle-plugin - diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/CipherKeyGenerator.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/CipherKeyGenerator.java index 171810d3d0..a818d4744c 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/CipherKeyGenerator.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/CipherKeyGenerator.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.cdi; import javax.enterprise.context.ApplicationScoped; + import org.apache.shiro.cdi.annotations.CipherKeySupplier; @ApplicationScoped diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/ComponentInjectionBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/ComponentInjectionBean.java index 2add290c1b..b7d0144079 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/ComponentInjectionBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/cdi/ComponentInjectionBean.java @@ -15,6 +15,7 @@ import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; + import lombok.Getter; import org.apache.shiro.cdi.annotations.NoSessionCreation; import org.apache.shiro.cdi.annotations.Principal; @@ -22,6 +23,7 @@ import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.testing.jakarta.ee.PropertyPrincipal; + import java.util.function.Supplier; @ApplicationScoped diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/FormBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/FormBean.java index b1d52aefc8..7af3ae0180 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/FormBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/FormBean.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.jakarta.ee; import javax.enterprise.inject.Model; + import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -25,7 +26,8 @@ * form's backing bean */ @Model -@Getter @Setter +@Getter +@Setter @Slf4j public class FormBean { private String firstName; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyPrincipal.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyPrincipal.java index 9bbfc7543e..44563c4a34 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyPrincipal.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyPrincipal.java @@ -15,6 +15,7 @@ import java.io.Serializable; import javax.enterprise.inject.Vetoed; + import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyRealm.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyRealm.java index 32edd55b81..505f0480b5 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyRealm.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/PropertyRealm.java @@ -16,6 +16,7 @@ import java.util.Map; import javax.enterprise.context.ApplicationScoped; import javax.inject.Named; + import lombok.Getter; import lombok.Setter; import org.apache.shiro.authc.SimpleAccount; @@ -27,7 +28,8 @@ @Named @ApplicationScoped public class PropertyRealm extends IniRealm { - @Getter @Setter + @Getter + @Setter private IniRealm iniRealm; @Override diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedFacesViewScopedBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedFacesViewScopedBean.java index 543153c053..b424e38949 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedFacesViewScopedBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedFacesViewScopedBean.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.jakarta.ee; import static org.apache.shiro.testing.jakarta.ee.StatisticsResource.increment; + import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; @@ -21,6 +22,7 @@ import javax.faces.context.FacesContext; import javax.faces.view.ViewScoped; import javax.inject.Named; + import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresUser; @@ -49,6 +51,6 @@ void preDestroy() { public String hello() { return String.format("Hello from FacesViewScoped %s - %s", count, - FacesContext.class.getPackage().getImplementationVersion()); + FacesContext.class.getPackage().getImplementationVersion()); } } diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOmniViewScopedBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOmniViewScopedBean.java index c4721a351b..87daa8d1ad 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOmniViewScopedBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOmniViewScopedBean.java @@ -14,12 +14,14 @@ package org.apache.shiro.testing.jakarta.ee; import static org.apache.shiro.testing.jakarta.ee.StatisticsResource.increment; + import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.faces.context.FacesContext; import javax.inject.Named; + import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresUser; import org.omnifaces.cdi.ViewScoped; @@ -49,6 +51,6 @@ void preDestroy() { public String hello() { return String.format("Hello from OmniViewScoped %s - %s", count, - FacesContext.class.getPackage().getImplementationVersion()); + FacesContext.class.getPackage().getImplementationVersion()); } } diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOneMethod.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOneMethod.java index 21006e15d4..d12624edc7 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOneMethod.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedOneMethod.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.jakarta.ee; import javax.enterprise.context.RequestScoped; + import org.apache.shiro.authz.annotation.RequiresUser; /** diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedSessionScopedBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedSessionScopedBean.java index e07e2c187b..44715c6264 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedSessionScopedBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedSessionScopedBean.java @@ -14,12 +14,14 @@ package org.apache.shiro.testing.jakarta.ee; import static org.apache.shiro.testing.jakarta.ee.StatisticsResource.increment; + import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.SessionScoped; import javax.inject.Named; + import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authz.annotation.RequiresUser; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedStatelessBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedStatelessBean.java index be2227d593..1359005088 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedStatelessBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/ProtectedStatelessBean.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.jakarta.ee; import javax.ejb.Stateless; + import org.apache.shiro.authz.annotation.RequiresUser; /** diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/StatisticsResource.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/StatisticsResource.java index b30b2980a2..bd25d688a2 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/StatisticsResource.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/StatisticsResource.java @@ -22,6 +22,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; + import lombok.AccessLevel; import lombok.Getter; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UnprotectedFacade.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UnprotectedFacade.java index e7087a31c5..d9cfe3bcca 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UnprotectedFacade.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UnprotectedFacade.java @@ -14,15 +14,20 @@ package org.apache.shiro.testing.jakarta.ee; import static org.apache.shiro.ee.cdi.ShiroScopeContext.isWebContainerSessions; + import org.apache.shiro.ee.filters.Forms; + import java.util.Map; import javax.ejb.EJBException; import javax.enterprise.inject.Model; import javax.inject.Inject; + import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.UnauthenticatedException; + import static org.omnifaces.util.Exceptions.unwrap; + import org.omnifaces.util.Messages; /** diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UseFallback.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UseFallback.java index 305d45d0ef..5e438da4ea 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UseFallback.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/UseFallback.java @@ -15,7 +15,9 @@ import javax.enterprise.context.ApplicationScoped; import javax.inject.Named; + import org.apache.shiro.ee.filters.Forms.FallbackPredicate; + import javax.servlet.http.HttpServletRequest; /** diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/ExceptionServlet.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/ExceptionServlet.java index 61ee78b1f6..6e391b7948 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/ExceptionServlet.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/ExceptionServlet.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.jakarta.ee.servlets; import org.apache.shiro.testing.logcapture.LogCapture; + import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; @@ -23,6 +24,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import static javax.ws.rs.core.MediaType.TEXT_PLAIN; /** diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/LogoutServlet.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/LogoutServlet.java index 3eb1ddcaf4..cdce25d705 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/LogoutServlet.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jakarta/ee/servlets/LogoutServlet.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import org.apache.shiro.SecurityUtils; /** diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/JsonPojo.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/JsonPojo.java index 519ff99d1f..d68df31408 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/JsonPojo.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/JsonPojo.java @@ -14,6 +14,7 @@ package org.apache.shiro.testing.jaxrs; import java.io.Serializable; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -21,7 +22,8 @@ import lombok.Setter; @Builder -@Getter @Setter +@Getter +@Setter @NoArgsConstructor @AllArgsConstructor public class JsonPojo implements Serializable { diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/TestApplication.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/TestApplication.java index 96e2b3544d..9b6cdb6b7d 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/TestApplication.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/TestApplication.java @@ -20,6 +20,7 @@ import javax.enterprise.event.Observes; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; + import lombok.Getter; import org.apache.shiro.authc.SimpleAccount; import org.apache.shiro.mgt.DefaultSecurityManager; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiBean.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiBean.java index ccecad958d..3e934058e5 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiBean.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiBean.java @@ -15,6 +15,7 @@ import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; + import org.apache.shiro.authz.annotation.RequiresUser; import org.apache.shiro.subject.Subject; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiResource.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiResource.java index 795d3c2dd7..995450b4bf 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiResource.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/jaxrs/WhoamiResource.java @@ -19,9 +19,12 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; + import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; + import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.lang.ShiroException; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCapture.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCapture.java index e553b839e4..e082f27dc6 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCapture.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCapture.java @@ -20,6 +20,7 @@ import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.Logger; + import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCaptureSingleton.java b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCaptureSingleton.java index 01b175a870..bb2e4e7d3e 100644 --- a/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCaptureSingleton.java +++ b/integration-tests/jakarta-ee/src/main/java/org/apache/shiro/testing/logcapture/LogCaptureSingleton.java @@ -21,7 +21,8 @@ /** * Entry point for capturing logs and exceptions via servlet */ -@Singleton @Startup +@Singleton +@Startup @SuppressWarnings("MagicNumber") public class LogCaptureSingleton { @PostConstruct diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java index aaa55cef91..d0e5000f9c 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/cdi/ComponentInjectionIT.java @@ -14,10 +14,13 @@ package org.apache.shiro.testing.cdi; import javax.inject.Inject; + import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; + import static org.apache.shiro.ee.util.JakartaTransformer.jakartify; + import org.apache.shiro.testing.jakarta.ee.PropertyPrincipal; import org.apache.shiro.testing.jaxrs.NoIniJaxRsIT; import org.apache.shiro.testing.jaxrs.TestApplication; @@ -34,7 +37,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; + import java.util.Optional; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java index df70916e02..913c905c04 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/Deployments.java @@ -15,12 +15,16 @@ import static com.flowlogix.util.ShrinkWrapManipulator.Action; import static com.flowlogix.util.ShrinkWrapManipulator.getContextParamValue; + import java.util.List; + import org.apache.shiro.testing.cdi.ComponentInjectionIT; + import static org.apache.shiro.ee.util.JakartaTransformer.jakartify; import static org.apache.shiro.testing.cdi.ComponentInjectionIT.TESTABLE_MODE; import static org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_DEV_MODE; import static org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_PROD_MODE; + import org.eu.ingwar.tools.arquillian.extension.suite.annotations.ArquillianSuiteDeployment; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.shrinkwrap.api.spec.WebArchive; @@ -72,7 +76,7 @@ private static List initializeStandardActions() { + ",classpath:META-INF/shiro-native-sessions.ini"))); case SHIRO_EE_DISABLED: return List.of(new Action(getContextParamValue("org.apache.shiro.ee.disabled"), - node -> node.setTextContent("true"), true)); + node -> node.setTextContent("true"), true)); default: return List.of(); } diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java index aee6aa7fe2..bad6cc1587 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/FacesTagsIT.java @@ -14,16 +14,22 @@ package org.apache.shiro.testing.jakarta.ee; import java.net.URL; + import static org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_DEV_MODE; import static org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.createDeploymentDev; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.drone.api.annotation.Drone; + import static org.jboss.arquillian.graphene.Graphene.guardHttp; + import org.jboss.arquillian.junit5.ArquillianExtension; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; + import static org.junit.jupiter.api.Assertions.assertEquals; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -200,7 +206,7 @@ void hasAnyPermission() { void hasPermission() { login(); webDriver.get(baseURL + "shiro/unprotected/tags"); - assertEquals("Has Permission" , hasPermission.getText()); + assertEquals("Has Permission", hasPermission.getText()); } @Test @@ -208,7 +214,7 @@ void hasPermission() { void lacksPermissio() { login(); webDriver.get(baseURL + "shiro/unprotected/tags"); - assertEquals("Lacks Permission" , lacksPermission.getText()); + assertEquals("Lacks Permission", lacksPermission.getText()); } @Test @@ -216,7 +222,7 @@ void lacksPermissio() { void remembered() { login(); webDriver.get(baseURL + "shiro/unprotected/tags"); - assertEquals("" , remembered.getText()); + assertEquals("", remembered.getText()); } private void login() { diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java index f188e9d29a..85c3a58ba6 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroAuthFormsIT.java @@ -15,30 +15,38 @@ import com.flowlogix.util.ShrinkWrapManipulator; import com.flowlogix.util.ShrinkWrapManipulator.Action; + import static com.flowlogix.util.ShrinkWrapManipulator.getContextParamValue; import static org.apache.shiro.testing.jakarta.ee.Deployments.standardActions; import static org.apache.shiro.testing.jakarta.ee.Deployments.isClientStateSavingIntegrationTest; import static org.apache.shiro.testing.jakarta.ee.Deployments.isShiroNativeSessionsIntegrationTest; + import java.net.URL; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; + import static org.apache.shiro.ee.util.JakartaTransformer.jakartify; import static org.apache.shiro.web.servlet.ShiroHttpSession.DEFAULT_SESSION_ID_NAME; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.drone.api.annotation.Drone; + import static org.jboss.arquillian.graphene.Graphene.guardAjax; import static org.jboss.arquillian.graphene.Graphene.guardHttp; import static org.jboss.arquillian.graphene.Graphene.waitForHttp; import static org.jboss.arquillian.graphene.Graphene.waitGui; + import org.jboss.arquillian.junit5.ArquillianExtension; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.resolver.api.maven.archive.importer.MavenImporter; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java index 97625824f6..cd211377c7 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroBeansIT.java @@ -14,20 +14,26 @@ package org.apache.shiro.testing.jakarta.ee; import java.net.URL; + import static org.apache.shiro.ee.util.JakartaTransformer.isJakarta; import static org.apache.shiro.ee.util.JakartaTransformer.jakartify; import static org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_DEV_MODE; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.drone.api.annotation.Drone; + import static org.jboss.arquillian.graphene.Graphene.guardAjax; import static org.jboss.arquillian.graphene.Graphene.guardHttp; import static org.jboss.arquillian.graphene.Graphene.waitGui; + import org.jboss.arquillian.junit5.ArquillianExtension; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -117,7 +123,7 @@ void checkDontCallWhenNotAuth() { webDriver.get(baseURL + "lastException"); String exceptionText = webDriver.findElement(By.tagName("body")).getText(); assertTrue(exceptionText - .startsWith(jakartify("WARNING: javax.ejb.EJBException: Attempting to perform a user-only operation")), + .startsWith(jakartify("WARNING: javax.ejb.EJBException: Attempting to perform a user-only operation")), String.format("capturing correct warning from the server: %s", exceptionText)); } @@ -149,7 +155,7 @@ void beanDestroyCalled() { } private void exersizeViewAndSessionScoped(WebElement elem, String createStatistic, String destroyStatistic, - boolean isBrokenDestructor) { + boolean isBrokenDestructor) { webDriver.get(baseURL + "shiro/auth/loginform"); login(); diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java index b0af647cfa..b1898ab53b 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jakarta/ee/ShiroSSLFilterIT.java @@ -14,16 +14,21 @@ package org.apache.shiro.testing.jakarta.ee; import static com.flowlogix.util.ShrinkWrapManipulator.toHttpsURL; + import java.net.URL; + import static org.apache.shiro.testing.jakarta.ee.ShiroAuthFormsIT.DEPLOYMENT_PROD_MODE; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.drone.api.annotation.Drone; import org.jboss.arquillian.junit5.ArquillianExtension; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; + import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java index 48537d2b13..df56c074d5 100644 --- a/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java +++ b/integration-tests/jakarta-ee/src/test/java/org/apache/shiro/testing/jaxrs/NoIniJaxRsIT.java @@ -21,17 +21,22 @@ import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; + import lombok.Builder; import lombok.SneakyThrows; import org.apache.shiro.testing.cdi.ComponentInjectionIT; + import static org.apache.shiro.testing.cdi.ComponentInjectionIT.TESTABLE_MODE; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.junit5.ArquillianExtension; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/JaxRsApplication.java b/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/JaxRsApplication.java index 6a74dccc1a..4319cfdc81 100644 --- a/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/JaxRsApplication.java +++ b/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/JaxRsApplication.java @@ -25,6 +25,7 @@ /** * Simple JAX-RS {@link Application} that is implementation agnostic. + * * @since 2.0.0 */ @Dependent diff --git a/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/config/ShiroServletFilter.java b/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/config/ShiroServletFilter.java index 39b023c313..43f1a4c3c2 100644 --- a/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/config/ShiroServletFilter.java +++ b/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/config/ShiroServletFilter.java @@ -27,7 +27,10 @@ @WebFilter( asyncSupported = true, urlPatterns = {"/*"}, - dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR, DispatcherType.ASYNC} + dispatcherTypes = { + DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, + DispatcherType.ERROR, DispatcherType.ASYNC + } ) public class ShiroServletFilter extends org.apache.shiro.web.servlet.ShiroFilter { } diff --git a/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/dao/InMemoryStormtrooperDao.java b/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/dao/InMemoryStormtrooperDao.java index 25ad4b4400..e24161e546 100644 --- a/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/dao/InMemoryStormtrooperDao.java +++ b/integration-tests/jaxrs/app/src/main/java/org/apache/shiro/testing/jaxrs/app/dao/InMemoryStormtrooperDao.java @@ -36,6 +36,7 @@ import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +@SuppressWarnings("checkstyle:MagicNumber") @Dependent @Default public class InMemoryStormtrooperDao implements StormtrooperDao { @@ -61,7 +62,7 @@ public Collection listTroopers() { @Override public Optional getStormtrooper(StormtrooperId id) { - return Optional.ofNullable(TROOPERS.get(id)); + return Optional.ofNullable(TROOPERS.get(id)); } @Override @@ -87,6 +88,7 @@ public Stormtrooper updateStormtrooper(StormtrooperId id, Stormtrooper stormtroo @Override public boolean deleteStormtrooper(StormtrooperId id) { // TODO: implement - throw new UnsupportedOperationException("not yet implemented: [org.apache.shiro.testing.meecrowave.jaxrs.dao.InMemoryStormtrooperDao::deleteStormtrooper]."); + throw new UnsupportedOperationException("not yet implemented: " + + "[org.apache.shiro.testing.meecrowave.jaxrs.dao.InMemoryStormtrooperDao::deleteStormtrooper]."); } } diff --git a/integration-tests/jaxrs/meecrowave/src/test/java/org/apache/shiro/testing/jaxrs/meecrowave/MeecrowaveIT.java b/integration-tests/jaxrs/meecrowave/src/test/java/org/apache/shiro/testing/jaxrs/meecrowave/MeecrowaveIT.java index 21d7f51220..1c5a0e19f0 100644 --- a/integration-tests/jaxrs/meecrowave/src/test/java/org/apache/shiro/testing/jaxrs/meecrowave/MeecrowaveIT.java +++ b/integration-tests/jaxrs/meecrowave/src/test/java/org/apache/shiro/testing/jaxrs/meecrowave/MeecrowaveIT.java @@ -35,7 +35,7 @@ public class MeecrowaveIT extends AbstractShiroJaxRsIT { private Meecrowave.Builder config; @Override - protected URI getBaseUri() { + protected URI getBaseUri() { return URI.create("http://localhost:" + config.getHttpPort() + "/api"); } diff --git a/integration-tests/jaxrs/openliberty/pom.xml b/integration-tests/jaxrs/openliberty/pom.xml index 3aad63bb86..9ae48b4a96 100644 --- a/integration-tests/jaxrs/openliberty/pom.xml +++ b/integration-tests/jaxrs/openliberty/pom.xml @@ -138,8 +138,12 @@ [16,) - --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED - --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED --add-opens + java.base/java.net=ALL-UNNAMED + + --add-opens java.base/java.lang=ALL-UNNAMED --add-opens + java.base/java.net=ALL-UNNAMED + diff --git a/integration-tests/jaxrs/openliberty/src/test/java/org/apache/shiro/testing/jaxrs/openliberty/OpenLibertyIT.java b/integration-tests/jaxrs/openliberty/src/test/java/org/apache/shiro/testing/jaxrs/openliberty/OpenLibertyIT.java index 6b1f227414..061c3ed231 100644 --- a/integration-tests/jaxrs/openliberty/src/test/java/org/apache/shiro/testing/jaxrs/openliberty/OpenLibertyIT.java +++ b/integration-tests/jaxrs/openliberty/src/test/java/org/apache/shiro/testing/jaxrs/openliberty/OpenLibertyIT.java @@ -26,8 +26,10 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class OpenLibertyIT extends AbstractShiroJaxRsIT { + @Override protected URI getBaseUri() { - return URI.create("http://localhost:" + System.getProperty("http.port") + "/" + System.getProperty("app.context.root") + "/api"); + return URI.create("http://localhost:" + System.getProperty("http.port") + + "/" + System.getProperty("app.context.root") + "/api"); } } diff --git a/integration-tests/jaxrs/tests/src/main/java/org/apache/shiro/testing/jaxrs/tests/AbstractShiroJaxRsIT.java b/integration-tests/jaxrs/tests/src/main/java/org/apache/shiro/testing/jaxrs/tests/AbstractShiroJaxRsIT.java index ee0946aaf6..888074fd44 100644 --- a/integration-tests/jaxrs/tests/src/main/java/org/apache/shiro/testing/jaxrs/tests/AbstractShiroJaxRsIT.java +++ b/integration-tests/jaxrs/tests/src/main/java/org/apache/shiro/testing/jaxrs/tests/AbstractShiroJaxRsIT.java @@ -53,7 +53,7 @@ public void logOut() { @Test - public void testGetUsersUnauthenticated() { + public void testGetUsersUnauthenticated() { final WebTarget usersTarget = client.target(getBaseUri()).path("troopers"); final Response usersResponse = usersTarget.request(MediaType.APPLICATION_JSON_TYPE) .buildGet() @@ -61,6 +61,7 @@ public void testGetUsersUnauthenticated() { assertEquals(Status.UNAUTHORIZED.getStatusCode(), usersResponse.getStatus()); } + @SuppressWarnings({"checkstyle:MagicNumber"}) @Test public void testGetUsersBasicAuthenticated() { final WebTarget usersTarget = client.target(getBaseUri()).path("troopers"); @@ -72,7 +73,8 @@ public void testGetUsersBasicAuthenticated() { assertEquals(Status.OK.getStatusCode(), usersResponse.getStatus()); final Stormtrooper[] stormtroopers = usersResponse.readEntity(Stormtrooper[].class); assertEquals(50, stormtroopers.length); - Arrays.stream(stormtroopers).forEach(stormtrooper -> assertTrue(stormtrooper.getStormtrooperId().getValue().startsWith("u"))); + Arrays.stream(stormtroopers).forEach(stormtrooper + -> assertTrue(stormtrooper.getStormtrooperId().getValue().startsWith("u"))); } } diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index df8bce4ced..63447d91ba 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + 4.0.0 diff --git a/integration-tests/support/pom.xml b/integration-tests/support/pom.xml index d9085c6812..f843c4557b 100644 --- a/integration-tests/support/pom.xml +++ b/integration-tests/support/pom.xml @@ -17,37 +17,38 @@ ~ specific language governing permissions and limitations ~ under the License. --> - - 4.0.0 + + 4.0.0 - - org.apache.shiro.integrationtests - shiro-integration-tests - 2.0.0-SNAPSHOT - + + org.apache.shiro.integrationtests + shiro-integration-tests + 2.0.0-SNAPSHOT + - shiro-its-support - Apache Shiro :: ITs :: Support + shiro-its-support + Apache Shiro :: ITs :: Support its.support - - + + org.apache.taglibs taglibs-standard-spec compile - - + + org.apache.taglibs taglibs-standard-impl compile - - - javax.servlet - javax.servlet-api - provided - + + + javax.servlet + javax.servlet-api + provided + org.apache.logging.log4j log4j-slf4j2-impl @@ -59,11 +60,11 @@ runtime - - org.slf4j - jcl-over-slf4j - runtime - + + org.slf4j + jcl-over-slf4j + runtime + org.htmlunit @@ -123,15 +124,15 @@ compile - - - org.apache.shiro - shiro-core - + + + org.apache.shiro + shiro-core + - + diff --git a/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java b/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java index b76a06dd4b..37e44edf7a 100644 --- a/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java +++ b/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java @@ -59,17 +59,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +@SuppressWarnings("checkstyle:ClassDataAbstractionCoupling") public abstract class AbstractContainerIT { + protected static final File TEST_KEYSTORE_PATH = setupKeyStore(); + protected static final String TEST_KEYSTORE_PASSWORD = "password"; + protected static EmbeddedJetty jetty; protected static int tlsPort; protected final WebClient webClient = new WebClient(); - protected static final File TEST_KEYSTORE_PATH = setupKeyStore(); - protected static final String TEST_KEYSTORE_PASSWORD = "password"; - + @SuppressWarnings("checkstyle:AnonInnerLength") @BeforeAll public static void startContainer() throws Exception { @@ -81,8 +83,9 @@ public static void startContainer() throws Exception { /** * Overriding with contents of this pull request, to make fragment scanning work. - * https://github.com/mjeanroy/junit-servers/pull/3 + * */ + @SuppressWarnings("checkstyle:LineLength") protected WebAppContext createdWebAppContext() throws Exception { final String path = configuration.getPath(); final String webapp = configuration.getWebapp(); @@ -95,7 +98,7 @@ protected WebAppContext createdWebAppContext() throws Exception { // Useful for WebXmlConfiguration ctx.setBaseResource(newResource(webapp)); - ctx.setConfigurations(new Configuration[]{ + ctx.setConfigurations(new Configuration[] { new WebInfConfiguration(), new WebXmlConfiguration(), new AnnotationConfiguration(), @@ -169,12 +172,14 @@ public boolean accept(File dir, String name) { } }); + assert warFiles != null; assertEquals(1, warFiles.length, "Expected only one war file in target directory, run 'mvn clean' and try again"); return warFiles[0].getAbsolutePath().replaceFirst("\\.war$", ""); } - protected static String getBasicAuthorizationHeaderValue(String username, String password) throws UnsupportedEncodingException { + protected static String getBasicAuthorizationHeaderValue(String username, String password) + throws UnsupportedEncodingException { String authorizationHeader = username + ":" + password; byte[] valueBytes; valueBytes = authorizationHeader.getBytes("UTF-8"); diff --git a/lang/pom.xml b/lang/pom.xml index e6729bce46..dc6d6c58bf 100644 --- a/lang/pom.xml +++ b/lang/pom.xml @@ -18,7 +18,8 @@ ~ under the License. --> - + org.apache.shiro @@ -31,7 +32,7 @@ Apache Shiro :: Lang The lang module encapsulates only language-specific utilities that are used by various - other modules. It exists to augment what we would have liked to see in the JDK but does not exist. + other modules. It exists to augment what we would have liked to see in the JDK but does not exist. bundle diff --git a/lang/src/main/java/org/apache/shiro/lang/codec/Base64.java b/lang/src/main/java/org/apache/shiro/lang/codec/Base64.java index 7738259ffb..2b3047f5c5 100644 --- a/lang/src/main/java/org/apache/shiro/lang/codec/Base64.java +++ b/lang/src/main/java/org/apache/shiro/lang/codec/Base64.java @@ -30,13 +30,16 @@ * great work they've done, but also didn't want to force every Shiro user to depend on the commons-codec.jar *

    * As per the Apache 2.0 license, the original copyright notice and all author and copyright information have - * remained in tact. + * remained intact. * * @see Wikipedia: Base 64 * @see RFC 2045 * @since 0.9 */ -public class Base64 { +public final class Base64 { + + private Base64() { + } /** * Base64 encodes the specified byte array and then encodes it as a String using Shiro's preferred character diff --git a/lang/src/main/java/org/apache/shiro/lang/codec/CodecSupport.java b/lang/src/main/java/org/apache/shiro/lang/codec/CodecSupport.java index d7fd0c8837..becf3ce9c0 100644 --- a/lang/src/main/java/org/apache/shiro/lang/codec/CodecSupport.java +++ b/lang/src/main/java/org/apache/shiro/lang/codec/CodecSupport.java @@ -33,6 +33,7 @@ * * @since 0.9 */ +@SuppressWarnings("checkstyle:BooleanExpressionComplexity") public abstract class CodecSupport { /** @@ -43,7 +44,7 @@ public abstract class CodecSupport { /** * Converts the specified character array to a byte array using the Shiro's preferred encoding (UTF-8). *

    - * 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 {@link CodecSupport#PREFERRED_ENCODING PREFERRED_ENCODING}, i.e. *

    * 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 the type of target. * @since 0.9 */ public class DefaultSerializer implements Serializer { @@ -50,9 +57,9 @@ public byte[] serialize(T o) throws SerializationException { baos.flush(); return baos.toByteArray(); } catch (IOException e) { - String msg = "Unable to serialize object [" + o + "]. " + - "In order for the DefaultSerializer to serialize this object, the [" + o.getClass().getName() + "] " + - "class must implement java.io.Serializable."; + String msg = "Unable to serialize object [" + o + "]. " + + "In order for the DefaultSerializer to serialize this object, " + + " the [" + o.getClass().getName() + "] class must implement java.io.Serializable."; throw new SerializationException(msg, e); } } diff --git a/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java b/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java index 174f489228..85937e5a4f 100644 --- a/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java +++ b/lang/src/main/java/org/apache/shiro/lang/io/ResourceUtils.java @@ -33,7 +33,7 @@ * @see #getInputStreamForPath(String) * @since 0.2 */ -public class ResourceUtils { +public final class ResourceUtils { /** * Resource path prefix that specifies to load from a classpath location, value is {@code classpath:} @@ -51,7 +51,7 @@ public class ResourceUtils { /** * Private internal log instance. */ - private static final Logger log = LoggerFactory.getLogger(ResourceUtils.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ResourceUtils.class); /** * Prevent instantiation. @@ -66,15 +66,14 @@ private ResourceUtils() { * * @param resourcePath the resource path to check * @return {@code true} if the resource path is not null and starts with one of the recognized - * resource prefixes, {@code false} otherwise. + * resource prefixes, {@code false} otherwise. * @since 0.9 */ @SuppressWarnings({"UnusedDeclaration"}) public static boolean hasResourcePrefix(String resourcePath) { - return resourcePath != null && - (resourcePath.startsWith(CLASSPATH_PREFIX) || - resourcePath.startsWith(URL_PREFIX) || - resourcePath.startsWith(FILE_PREFIX)); + return resourcePath != null + && (resourcePath.startsWith(CLASSPATH_PREFIX) + || resourcePath.startsWith(URL_PREFIX) || resourcePath.startsWith(FILE_PREFIX)); } /** @@ -143,20 +142,20 @@ public static InputStream getInputStreamForPath(String resourcePath) throws IOEx } private static InputStream loadFromFile(String path) throws IOException { - if (log.isDebugEnabled()) { - log.debug("Opening file [" + path + "]..."); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Opening file [" + path + "]..."); } return new FileInputStream(path); } private static InputStream loadFromUrl(String urlPath) throws IOException { - log.debug("Opening url {}", urlPath); + LOGGER.debug("Opening url {}", urlPath); URL url = new URL(urlPath); return url.openStream(); } private static InputStream loadFromClassPath(String path) { - log.debug("Opening resource from class path [{}]", path); + LOGGER.debug("Opening resource from class path [{}]", path); return ClassUtils.getResourceAsStream(path); } @@ -176,7 +175,7 @@ public static void close(InputStream is) { try { is.close(); } catch (IOException e) { - log.warn("Error closing input stream.", e); + LOGGER.warn("Error closing input stream.", e); } } } diff --git a/lang/src/main/java/org/apache/shiro/lang/io/SerializationException.java b/lang/src/main/java/org/apache/shiro/lang/io/SerializationException.java index a10a254450..5292d74791 100644 --- a/lang/src/main/java/org/apache/shiro/lang/io/SerializationException.java +++ b/lang/src/main/java/org/apache/shiro/lang/io/SerializationException.java @@ -26,8 +26,7 @@ * * @since Apr 23, 2008 8:58:22 AM */ -public class SerializationException extends ShiroException -{ +public class SerializationException extends ShiroException { /** * Creates a new SerializationException. diff --git a/lang/src/main/java/org/apache/shiro/lang/io/XmlSerializer.java b/lang/src/main/java/org/apache/shiro/lang/io/XmlSerializer.java index 8e31716488..4788c63821 100644 --- a/lang/src/main/java/org/apache/shiro/lang/io/XmlSerializer.java +++ b/lang/src/main/java/org/apache/shiro/lang/io/XmlSerializer.java @@ -42,6 +42,7 @@ public class XmlSerializer implements Serializer { * Serializes the specified 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");
    - * + *

    * Mainly for internal use within the framework; consider Jakarta's Commons Lang * >= 2.0 for a more comprehensive suite of assertion utilities. *

    @@ -58,8 +58,9 @@ public abstract class Assert { * Assert a boolean expression, throwing 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) { *

    Call {@link #isTrue(boolean)} if you wish to * throw {@link IllegalArgumentException} on an assertion failure. *

    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 HashMap> primClasses + private static final HashMap> PRIM_CLASSES = new HashMap<>(8, 1.0F); + static { - primClasses.put("boolean", boolean.class); - primClasses.put("byte", byte.class); - primClasses.put("char", char.class); - primClasses.put("short", short.class); - primClasses.put("int", int.class); - primClasses.put("long", long.class); - primClasses.put("float", float.class); - primClasses.put("double", double.class); - primClasses.put("void", void.class); + PRIM_CLASSES.put("boolean", boolean.class); + PRIM_CLASSES.put("byte", byte.class); + PRIM_CLASSES.put("char", char.class); + PRIM_CLASSES.put("short", short.class); + PRIM_CLASSES.put("int", int.class); + PRIM_CLASSES.put("long", long.class); + PRIM_CLASSES.put("float", float.class); + PRIM_CLASSES.put("double", double.class); + PRIM_CLASSES.put("void", void.class); } - /** * @since 1.0 */ @@ -94,6 +92,10 @@ protected ClassLoader doGetClassLoader() throws Throwable { } }; + private ClassUtils() { + + } + /** * Returns the specified resource by checking the current thread's * {@link Thread#getContextClassLoader() context class loader}, then the @@ -103,7 +105,7 @@ protected ClassLoader doGetClassLoader() throws Throwable { * * @param name the name of the resource to acquire from the classloader(s). * @return the InputStream of the resource found, or null 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 List getAnnotatedMethods(final Class type, final Class< /** * @since 1.0 */ - private static interface ClassLoaderAccessor { + private interface ClassLoaderAccessor { Class loadClass(String fqcn); + InputStream getResourceStream(String name); } /** * @since 1.0 */ - private static abstract class ExceptionIgnoringAccessor implements ClassLoaderAccessor { + private abstract static class ExceptionIgnoringAccessor implements ClassLoaderAccessor { public Class loadClass(String fqcn) { Class clazz = null; @@ -280,8 +282,8 @@ public Class loadClass(String fqcn) { //SHIRO-767: Use Class.forName instead of cl.loadClass(), as byte arrays would fail otherwise. clazz = Class.forName(fqcn, false, cl); } catch (ClassNotFoundException e) { - if (log.isTraceEnabled()) { - log.trace("Unable to load clazz named [" + fqcn + "] from class loader [" + cl + "]"); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Unable to load clazz named [" + fqcn + "] from class loader [" + cl + "]"); } } } @@ -301,8 +303,8 @@ protected final ClassLoader getClassLoader() { try { return doGetClassLoader(); } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug("Unable to acquire ClassLoader.", t); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Unable to acquire ClassLoader.", t); } } return null; diff --git a/lang/src/main/java/org/apache/shiro/lang/util/Initializable.java b/lang/src/main/java/org/apache/shiro/lang/util/Initializable.java index 37add6f642..07acd0ed1f 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/Initializable.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/Initializable.java @@ -30,8 +30,7 @@ public interface Initializable { /** * Initializes this object. * - * @throws ShiroException - * if an exception occurs during initialization. + * @throws ShiroException if an exception occurs during initialization. */ void init() throws ShiroException; diff --git a/lang/src/main/java/org/apache/shiro/lang/util/LifecycleUtils.java b/lang/src/main/java/org/apache/shiro/lang/util/LifecycleUtils.java index 9d78646b9e..2a57e32735 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/LifecycleUtils.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/LifecycleUtils.java @@ -33,7 +33,7 @@ */ public abstract class LifecycleUtils { - private static final Logger log = LoggerFactory.getLogger(LifecycleUtils.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtils.class); public static void init(Object o) throws ShiroException { if (o instanceof Initializable) { @@ -66,7 +66,7 @@ public static void destroy(Object o) { if (o instanceof Destroyable) { destroy((Destroyable) o); } else if (o instanceof Collection) { - destroy((Collection)o); + destroy((Collection) o); } } @@ -75,9 +75,9 @@ public static void destroy(Destroyable d) { try { d.destroy(); } catch (Throwable t) { - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { String msg = "Unable to cleanly destroy instance [" + d + "] of type [" + d.getClass().getName() + "]."; - log.debug(msg, t); + LOGGER.debug(msg, t); } } } diff --git a/lang/src/main/java/org/apache/shiro/lang/util/Nameable.java b/lang/src/main/java/org/apache/shiro/lang/util/Nameable.java index b645b4a89a..0d6e902c98 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/Nameable.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/Nameable.java @@ -29,6 +29,7 @@ public interface Nameable { /** * Sets the (preferably application unique) name for this component. + * * @param name the preferably application unique name for this component. */ void setName(String name); diff --git a/lang/src/main/java/org/apache/shiro/lang/util/SimpleByteSource.java b/lang/src/main/java/org/apache/shiro/lang/util/SimpleByteSource.java index dbb8d3d3c1..e7351d074e 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/SimpleByteSource.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/SimpleByteSource.java @@ -44,6 +44,7 @@ * * @since 1.0 */ +@SuppressWarnings("checkstyle:BooleanExpressionComplexity") public class SimpleByteSource implements ByteSource { private final byte[] bytes; @@ -122,16 +123,16 @@ public SimpleByteSource(InputStream stream) { * * @param o the object to test to see if it can be easily converted to bytes by instances of this class. * @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.2 */ public static boolean isCompatible(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; } public static ByteSource empty() { - return new SimpleByteSource(new byte[]{}); + return new SimpleByteSource(new byte[] {}); } @Override @@ -146,7 +147,7 @@ public boolean isEmpty() { @Override public String toHex() { - if ( this.cachedHex == null ) { + if (this.cachedHex == null) { this.cachedHex = Hex.encodeToString(getBytes()); } return this.cachedHex; @@ -154,7 +155,7 @@ public String toHex() { @Override public String toBase64() { - if ( this.cachedBase64 == null ) { + if (this.cachedBase64 == null) { this.cachedBase64 = Base64.encodeToString(getBytes()); } return this.cachedBase64; diff --git a/lang/src/main/java/org/apache/shiro/lang/util/SoftHashMap.java b/lang/src/main/java/org/apache/shiro/lang/util/SoftHashMap.java index cf20c7d409..47145e5c95 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/SoftHashMap.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/SoftHashMap.java @@ -20,7 +20,14 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; -import java.util.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.ReentrantLock; @@ -29,7 +36,7 @@ /** * A SoftHashMap 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 K + * @param V * @since 1.0 */ public class SoftHashMap implements Map { @@ -60,12 +69,13 @@ public class SoftHashMap implements Map { * The number of strong references to hold internally, that is, the number of instances to prevent * from being garbage collected automatically (unlike other soft references). */ - private final int RETENTION_SIZE; + private final int retentionSize; /** * The FIFO list of strong references (not to be garbage collected), order of last access. */ - private final Queue strongReferences; //guarded by 'strongReferencesLock' + //guarded by 'strongReferencesLock' + private final Queue strongReferences; private final ReentrantLock strongReferencesLock; /** @@ -101,7 +111,7 @@ public SoftHashMap() { @SuppressWarnings({"unchecked"}) public SoftHashMap(int retentionSize) { super(); - RETENTION_SIZE = Math.max(0, retentionSize); + this.retentionSize = Math.max(0, retentionSize); queue = new ReferenceQueue(); strongReferencesLock = new ReentrantLock(); map = new ConcurrentHashMap>(); @@ -113,7 +123,7 @@ public SoftHashMap(int retentionSize) { * size of {@link #DEFAULT_RETENTION_SIZE DEFAULT_RETENTION_SIZE} (100 entries). * * @param source the backing map to populate this {@code SoftHashMap} - * @see #SoftHashMap(Map,int) + * @see #SoftHashMap(java.util.Map, int) */ public SoftHashMap(Map source) { this(DEFAULT_RETENTION_SIZE); @@ -177,7 +187,7 @@ private void addToStrongReferences(V result) { private void trimStrongReferencesIfNecessary() { //trim the strong ref queue if necessary: - while (strongReferences.size() > RETENTION_SIZE) { + while (strongReferences.size() > retentionSize) { strongReferences.poll(); } } @@ -186,11 +196,12 @@ private void trimStrongReferencesIfNecessary() { * Traverses the ReferenceQueue and removes garbage-collected SoftValue objects from the backing map * by looking them up using the SoftValue.key data member. */ + @SuppressWarnings({"unchecked", "SuspiciousMethodCalls"}) private void processQueue() { SoftValue sv; while ((sv = (SoftValue) queue.poll()) != null) { - //noinspection SuspiciousMethodCalls - map.remove(sv.key); // we can access private data! + // we can access private data! + map.remove(sv.key); } } @@ -229,7 +240,6 @@ public Collection values() { processQueue(); Collection keys = map.keySet(); if (keys.isEmpty()) { - //noinspection unchecked return Collections.EMPTY_SET; } Collection values = new ArrayList(keys.size()); @@ -246,7 +256,8 @@ public Collection values() { * Creates a new entry, but wraps the value in a SoftValue instance to enable auto garbage collection. */ public V put(K key, V value) { - processQueue(); // throw out garbage collected values first + // throw out garbage collected values first + processQueue(); SoftValue sv = new SoftValue(value, key, queue); SoftValue previous = map.put(key, sv); addToStrongReferences(value); @@ -254,7 +265,8 @@ public V put(K key, V value) { } public V remove(Object key) { - processQueue(); // throw out garbage collected values first + // throw out garbage collected values first + processQueue(); SoftValue raw = map.remove(key); return raw != null ? raw.get() : null; } @@ -266,17 +278,20 @@ public void clear() { } finally { strongReferencesLock.unlock(); } - processQueue(); // throw out garbage collected values + // throw out garbage collected values + processQueue(); map.clear(); } public int size() { - processQueue(); // throw out garbage collected values first + // throw out garbage collected values first + processQueue(); return map.size(); } public Set> entrySet() { - processQueue(); // throw out garbage collected values first + // throw out garbage collected values first + processQueue(); Collection keys = map.keySet(); if (keys.isEmpty()) { //noinspection unchecked @@ -298,7 +313,7 @@ public Set> entrySet() { * not only the value but also the key to make it easier to find * the entry in the HashMap after it's been garbage collected. */ - private static class SoftValue extends SoftReference { + private static final class SoftValue extends SoftReference { private final K key; diff --git a/lang/src/main/java/org/apache/shiro/lang/util/StringUtils.java b/lang/src/main/java/org/apache/shiro/lang/util/StringUtils.java index b748d32625..fb444958fc 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/StringUtils.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/StringUtils.java @@ -19,7 +19,15 @@ package org.apache.shiro.lang.util; import java.text.ParseException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; + /** *

    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 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. - * + * *

    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}.

    - * + * * @param line the line to split using the {@link #DEFAULT_DELIMITER_CHAR}. * @return the split line, split tokens do not contain quotes and are trimmed. * @see #split(String, char, char, char, boolean, boolean) @@ -356,7 +366,8 @@ public static String[] split(String line, char delimiter, char beginQuoteChar, c *

    * This method's implementation is very loosely based (with significant modifications) on * Glen Smith's open-source - * CSVReader.java + * CSVReader.java * file. *

    * That file is Apache 2.0 licensed as well, making Glen's code a great starting point for us to modify to @@ -387,9 +398,12 @@ public static String[] split(String aLine, char delimiter, char beginQuoteChar, if (c == beginQuoteChar) { // this gets complex... the quote may end a quoted block, or escape another quote. // do a 1-char lookahead: - if (inQuotes // we are in quotes, therefore there can be escaped quotes in here. - && line.length() > (i + 1) // there is indeed another character to check. - && line.charAt(i + 1) == beginQuoteChar) { // ..and that char. is a quote also. + // we are in quotes, therefore there can be escaped quotes in here. + if (inQuotes + // there is indeed another character to check. + && line.length() > (i + 1) + // ..and that char. is a quote also. + && line.charAt(i + 1) == beginQuoteChar) { // we have two quote chars in a row == one quote char, so consume them both and // put one on the token. we do *not* exit the quoted text. sb.append(line.charAt(i + 1)); @@ -411,7 +425,8 @@ public static String[] split(String aLine, char delimiter, char beginQuoteChar, s = s.trim(); } tokens.add(s); - sb = new StringBuilder(); // start work on next token + // start work on next token + sb = new StringBuilder(); } else { sb.append(c); } @@ -454,7 +469,9 @@ public static String join(Iterator iterator, String separator) { } // two or more elements - StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small + // Java default is 16, probably too small + @SuppressWarnings("checkstyle:MagicNumber") + StringBuilder buf = new StringBuilder(256); if (first != null) { buf.append(first); } @@ -492,6 +509,7 @@ public static Set splitToSet(String delimited, String separator) { /** * Returns the input argument, but ensures the first character is capitalized (if possible). + * * @param in the string to uppercase the first character. * @return the input argument, but with the first character capitalized (if possible). * @since 1.2 diff --git a/lang/src/main/java/org/apache/shiro/lang/util/UnknownClassException.java b/lang/src/main/java/org/apache/shiro/lang/util/UnknownClassException.java index b7891e1188..881d3765dc 100644 --- a/lang/src/main/java/org/apache/shiro/lang/util/UnknownClassException.java +++ b/lang/src/main/java/org/apache/shiro/lang/util/UnknownClassException.java @@ -27,8 +27,7 @@ * * @since 0.1 */ -public class UnknownClassException extends ShiroException -{ +public class UnknownClassException extends ShiroException { /** * Creates a new UnknownClassException. diff --git a/lang/src/main/java/org/apache/shiro/lang/util/package-info.java b/lang/src/main/java/org/apache/shiro/lang/util/package-info.java new file mode 100644 index 0000000000..9d31257920 --- /dev/null +++ b/lang/src/main/java/org/apache/shiro/lang/util/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.util package-info. + */ +package org.apache.shiro.lang.util; diff --git a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java index 497e58eb08..04883a47b4 100644 --- a/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java +++ b/lang/src/test/java/org/apache/shiro/lang/util/ClassUtilsTest.java @@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; - class ClassUtilsTest { @Test diff --git a/pom.xml b/pom.xml index b1e0e6c89e..355ada4974 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + 4.0.0 @@ -327,7 +328,7 @@ org.apache.rat apache-rat-plugin - + **/.externalToolBuilders/* **/infinitest.filters @@ -482,7 +483,8 @@ jakarta false - + @@ -546,6 +548,7 @@ true true true + test-keystore.jks,test-keystore.pem root.dir=${root.dir} @@ -600,6 +603,9 @@ + + maven-checkstyle-plugin + org.apache.maven.plugins maven-compiler-plugin @@ -1546,7 +1552,7 @@ false - + **/.externalToolBuilders/* **/infinitest.filters @@ -1810,18 +1816,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -1847,8 +1853,8 @@ - + apache.snapshots diff --git a/samples/aspectj/pom.xml b/samples/aspectj/pom.xml index af9b9218bc..5387eb5144 100644 --- a/samples/aspectj/pom.xml +++ b/samples/aspectj/pom.xml @@ -18,79 +18,80 @@ ~ under the License. --> - + - + org.apache.shiro.samples shiro-samples 2.0.0-SNAPSHOT - + - 4.0.0 - samples-aspectj - Apache Shiro :: Samples :: AspectJ - - samples.aspectj - + 4.0.0 + samples-aspectj + Apache Shiro :: Samples :: AspectJ + + samples.aspectj + - - - - org.codehaus.mojo - aspectj-maven-plugin - - - - org.apache.shiro - shiro-aspectj - - - - - - aspectj-compile - - compile - test-compile - - - - - - org.aspectj - aspectjtools - ${aspectj.version} - - - - - + + + + org.codehaus.mojo + aspectj-maven-plugin + + + + org.apache.shiro + shiro-aspectj + + + + + + aspectj-compile + + compile + test-compile + + + + + + org.aspectj + aspectjtools + ${aspectj.version} + + + + + - - - org.apache.shiro - shiro-aspectj - - - org.apache.commons - commons-lang3 - ${commons.lang3.version} - - - org.slf4j - jcl-over-slf4j - runtime - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - + + + org.apache.shiro + shiro-aspectj + + + org.apache.commons + commons-lang3 + ${commons.lang3.version} + + + org.slf4j + jcl-over-slf4j + runtime + + + org.apache.logging.log4j + log4j-slf4j2-impl + runtime + + + org.apache.logging.log4j + log4j-core + runtime + + diff --git a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/Account.java b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/Account.java index 6c7bbfa85b..c58dce8cc4 100644 --- a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/Account.java +++ b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/Account.java @@ -29,30 +29,30 @@ public class Account { - private static long _SEQUENCE; + private static long sequence; - private long _id; + private long id; - private String _ownerName; + private String ownerName; - private volatile boolean _isActive; + private volatile boolean isActive; - private double _balance; + private double balance; - private final List _transactions; + private final List transactionList; - private String _createdBy; + private String createdBy; - private Date _creationDate; + private Date creationDate; public Account(String anOwnerName) { - _id = ++_SEQUENCE; - _ownerName = anOwnerName; - _isActive = true; - _balance = 0.0d; - _transactions = new ArrayList(); - _createdBy = "unknown"; - _creationDate = new Date(); + id = ++sequence; + ownerName = anOwnerName; + isActive = true; + balance = 0.0d; + transactionList = new ArrayList(); + createdBy = "unknown"; + creationDate = new Date(); } /** @@ -61,7 +61,7 @@ public Account(String anOwnerName) { * @return The id value. */ public long getId() { - return _id; + return id; } /** @@ -70,7 +70,7 @@ public long getId() { * @return The ownerName value. */ public String getOwnerName() { - return _ownerName; + return ownerName; } /** @@ -79,7 +79,7 @@ public String getOwnerName() { * @return The isActive value. */ public boolean isActive() { - return _isActive; + return isActive; } /** @@ -88,7 +88,7 @@ public boolean isActive() { * @param aIsActive The new value of the isActive attribute. */ public void setActive(boolean aIsActive) { - _isActive = aIsActive; + isActive = aIsActive; } /** @@ -97,7 +97,7 @@ public void setActive(boolean aIsActive) { * @param aOwnerName The new value of the ownerName attribute. */ public void setOwnerName(String aOwnerName) { - _ownerName = aOwnerName; + ownerName = aOwnerName; } /** @@ -106,7 +106,7 @@ public void setOwnerName(String aOwnerName) { * @return The balance value. */ public double getBalance() { - return _balance; + return balance; } /** @@ -115,25 +115,27 @@ public double getBalance() { * @return The transactions value. */ public List getTransactions() { - return _transactions; + return transactionList; } protected void applyTransaction(AccountTransaction aTransaction) throws NotEnoughFundsException, InactiveAccountException { - if (!_isActive) { - throw new InactiveAccountException("Unable to apply " + aTransaction.getType() + " of amount " + aTransaction.getAmount() + " to account " + _id); + if (!isActive) { + throw new InactiveAccountException("Unable to apply " + + aTransaction.getType() + " of amount " + aTransaction.getAmount() + " to account " + id); } - synchronized (_transactions) { + synchronized (transactionList) { if (AccountTransaction.TransactionType.DEPOSIT == aTransaction.getType()) { - _transactions.add(aTransaction); - _balance += aTransaction.getAmount(); + transactionList.add(aTransaction); + balance += aTransaction.getAmount(); } else if (AccountTransaction.TransactionType.WITHDRAWAL == aTransaction.getType()) { - if (_balance < aTransaction.getAmount()) { - throw new NotEnoughFundsException("Unable to withdraw " + aTransaction.getAmount() + "$ from account " + _id + " - current balance is " + _balance); + if (balance < aTransaction.getAmount()) { + throw new NotEnoughFundsException("Unable to withdraw " + + aTransaction.getAmount() + "$ from account " + id + " - current balance is " + balance); } - _transactions.add(aTransaction); - _balance -= aTransaction.getAmount(); + transactionList.add(aTransaction); + balance -= aTransaction.getAmount(); } else { throw new IllegalArgumentException("The transaction passed in has an invalid type: " + aTransaction.getType()); @@ -147,7 +149,7 @@ protected void applyTransaction(AccountTransaction aTransaction) throws NotEnoug * @param aCreatedBy The new value of the createdBy attribute. */ protected void setCreatedBy(String aCreatedBy) { - _createdBy = aCreatedBy; + createdBy = aCreatedBy; } /** @@ -156,7 +158,7 @@ protected void setCreatedBy(String aCreatedBy) { * @return The createdBy value. */ public String getCreatedBy() { - return _createdBy; + return createdBy; } /** @@ -165,22 +167,22 @@ public String getCreatedBy() { * @return The creationDate value. */ public Date getCreationDate() { - return _creationDate; + return creationDate; } /* (non-Javadoc) - * @see java.lang.Object#toString() - */ + * @see java.lang.Object#toString() + */ public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE). - append("id", _id). - append("ownerName", _ownerName). - append("isActive", _isActive). - append("balance", _balance). - append("tx.count", _transactions.size()). - append("createdBy", _createdBy). - append("creationDate", new Timestamp(_creationDate.getTime())). + append("id", id). + append("ownerName", ownerName). + append("isActive", isActive). + append("balance", balance). + append("tx.count", transactionList.size()). + append("createdBy", createdBy). + append("creationDate", new Timestamp(creationDate.getTime())). toString(); } } diff --git a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/AccountTransaction.java b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/AccountTransaction.java index 4540bcab8f..a3eab3d819 100644 --- a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/AccountTransaction.java +++ b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/AccountTransaction.java @@ -24,25 +24,41 @@ import java.sql.Timestamp; import java.util.Date; -public class AccountTransaction { +public final class AccountTransaction { - private static long _SEQUENCE; + private static long sequence; public enum TransactionType { + /** + * deposit. + */ DEPOSIT, + /** + * withdrawal. + */ WITHDRAWAL } - private long _id; + private long id; - private TransactionType _type; + private TransactionType type; - private long _accountId; + private long accountId; - private double _amount; + private double amount; - private String _createdBy; - private Date _creationDate; + private String createdBy; + + private Date creationDate; + + private AccountTransaction(TransactionType aType, long anAccountId, double anAmount) { + id = ++sequence; + type = aType; + accountId = anAccountId; + amount = anAmount; + createdBy = "unknown"; + creationDate = new Date(); + } public static AccountTransaction createDepositTx(long anAccountId, double anAmount) { return new AccountTransaction(TransactionType.DEPOSIT, anAccountId, anAmount); @@ -52,22 +68,13 @@ public static AccountTransaction createWithdrawalTx(long anAccountId, double anA return new AccountTransaction(TransactionType.WITHDRAWAL, anAccountId, anAmount); } - private AccountTransaction(TransactionType aType, long anAccountId, double anAmount) { - _id = ++_SEQUENCE; - _type = aType; - _accountId = anAccountId; - _amount = anAmount; - _createdBy = "unknown"; - _creationDate = new Date(); - } - /** * Returns the id attribute. * * @return The id value. */ public long getId() { - return _id; + return id; } /** @@ -76,7 +83,7 @@ public long getId() { * @return The type value. */ public TransactionType getType() { - return _type; + return type; } /** @@ -85,7 +92,7 @@ public TransactionType getType() { * @return The accountId value. */ public long getAccountId() { - return _accountId; + return accountId; } /** @@ -94,7 +101,7 @@ public long getAccountId() { * @return The amount value. */ public double getAmount() { - return _amount; + return amount; } /** @@ -103,7 +110,7 @@ public double getAmount() { * @param aCreatedBy The new value of the createdBy attribute. */ protected void setCreatedBy(String aCreatedBy) { - _createdBy = aCreatedBy; + createdBy = aCreatedBy; } /** @@ -112,7 +119,7 @@ protected void setCreatedBy(String aCreatedBy) { * @return The createdBy value. */ public String getCreatedBy() { - return _createdBy; + return createdBy; } /** @@ -121,21 +128,21 @@ public String getCreatedBy() { * @return The creationDate value. */ public Date getCreationDate() { - return _creationDate; + return creationDate; } /* (non-Javadoc) - * @see java.lang.Object#toString() - */ + * @see java.lang.Object#toString() + */ public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE). - append("id", _id). - append("type", _type). - append("accountId", _accountId). - append("amount", _amount). - append("createdBy", _createdBy). - append("creationDate", new Timestamp(_creationDate.getTime())). + append("id", id). + append("type", type). + append("accountId", accountId). + append("amount", amount). + append("createdBy", createdBy). + append("creationDate", new Timestamp(creationDate.getTime())). toString(); } diff --git a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankServerRunner.java b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankServerRunner.java index 162d3405fd..2ac60002fe 100644 --- a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankServerRunner.java +++ b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankServerRunner.java @@ -20,27 +20,27 @@ public class BankServerRunner { - private SecureBankService _bankService; + private SecureBankService bankService; public synchronized void start() throws Exception { - if (_bankService == null) { - _bankService = new SecureBankService(); - _bankService.start(); + if (bankService == null) { + bankService = new SecureBankService(); + bankService.start(); } } public synchronized void stop() { - if (_bankService != null) { + if (bankService != null) { try { - _bankService.dispose(); + bankService.dispose(); } finally { - _bankService = null; + bankService = null; } } } public BankService getBankService() { - return _bankService; + return bankService; } public static void main(String[] args) { diff --git a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankService.java b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankService.java index 9dd7c9d7ba..a76399ddc6 100644 --- a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankService.java +++ b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/BankService.java @@ -22,34 +22,35 @@ public interface BankService { - public long[] searchAccountIdsByOwner(String anOwnerName); + long[] searchAccountIdsByOwner(String anOwnerName); - public long createNewAccount(String anOwnerName); + long createNewAccount(String anOwnerName); - public double getBalanceOf(long anAccountId) throws AccountNotFoundException; + double getBalanceOf(long anAccountId) throws AccountNotFoundException; - public String getOwnerOf(long anAccountId) throws AccountNotFoundException; + String getOwnerOf(long anAccountId) throws AccountNotFoundException; - public double depositInto(long anAccountId, double anAmount) throws AccountNotFoundException, InactiveAccountException; + double depositInto(long anAccountId, double anAmount) throws AccountNotFoundException, InactiveAccountException; - public double withdrawFrom(long anAccountId, double anAmount) throws AccountNotFoundException, NotEnoughFundsException, InactiveAccountException; + double withdrawFrom(long anAccountId, double anAmount) + throws AccountNotFoundException, NotEnoughFundsException, InactiveAccountException; - public TxLog[] getTxHistoryFor(long anAccountId) throws AccountNotFoundException; + TxLog[] getTxHistoryFor(long anAccountId) throws AccountNotFoundException; - public double closeAccount(long anAccountId) throws AccountNotFoundException, InactiveAccountException; + double closeAccount(long anAccountId) throws AccountNotFoundException, InactiveAccountException; - public boolean isAccountActive(long anAccountId) throws AccountNotFoundException; + boolean isAccountActive(long anAccountId) throws AccountNotFoundException; - public static class TxLog { - private Date _creationDate; - private double _amount; - private String _madeBy; + class TxLog { + private Date creationDate; + private double amount; + private String madeBy; public TxLog(Date aCreationDate, double aAmount, String aMadeBy) { super(); - _creationDate = aCreationDate; - _amount = aAmount; - _madeBy = aMadeBy; + creationDate = aCreationDate; + amount = aAmount; + madeBy = aMadeBy; } /** @@ -58,7 +59,7 @@ public TxLog(Date aCreationDate, double aAmount, String aMadeBy) { * @return The creationDate value. */ public Date getCreationDate() { - return _creationDate; + return creationDate; } /** @@ -67,7 +68,7 @@ public Date getCreationDate() { * @return The amount value. */ public double getAmount() { - return _amount; + return amount; } /** @@ -76,7 +77,7 @@ public double getAmount() { * @return The madeBy value. */ public String getMadeBy() { - return _madeBy; + return madeBy; } } diff --git a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/SecureBankService.java b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/SecureBankService.java index 41f0e3aa82..2706734d61 100644 --- a/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/SecureBankService.java +++ b/samples/aspectj/src/main/java/org/apache/shiro/samples/aspectj/bank/SecureBankService.java @@ -32,86 +32,86 @@ public class SecureBankService implements BankService { - private static final Logger log = LoggerFactory.getLogger(SecureBankService.class); - private volatile boolean _isRunning; - private final List _accounts; - private Map _accountsById; + private static final Logger LOGGER = LoggerFactory.getLogger(SecureBankService.class); + private volatile boolean isRunning; + private final List accounts; + private Map accountsById; /** * Creates a new {@link SecureBankService} instance. */ public SecureBankService() { - _accounts = new ArrayList(); - _accountsById = new HashMap(); + accounts = new ArrayList(); + accountsById = new HashMap(); } /** * Starts this service */ public void start() throws Exception { - _isRunning = true; - log.info("Bank service started"); + isRunning = true; + LOGGER.info("Bank service started"); } /** * Stop this service */ public void dispose() { - log.info("Stopping bank service..."); - _isRunning = false; + LOGGER.info("Stopping bank service..."); + isRunning = false; - synchronized (_accounts) { - _accountsById.clear(); - _accounts.clear(); + synchronized (accounts) { + accountsById.clear(); + accounts.clear(); } - log.info("Bank service stopped"); + LOGGER.info("Bank service stopped"); } /** * Internal utility method that validate the internal state of this service. */ protected void assertServiceState() { - if (!_isRunning) { + if (!isRunning) { throw new IllegalStateException("This bank service is not running"); } } public int getAccountCount() { - return _accounts.size(); + return accounts.size(); } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#createNewAccount(java.lang.String) - */ + * @see com.connectif.trilogy.root.security.BankService#createNewAccount(java.lang.String) + */ @RequiresPermissions("bankAccount:create") public long createNewAccount(String anOwnerName) { assertServiceState(); - log.info("Creating new account for " + anOwnerName); + LOGGER.info("Creating new account for " + anOwnerName); - synchronized (_accounts) { + synchronized (accounts) { Account account = new Account(anOwnerName); account.setCreatedBy(getCurrentUsername()); - _accounts.add(account); - _accountsById.put(account.getId(), account); + accounts.add(account); + accountsById.put(account.getId(), account); - log.debug("Created new account: " + account); + LOGGER.debug("Created new account: " + account); return account.getId(); } } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#searchAccountIdsByOwner(java.lang.String) - */ + * @see com.connectif.trilogy.root.security.BankService#searchAccountIdsByOwner(java.lang.String) + */ public long[] searchAccountIdsByOwner(String anOwnerName) { assertServiceState(); - log.info("Searching existing accounts for " + anOwnerName); + LOGGER.info("Searching existing accounts for " + anOwnerName); ArrayList matchAccounts = new ArrayList(); - synchronized (_accounts) { - for (Account a : _accounts) { + synchronized (accounts) { + for (Account a : accounts) { if (a.getOwnerName().toLowerCase().contains(anOwnerName.toLowerCase())) { matchAccounts.add(a); } @@ -124,53 +124,53 @@ public long[] searchAccountIdsByOwner(String anOwnerName) { accountIds[index++] = a.getId(); } - log.debug("Found " + accountIds.length + " account(s) matching the name " + anOwnerName); + LOGGER.debug("Found " + accountIds.length + " account(s) matching the name " + anOwnerName); return accountIds; } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#getOwnerOf(long) - */ + * @see com.connectif.trilogy.root.security.BankService#getOwnerOf(long) + */ @RequiresPermissions("bankAccount:read") public String getOwnerOf(long anAccountId) throws AccountNotFoundException { assertServiceState(); - log.info("Getting owner of account " + anAccountId); + LOGGER.info("Getting owner of account " + anAccountId); Account a = safelyRetrieveAccountForId(anAccountId); return a.getOwnerName(); } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#getBalanceOf(long) - */ + * @see com.connectif.trilogy.root.security.BankService#getBalanceOf(long) + */ @RequiresPermissions("bankAccount:read") public double getBalanceOf(long anAccountId) throws AccountNotFoundException { assertServiceState(); - log.info("Getting balance of account " + anAccountId); + LOGGER.info("Getting balance of account " + anAccountId); Account a = safelyRetrieveAccountForId(anAccountId); return a.getBalance(); } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#depositInto(long, double) - */ + * @see com.connectif.trilogy.root.security.BankService#depositInto(long, double) + */ @RequiresPermissions("bankAccount:operate") public double depositInto(long anAccountId, double anAmount) throws AccountNotFoundException, InactiveAccountException { assertServiceState(); - log.info("Making deposit of " + anAmount + " into account " + anAccountId); + LOGGER.info("Making deposit of " + anAmount + " into account " + anAccountId); try { Account a = safelyRetrieveAccountForId(anAccountId); AccountTransaction tx = AccountTransaction.createDepositTx(anAccountId, anAmount); tx.setCreatedBy(getCurrentUsername()); - log.debug("Created a new transaction " + tx); + LOGGER.debug("Created a new transaction " + tx); a.applyTransaction(tx); - log.debug("New balance of account " + a.getId() + " after deposit is " + a.getBalance()); + LOGGER.debug("New balance of account " + a.getId() + " after deposit is " + a.getBalance()); return a.getBalance(); @@ -180,40 +180,40 @@ public double depositInto(long anAccountId, double anAmount) throws AccountNotFo } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#withdrawFrom(long, double) - */ - + * @see com.connectif.trilogy.root.security.BankService#withdrawFrom(long, double) + */ @RequiresPermissions("bankAccount:operate") - public double withdrawFrom(long anAccountId, double anAmount) throws AccountNotFoundException, NotEnoughFundsException, InactiveAccountException { + public double withdrawFrom(long anAccountId, double anAmount) + throws AccountNotFoundException, NotEnoughFundsException, InactiveAccountException { assertServiceState(); - log.info("Making withdrawal of " + anAmount + " from account " + anAccountId); + LOGGER.info("Making withdrawal of " + anAmount + " from account " + anAccountId); Account a = safelyRetrieveAccountForId(anAccountId); AccountTransaction tx = AccountTransaction.createWithdrawalTx(anAccountId, anAmount); tx.setCreatedBy(getCurrentUsername()); - log.debug("Created a new transaction " + tx); + LOGGER.debug("Created a new transaction " + tx); a.applyTransaction(tx); - log.debug("New balance of account " + a.getId() + " after withdrawal is " + a.getBalance()); + LOGGER.debug("New balance of account " + a.getId() + " after withdrawal is " + a.getBalance()); return a.getBalance(); } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#getTxHistoryFor(long) - */ + * @see com.connectif.trilogy.root.security.BankService#getTxHistoryFor(long) + */ @RequiresPermissions("bankAccount:read") public TxLog[] getTxHistoryFor(long anAccountId) throws AccountNotFoundException { assertServiceState(); - log.info("Getting transactions of account " + anAccountId); + LOGGER.info("Getting transactions of account " + anAccountId); Account a = safelyRetrieveAccountForId(anAccountId); TxLog[] txs = new TxLog[a.getTransactions().size()]; int index = 0; for (AccountTransaction tx : a.getTransactions()) { - log.debug("Retrieved transaction " + tx); + LOGGER.debug("Retrieved transaction " + tx); if (TransactionType.DEPOSIT == tx.getType()) { txs[index++] = new TxLog(tx.getCreationDate(), tx.getAmount(), tx.getCreatedBy()); @@ -226,13 +226,13 @@ public TxLog[] getTxHistoryFor(long anAccountId) throws AccountNotFoundException } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#closeAccount(long) - */ + * @see com.connectif.trilogy.root.security.BankService#closeAccount(long) + */ @RequiresPermissions("bankAccount:close") public double closeAccount(long anAccountId) throws AccountNotFoundException, InactiveAccountException { assertServiceState(); - log.info("Closing account " + anAccountId); + LOGGER.info("Closing account " + anAccountId); Account a = safelyRetrieveAccountForId(anAccountId); if (!a.isActive()) { @@ -242,11 +242,11 @@ public double closeAccount(long anAccountId) throws AccountNotFoundException, In try { AccountTransaction tx = AccountTransaction.createWithdrawalTx(a.getId(), a.getBalance()); tx.setCreatedBy(getCurrentUsername()); - log.debug("Created a new transaction " + tx); + LOGGER.debug("Created a new transaction " + tx); a.applyTransaction(tx); a.setActive(false); - log.debug("Account " + a.getId() + " is now closed and an amount of " + tx.getAmount() + " is given to the owner"); + LOGGER.debug("Account " + a.getId() + " is now closed and an amount of " + tx.getAmount() + " is given to the owner"); return tx.getAmount(); } catch (NotEnoughFundsException nefe) { @@ -255,13 +255,13 @@ public double closeAccount(long anAccountId) throws AccountNotFoundException, In } /* (non-Javadoc) - * @see com.connectif.trilogy.root.security.BankService#isAccountActive(long) - */ + * @see com.connectif.trilogy.root.security.BankService#isAccountActive(long) + */ @RequiresPermissions("bankAccount:read") public boolean isAccountActive(long anAccountId) throws AccountNotFoundException { assertServiceState(); - log.info("Getting active status of account " + anAccountId); + LOGGER.info("Getting active status of account " + anAccountId); Account a = safelyRetrieveAccountForId(anAccountId); return a.isActive(); @@ -277,15 +277,15 @@ public boolean isAccountActive(long anAccountId) throws AccountNotFoundException */ protected Account safelyRetrieveAccountForId(long anAccountId) throws AccountNotFoundException { Account account = null; - synchronized (_accounts) { - account = _accountsById.get(anAccountId); + synchronized (accounts) { + account = accountsById.get(anAccountId); } if (account == null) { throw new AccountNotFoundException("No account found for the id " + anAccountId); } - log.info("Retrieved account " + account); + LOGGER.info("Retrieved account " + account); return account; } diff --git a/samples/aspectj/src/test/java/org/apache/shiro/samples/aspectj/bank/SecureBankServiceTest.java b/samples/aspectj/src/test/java/org/apache/shiro/samples/aspectj/bank/SecureBankServiceTest.java index 123f631c31..416e9e8a75 100644 --- a/samples/aspectj/src/test/java/org/apache/shiro/samples/aspectj/bank/SecureBankServiceTest.java +++ b/samples/aspectj/src/test/java/org/apache/shiro/samples/aspectj/bank/SecureBankServiceTest.java @@ -22,21 +22,29 @@ import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.ini.IniSecurityManagerFactory; +import org.apache.shiro.lang.util.Factory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; -import org.apache.shiro.lang.util.Factory; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.junit.jupiter.api.Assertions.assertThrows; +@SuppressWarnings({"checkstyle:MemberName", "checkstyle:MethodName", "checkstyle:MagicNumber"}) public class SecureBankServiceTest { private static Logger logger = LoggerFactory.getLogger(SecureBankServiceTest.class); private static SecureBankService service; private static int testCounter; + private Subject _subject; + @BeforeAll public static void setUpClass() throws Exception { Factory factory = new IniSecurityManagerFactory("classpath:shiroBankServiceTest.ini"); @@ -54,8 +62,6 @@ public static void tearDownClass() { } } - private Subject _subject; - @BeforeEach public void setUp() throws Exception { logger.info("\n\n#########################\n### STARTING TEST CASE " + (++testCounter) + "\n"); @@ -172,7 +178,7 @@ void testCloseAccount_zeroBalance() throws Exception { logoutCurrentSubject(); loginAsSuperviser(); double closingBalance = service.closeAccount(accountId); - Assertions.assertEquals(0, (int)closingBalance); + Assertions.assertEquals(0, (int) closingBalance); assertAccount("Chris Smith", false, 0, 1, accountId); } @@ -185,7 +191,7 @@ void testCloseAccount_withBalance() throws Exception { logoutCurrentSubject(); loginAsSuperviser(); double closingBalance = service.closeAccount(accountId); - Assertions.assertEquals(385, (int)closingBalance); + Assertions.assertEquals(385, (int) closingBalance); assertAccount("Gerry Smith", false, 0, 2, accountId); } @@ -223,8 +229,8 @@ protected double makeDepositAndValidateAccount(long anAccountId, int anAmount, S double previousBalance = service.getBalanceOf(anAccountId); int previousTxCount = service.getTxHistoryFor(anAccountId).length; double newBalance = service.depositInto(anAccountId, anAmount); - Assertions.assertEquals((int)previousBalance + anAmount, (int)newBalance); - assertAccount(eOwnerName, true, (int)newBalance, 1 + previousTxCount, anAccountId); + Assertions.assertEquals((int) previousBalance + anAmount, (int) newBalance); + assertAccount(eOwnerName, true, (int) newBalance, 1 + previousTxCount, anAccountId); return newBalance; } @@ -232,16 +238,17 @@ protected double makeWithdrawalAndValidateAccount(long anAccountId, int anAmount double previousBalance = service.getBalanceOf(anAccountId); int previousTxCount = service.getTxHistoryFor(anAccountId).length; double newBalance = service.withdrawFrom(anAccountId, anAmount); - Assertions.assertEquals((int)previousBalance - anAmount, (int)newBalance); - assertAccount(eOwnerName, true, (int)newBalance, 1 + previousTxCount, anAccountId); + Assertions.assertEquals((int) previousBalance - anAmount, (int) newBalance); + assertAccount(eOwnerName, true, (int) newBalance, 1 + previousTxCount, anAccountId); return newBalance; } - public static void assertAccount(String eOwnerName, boolean eIsActive, int eBalance, int eTxLogCount, long actualAccountId) throws Exception { + public static void assertAccount(String eOwnerName, boolean eIsActive, int eBalance, + int eTxLogCount, long actualAccountId) throws Exception { Assertions.assertEquals(eOwnerName, service.getOwnerOf(actualAccountId)); Assertions.assertEquals(eIsActive, service.isAccountActive(actualAccountId)); - Assertions.assertEquals(eBalance, (int)service.getBalanceOf(actualAccountId)); + Assertions.assertEquals(eBalance, (int) service.getBalanceOf(actualAccountId)); Assertions.assertEquals(eTxLogCount, service.getTxHistoryFor(actualAccountId).length); } } diff --git a/samples/guice/pom.xml b/samples/guice/pom.xml index 3f6bccd039..9727dc584a 100644 --- a/samples/guice/pom.xml +++ b/samples/guice/pom.xml @@ -17,74 +17,75 @@ ~ specific language governing permissions and limitations ~ under the License. --> - - + + org.apache.shiro.samples shiro-samples - 2.0.0-SNAPSHOT - + 2.0.0-SNAPSHOT + - 4.0.0 - samples-guice - Apache Shiro :: Samples :: Guice Web - war + 4.0.0 + samples-guice + Apache Shiro :: Samples :: Guice Web + war - - - - org.eclipse.jetty - jetty-maven-plugin - - - + + + + org.eclipse.jetty + jetty-maven-plugin + + + - - - org.apache.taglibs - taglibs-standard-spec - compile - - - org.apache.taglibs - taglibs-standard-impl - compile - - - javax.servlet - javax.servlet-api - provided - - - org.apache.logging.log4j - log4j-slf4j2-impl - runtime - - - org.apache.logging.log4j - log4j-core - runtime - - - org.apache.shiro - shiro-core - - - org.apache.shiro - shiro-web - - - org.apache.shiro - shiro-guice - - - com.google.inject.extensions - guice-servlet - - - org.slf4j - jcl-over-slf4j - runtime - + + + org.apache.taglibs + taglibs-standard-spec + compile + + + org.apache.taglibs + taglibs-standard-impl + compile + + + javax.servlet + javax.servlet-api + provided + + + org.apache.logging.log4j + log4j-slf4j2-impl + runtime + + + org.apache.logging.log4j + log4j-core + runtime + + + org.apache.shiro + shiro-core + + + org.apache.shiro + shiro-web + + + org.apache.shiro + shiro-guice + + + com.google.inject.extensions + guice-servlet + + + org.slf4j + jcl-over-slf4j + runtime + org.htmlunit @@ -105,35 +106,35 @@ test - - org.apache.shiro.integrationtests - shiro-its-support - test - - + + org.apache.shiro.integrationtests + shiro-its-support + test + + - - - jdk16 - - [16,) - - - - --illegal-access=permit - --illegal-access=permit - - - - jdk17 - - [17,) - - - - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.lang=ALL-UNNAMED - - - + + + jdk16 + + [16,) + + + + --illegal-access=permit + --illegal-access=permit + + + + jdk17 + + [17,) + + + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED + + + diff --git a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroGuiceBootstrap.java b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroGuiceBootstrap.java index 05e1b35e63..c74ff9c7ca 100644 --- a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroGuiceBootstrap.java +++ b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroGuiceBootstrap.java @@ -21,11 +21,12 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceServletContextListener; -import org.apache.shiro.guice.web.ShiroWebModule; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; +import static org.apache.shiro.guice.web.ShiroWebModule.guiceFilterModule; + public class SampleShiroGuiceBootstrap extends GuiceServletContextListener { private ServletContext servletContext; @@ -39,6 +40,6 @@ public void contextInitialized(final ServletContextEvent servletContextEvent) { @Override protected Injector getInjector() { // return Guice.createInjector(new SampleShiroServletModule(servletContext), ShiroWebModule.guiceFilterModule()); - return Guice.createInjector(new SampleShiroNativeSessionsServletModule(servletContext), ShiroWebModule.guiceFilterModule()); + return Guice.createInjector(new SampleShiroNativeSessionsServletModule(servletContext), guiceFilterModule()); } } diff --git a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroNativeSessionsServletModule.java b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroNativeSessionsServletModule.java index 271982daa8..00425eb2b9 100644 --- a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroNativeSessionsServletModule.java +++ b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroNativeSessionsServletModule.java @@ -21,10 +21,10 @@ import com.google.inject.Provides; import com.google.inject.binder.AnnotatedBindingBuilder; import com.google.inject.name.Names; -import org.apache.shiro.lang.codec.Base64; import org.apache.shiro.config.ConfigurationException; import org.apache.shiro.config.Ini; import org.apache.shiro.guice.web.ShiroWebModule; +import org.apache.shiro.lang.codec.Base64; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.web.mgt.CookieRememberMeManager; @@ -60,7 +60,10 @@ protected void configureShiroWeb() { this.addFilterChain("/login.jsp", AUTHC); this.addFilterChain("/logout", LOGOUT); this.addFilterChain("/account/**", AUTHC); - this.addFilterChain("/remoting/**", filterConfig(AUTHC), filterConfig(ROLES, "b2bClient"), filterConfig(PERMS, "remote:invoke:lan,wan")); + this.addFilterChain("/remoting/**", + filterConfig(AUTHC), + filterConfig(ROLES, "b2bClient"), + filterConfig(PERMS, "remote:invoke:lan,wan")); } @Provides @@ -70,6 +73,7 @@ Ini loadShiroIni() throws MalformedURLException { return Ini.fromResourcePath("url:" + iniUrl.toExternalForm()); } + @SuppressWarnings("checkstyle:MagicNumber") @Override protected void bindSessionManager(AnnotatedBindingBuilder bind) { bind.to(DefaultWebSessionManager.class); @@ -80,23 +84,19 @@ protected void bindSessionManager(AnnotatedBindingBuilder bind) } @Override - protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) - { - try - { - String cipherKey = loadShiroIni().getSectionProperty( "main", "securityManager.rememberMeManager.cipherKey" ); + protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) { + try { + String cipherKey = loadShiroIni().getSectionProperty("main", "securityManager.rememberMeManager.cipherKey"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); CookieRememberMeManager rememberMeManager = new CookieRememberMeManager(); - rememberMeManager.setCipherKey( Base64.decode( cipherKey ) ); + rememberMeManager.setCipherKey(Base64.decode(cipherKey)); securityManager.setRememberMeManager(rememberMeManager); bind.toInstance(securityManager); - } - catch ( MalformedURLException e ) - { + } catch (MalformedURLException e) { // for now just throw, you could just call // super.bindWebSecurityManager(bind) if you do not need rememberMe functionality - throw new ConfigurationException( "securityManager.rememberMeManager.cipherKey must be set in shiro.ini." ); + throw new ConfigurationException("securityManager.rememberMeManager.cipherKey must be set in shiro.ini."); } } } diff --git a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java index 312a59326c..21589161a4 100644 --- a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java +++ b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java @@ -57,7 +57,10 @@ protected void configureShiroWeb() { this.addFilterChain("/logout", LOGOUT); this.addFilterChain("/account/**", AUTHC); - this.addFilterChain("/remoting/**", filterConfig(AUTHC), filterConfig(ROLES, "b2bClient"), filterConfig(PERMS, "remote:invoke:lan,wan")); + this.addFilterChain("/remoting/**", + filterConfig(AUTHC), + filterConfig(ROLES, "b2bClient"), + filterConfig(PERMS, "remote:invoke:lan,wan")); } @Provides @@ -68,23 +71,19 @@ Ini loadShiroIni() throws MalformedURLException { } @Override - protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) - { - try - { - String cipherKey = loadShiroIni().getSectionProperty( "main", "securityManager.rememberMeManager.cipherKey" ); + protected void bindWebSecurityManager(AnnotatedBindingBuilder bind) { + try { + String cipherKey = loadShiroIni().getSectionProperty("main", "securityManager.rememberMeManager.cipherKey"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); CookieRememberMeManager rememberMeManager = new CookieRememberMeManager(); - rememberMeManager.setCipherKey( Base64.decode( cipherKey ) ); + rememberMeManager.setCipherKey(Base64.decode(cipherKey)); securityManager.setRememberMeManager(rememberMeManager); bind.toInstance(securityManager); - } - catch ( MalformedURLException e ) - { + } catch (MalformedURLException e) { // for now just throw, you could just call // super.bindWebSecurityManager(bind) if you do not need rememberMe functionality - throw new ConfigurationException( "securityManager.rememberMeManager.cipherKey must be set in shiro.ini." ); + throw new ConfigurationException("securityManager.rememberMeManager.cipherKey must be set in shiro.ini."); } diff --git a/samples/guice/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java b/samples/guice/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java index d7bb94ebde..7963a6a801 100644 --- a/samples/guice/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java +++ b/samples/guice/src/test/java/org/apache/shiro/samples/guice/ContainerIntegrationIT.java @@ -39,8 +39,7 @@ public void logOut() throws IOException { final HtmlPage homePage = webClient.getPage(getBaseUri()); try { homePage.getAnchorByHref("/logout").click(); - } - catch (ElementNotFoundException e) { + } catch (ElementNotFoundException e) { //Ignore } } diff --git a/samples/pom.xml b/samples/pom.xml index ea9049337b..b378d6ca61 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.apache.shiro diff --git a/samples/quickstart-guice/pom.xml b/samples/quickstart-guice/pom.xml index de44171685..7fa9e70fd2 100644 --- a/samples/quickstart-guice/pom.xml +++ b/samples/quickstart-guice/pom.xml @@ -17,7 +17,8 @@ ~ specific language governing permissions and limitations ~ under the License. --> - + org.apache.shiro.samples shiro-samples diff --git a/samples/quickstart-guice/src/main/java/QuickstartShiroModule.java b/samples/quickstart-guice/src/main/java/QuickstartShiroModule.java index 01caf689f8..0b32d5b4b4 100644 --- a/samples/quickstart-guice/src/main/java/QuickstartShiroModule.java +++ b/samples/quickstart-guice/src/main/java/QuickstartShiroModule.java @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ + import com.google.inject.Provides; import org.apache.shiro.config.Ini; import org.apache.shiro.guice.ShiroModule; diff --git a/samples/quickstart/pom.xml b/samples/quickstart/pom.xml index 3f117014ee..15ce3028ea 100644 --- a/samples/quickstart/pom.xml +++ b/samples/quickstart/pom.xml @@ -18,7 +18,8 @@ ~ under the License. --> - + org.apache.shiro.samples diff --git a/samples/quickstart/src/main/java/Quickstart.java b/samples/quickstart/src/main/java/Quickstart.java index fbba9d2c85..af82f6f261 100644 --- a/samples/quickstart/src/main/java/Quickstart.java +++ b/samples/quickstart/src/main/java/Quickstart.java @@ -27,7 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * Simple Quickstart application showing how to use Shiro's API. * diff --git a/samples/servlet-plugin/pom.xml b/samples/servlet-plugin/pom.xml index de83d018ed..a251bc5b72 100644 --- a/samples/servlet-plugin/pom.xml +++ b/samples/servlet-plugin/pom.xml @@ -18,7 +18,8 @@ ~ under the License. --> - + org.apache.shiro.samples @@ -64,14 +65,14 @@ - - org.apache.maven.plugins - maven-failsafe-plugin - - - **/ContainerIntegrationIT.java - - + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/ContainerIntegrationIT.java + + diff --git a/samples/servlet-plugin/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java b/samples/servlet-plugin/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java index 60d3666be6..e96016857d 100644 --- a/samples/servlet-plugin/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java +++ b/samples/servlet-plugin/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java @@ -37,8 +37,7 @@ public void logOut() throws IOException { final HtmlPage homePage = webClient.getPage(getBaseUri()); try { homePage.getAnchorByHref("/logout").click(); - } - catch (ElementNotFoundException e) { + } catch (ElementNotFoundException e) { //Ignore } } diff --git a/samples/spring-boot-3-web/README.md b/samples/spring-boot-3-web/README.md index 8d2474d9b5..bf33169a69 100644 --- a/samples/spring-boot-3-web/README.md +++ b/samples/spring-boot-3-web/README.md @@ -1,7 +1,8 @@ Apache Shiro + Spring Boot 3 Web Example ================================= -A Spring Boot example web application that show the usage of a user login, checking permissions, and annotation protected methods. +A Spring Boot example web application that show the usage of a user login, checking permissions, and annotation +protected methods. Run the Example --------------- diff --git a/samples/spring-boot-3-web/pom.xml b/samples/spring-boot-3-web/pom.xml index 5f16321e36..a56910b0d2 100644 --- a/samples/spring-boot-3-web/pom.xml +++ b/samples/spring-boot-3-web/pom.xml @@ -18,7 +18,8 @@ ~ under the License. --> - + 4.0.0 @@ -36,7 +37,7 @@ samples.spring.boot3.web 3.1.2 ${spring-boot3.version} - + 6.0.11 @@ -79,7 +80,7 @@ true - + jakarta.servlet jakarta.servlet-api diff --git a/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/HelloController.java b/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/HelloController.java index f4dd27a32f..2861c24067 100644 --- a/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/HelloController.java +++ b/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/HelloController.java @@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import jakarta.servlet.http.HttpServletRequest; + import java.util.Collection; import java.util.Map; @@ -47,8 +48,7 @@ public String home(HttpServletRequest request, Model model) { Collection principalMaps = subject.getPrincipals().byType(Map.class); if (CollectionUtils.isEmpty(principalMaps)) { name = subject.getPrincipal().toString(); - } - else { + } else { name = (String) principalMaps.iterator().next().get("username"); } } diff --git a/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/RestrictedErrorController.java b/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/RestrictedErrorController.java index e7a5e5df5a..6fb0bc6e22 100644 --- a/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/RestrictedErrorController.java +++ b/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/RestrictedErrorController.java @@ -28,9 +28,11 @@ import org.springframework.web.context.request.ServletWebRequest; import jakarta.servlet.http.HttpServletRequest; + import java.util.Map; /** + * */ @Controller public class RestrictedErrorController implements ErrorController { diff --git a/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/WebApp.java b/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/WebApp.java index 819db0f0dc..c347ed875e 100644 --- a/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/WebApp.java +++ b/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/WebApp.java @@ -41,10 +41,13 @@ import java.util.HashMap; import java.util.Map; +/** + * NOPMD + */ @Configuration @ControllerAdvice @SpringBootApplication -public class WebApp { //NOPMD +public class WebApp { private static Logger log = LoggerFactory.getLogger(WebApp.class); @@ -72,11 +75,9 @@ public String handleException(AuthorizationException e, Model model) { @Bean public Realm realm() { TextConfigurationRealm realm = new TextConfigurationRealm(); - realm.setUserDefinitions("joe.coder=password,user\n" + - "jill.coder=password,admin"); + realm.setUserDefinitions("joe.coder=password,user\n" + "jill.coder=password,admin"); - realm.setRoleDefinitions("admin=read,write\n" + - "user=read"); + realm.setRoleDefinitions("admin=read,write\n" + "user=read"); realm.setCachingEnabled(true); return realm; } @@ -84,7 +85,8 @@ public Realm realm() { @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); - chainDefinition.addPathDefinition("/login.html", "authc"); // need to accept POSTs from the login form + // need to accept POSTs from the login form + chainDefinition.addPathDefinition("/login.html", "authc"); chainDefinition.addPathDefinition("/logout", "logout"); return chainDefinition; } diff --git a/samples/spring-boot-3-web/src/main/resources/templates/account-info.html b/samples/spring-boot-3-web/src/main/resources/templates/account-info.html index 1fc0ca95ba..52793f37c2 100644 --- a/samples/spring-boot-3-web/src/main/resources/templates/account-info.html +++ b/samples/spring-boot-3-web/src/main/resources/templates/account-info.html @@ -18,22 +18,22 @@ --> - - Account Info - - - -

    -

    + + Account Info + + + +
    +

    - Home + Home -
    - -
    +
    + +
    -

    - - - +

    + + + \ No newline at end of file diff --git a/samples/spring-boot-3-web/src/main/resources/templates/fragments/head.html b/samples/spring-boot-3-web/src/main/resources/templates/fragments/head.html index 58ab413e91..27d2d78fea 100644 --- a/samples/spring-boot-3-web/src/main/resources/templates/fragments/head.html +++ b/samples/spring-boot-3-web/src/main/resources/templates/fragments/head.html @@ -23,18 +23,22 @@ - - + +