You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by ka...@apache.org on 2010/08/03 06:12:36 UTC
svn commit: r981734 - in /incubator/shiro/trunk/core/src:
main/java/org/apache/shiro/authz/
main/java/org/apache/shiro/authz/annotation/
main/java/org/apache/shiro/authz/aop/ main/java/org/apache/shiro/mgt/
main/java/org/apache/shiro/realm/ main/java/o...
Author: kaosko
Date: Tue Aug 3 04:12:36 2010
New Revision: 981734
URL: http://svn.apache.org/viewvc?rev=981734&view=rev
Log:
Complete - issue SHIRO-175: Improve Set of permission and role checks
https://issues.apache.org/jira/browse/SHIRO-175
- added Logical enum and implemented optional Logical.OR annotation parameter for RequiresRoles and RequiresPermissions annotations
- added Subject.checkRoles(String... roleIdentifiers) etc. (there are several pass-through operations underneath) for completeness
Added:
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java
Modified:
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/Authorizer.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java
incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java
incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java
incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/Authorizer.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/Authorizer.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/Authorizer.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/Authorizer.java Tue Aug 3 04:12:36 2010
@@ -258,5 +258,21 @@ public interface Authorizer {
*/
void checkRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers) throws AuthorizationException;
+ /**
+ * Same as {@link #checkRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers)
+ * 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
+ * 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
+ */
+ void checkRoles(PrincipalCollection subjectPrincipal, String... roleIdentifiers) throws AuthorizationException;
+
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/ModularRealmAuthorizer.java Tue Aug 3 04:12:36 2010
@@ -66,7 +66,6 @@ public class ModularRealmAuthorizer impl
*
* @param realms the realms to consult during an authorization check.
*/
- @SuppressWarnings({"UnusedDeclaration"})
public ModularRealmAuthorizer(Collection<Realm> realms) {
setRealms(realms);
}
@@ -421,9 +420,16 @@ public class ModularRealmAuthorizer impl
}
/**
- * Calls {@link #checkRole(org.apache.shiro.subject.PrincipalCollection , String) checkRole} for each role specified.
+ * Calls {@link #checkRoles(PrincipalCollection principals, String... roles) checkRoles(PrincipalCollection principals, String... roles) }.
*/
public void checkRoles(PrincipalCollection principals, Collection<String> roles) throws AuthorizationException {
+ if (roles != null && !roles.isEmpty()) checkRoles(principals, (String[])roles.toArray() );
+ }
+
+ /**
+ * Calls {@link #checkRole(org.apache.shiro.subject.PrincipalCollection , String) checkRole} for each role specified.
+ */
+ public void checkRoles(PrincipalCollection principals, String... roles) throws AuthorizationException {
assertRealmsConfigured();
if (roles != null) {
for (String role : roles) {
Added: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java?rev=981734&view=auto
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java (added)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/Logical.java Tue Aug 3 04:12:36 2010
@@ -0,0 +1,11 @@
+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
+}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresPermissions.java Tue Aug 3 04:12:36 2010
@@ -33,7 +33,7 @@ import java.lang.annotation.Target;
*
* <p>For example, this declaration:
* <p/>
- * <code>@RequiresPermissions( "file:read,write:aFile.txt" )<br/>
+ * <code>@RequiresPermissions( {"file:read", "write:aFile.txt"} )<br/>
* void someMethod();</code>
* <p/>
* indicates the current user must be able to both <tt>read</tt> and <tt>write</tt>
@@ -52,6 +52,12 @@ public @interface RequiresPermissions {
* 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;
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/annotation/RequiresRoles.java Tue Aug 3 04:12:36 2010
@@ -59,5 +59,10 @@ public @interface RequiresRoles {
* 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;
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/PermissionAnnotationHandler.java Tue Aug 3 04:12:36 2010
@@ -19,14 +19,12 @@
package org.apache.shiro.authz.aop;
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 org.apache.shiro.util.PermissionUtils;
import java.lang.annotation.Annotation;
-import java.util.Arrays;
-import java.util.Set;
-
/**
* Checks to see if a @{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions} annotation is
@@ -68,10 +66,25 @@ public class PermissionAnnotationHandler
public void assertAuthorized(Annotation a) throws AuthorizationException {
if (!(a instanceof RequiresPermissions)) return;
+ RequiresPermissions rpAnnotation = (RequiresPermissions) a;
String[] perms = getAnnotationValue(a);
Subject subject = getSubject();
- if (perms.length == 1) subject.checkPermission(perms[0]);
- else subject.checkPermissions(perms);
+ if (perms.length == 1) {
+ subject.checkPermission(perms[0]);
+ return;
+ }
+ if (Logical.AND.equals(rpAnnotation.logical())) {
+ getSubject().checkPermissions(perms);
+ return;
+ }
+ if (Logical.OR.equals(rpAnnotation.logical())) {
+ // Avoid processing exceptions unnecessarily - "delay" throwing the exception by calling hasRole first
+ boolean hasAtLeastOnePermission = false;
+ for (String permission : perms) if (getSubject().isPermitted(permission)) hasAtLeastOnePermission = true;
+ // 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]);
+
+ }
}
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/authz/aop/RoleAnnotationHandler.java Tue Aug 3 04:12:36 2010
@@ -19,6 +19,7 @@
package org.apache.shiro.authz.aop;
import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import java.lang.annotation.Annotation;
@@ -55,8 +56,21 @@ public class RoleAnnotationHandler exten
RequiresRoles rrAnnotation = (RequiresRoles) a;
String[] roles = rrAnnotation.value();
- if (roles.length == 1) getSubject().checkRole(roles[0]);
- else getSubject().checkRoles(Arrays.asList(roles));
+ if (roles.length == 1) {
+ getSubject().checkRole(roles[0]);
+ return;
+ }
+ if (Logical.AND.equals(rrAnnotation.logical())) {
+ getSubject().checkRoles(Arrays.asList(roles));
+ return;
+ }
+ 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;
+ // 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]);
+ }
}
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/AuthorizingSecurityManager.java Tue Aug 3 04:12:36 2010
@@ -168,4 +168,8 @@ public abstract class AuthorizingSecurit
public void checkRoles(PrincipalCollection principals, Collection<String> roles) throws AuthorizationException {
this.authorizer.checkRoles(principals, roles);
}
+
+ public void checkRoles(PrincipalCollection principals, String... roles) throws AuthorizationException {
+ this.authorizer.checkRoles(principals, roles);
+ }
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/realm/AuthorizingRealm.java Tue Aug 3 04:12:36 2010
@@ -628,7 +628,11 @@ public abstract class AuthorizingRealm e
AuthorizationInfo info = getAuthorizationInfo(principal);
checkRoles(roles, info);
}
-
+
+ public void checkRoles(PrincipalCollection principal, String... roles) throws AuthorizationException {
+ checkRoles(principal, Arrays.asList(roles));
+ }
+
protected void checkRoles(Collection<String> roles, AuthorizationInfo info) {
if (roles != null && !roles.isEmpty()) {
for (String roleName : roles) {
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java Tue Aug 3 04:12:36 2010
@@ -300,6 +300,19 @@ public interface Subject {
* if this Subject does not have all of the specified roles.
*/
void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException;
+
+ /**
+ * Same as {@link #checkRoles(Collection<String> roleIdentifiers) checkRoles(Collection<String> roleIdentifiers)} but
+ * doesn't require a collection as a an argument.
+ * Asserts this Subject has all of the specified roles by returning quietly if they do or throwing an
+ * {@link org.apache.shiro.authz.AuthorizationException} if they do not.
+ *
+ * @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.
+ * @since 1.1.0
+ */
+ void checkRoles(String... roleIdentifiers) throws AuthorizationException;
/**
* Performs a login attempt for this Subject/user. If unsuccessful,
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/support/DelegatingSubject.java Tue Aug 3 04:12:36 2010
@@ -233,6 +233,9 @@ public class DelegatingSubject implement
assertAuthzCheckPossible();
securityManager.checkRole(getPrincipals(), role);
}
+
+ public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
+ }
public void checkRoles(Collection<String> roles) throws AuthorizationException {
assertAuthzCheckPossible();
@@ -456,5 +459,4 @@ public class DelegatingSubject implement
return popped;
}
-
}
Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/PermissionAnnotationHandlerTest.java Tue Aug 3 04:12:36 2010
@@ -19,6 +19,7 @@
package org.apache.shiro.authz.aop;
import org.apache.shiro.authz.UnauthenticatedException;
+import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.test.SecurityManagerTestSupport;
import org.junit.Test;
@@ -44,6 +45,10 @@ public class PermissionAnnotationHandler
public Class<? extends Annotation> annotationType() {
return RequiresPermissions.class;
}
+
+ public Logical logical() {
+ return Logical.AND;
+ }
};
handler.assertAuthorized(requiresPermissionAnnotation);
@@ -63,6 +68,10 @@ public class PermissionAnnotationHandler
public Class<? extends Annotation> annotationType() {
return RequiresPermissions.class;
}
+
+ public Logical logical() {
+ return Logical.AND;
+ }
};
handler.assertAuthorized(requiresPermissionAnnotation);
Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/authz/aop/RoleAnnotationHandlerTest.java Tue Aug 3 04:12:36 2010
@@ -18,8 +18,14 @@
*/
package org.apache.shiro.authz.aop;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
import org.apache.shiro.authz.UnauthenticatedException;
+import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.apache.shiro.subject.Subject;
import org.apache.shiro.test.SecurityManagerTestSupport;
import org.junit.Test;
@@ -29,6 +35,7 @@ import java.lang.annotation.Annotation;
* Test cases for the {@link RoleAnnotationHandler} class.
*/
public class RoleAnnotationHandlerTest extends SecurityManagerTestSupport {
+ private Subject subject;
//Added to satisfy SHIRO-146
@@ -44,6 +51,9 @@ public class RoleAnnotationHandlerTest e
public Class<? extends Annotation> annotationType() {
return RequiresRoles.class;
}
+ public Logical logical() {
+ return Logical.AND;
+ }
};
handler.assertAuthorized(requiresRolesAnnotation);
@@ -63,8 +73,39 @@ public class RoleAnnotationHandlerTest e
public Class<? extends Annotation> annotationType() {
return RequiresRoles.class;
}
+ public Logical logical() {
+ return Logical.AND;
+ }
+ };
+
+ handler.assertAuthorized(requiresRolesAnnotation);
+ }
+
+ @Test
+ public void testOneOfTheRolesRequired() throws Throwable {
+ subject = createMock(Subject.class);
+ expect(subject.hasRole("blah")).andReturn(true);
+ expect(subject.hasRole("blah2")).andReturn(false);
+ replay(subject);
+ RoleAnnotationHandler handler = new RoleAnnotationHandler() {
+ @Override
+ protected Subject getSubject() {
+ return subject;
+ }
};
+ Annotation requiresRolesAnnotation = new RequiresRoles() {
+ public String[] value() {
+ return new String[]{"blah", "blah2"};
+ }
+
+ public Class<? extends Annotation> annotationType() {
+ return RequiresRoles.class;
+ }
+ public Logical logical() {
+ return Logical.OR;
+ }
+ };
handler.assertAuthorized(requiresRolesAnnotation);
}
}
Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java?rev=981734&r1=981733&r2=981734&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java Tue Aug 3 04:12:36 2010
@@ -249,6 +249,7 @@ public class AuthorizingRealmTest {
principals.add(USER_ID + USERNAME);
return new SimpleAuthenticationInfo(principals, PASSWORD, getName());
}
+
}
}
\ No newline at end of file