Separating security into a part that depends only on the JPA and into a
[utils] / security / impl / src / main / java / org / wamblee / security / authorization / UrlAuthorizationRule.java
diff --git a/security/impl/src/main/java/org/wamblee/security/authorization/UrlAuthorizationRule.java b/security/impl/src/main/java/org/wamblee/security/authorization/UrlAuthorizationRule.java
new file mode 100644 (file)
index 0000000..adeb93c
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      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.wamblee.security.authorization;
+
+import org.apache.log4j.Logger;
+
+import org.wamblee.persistence.AbstractPersistent;
+import static org.wamblee.security.authorization.AuthorizationResult.DENIED;
+import static org.wamblee.security.authorization.AuthorizationResult.GRANTED;
+import static org.wamblee.security.authorization.AuthorizationResult.UNDECIDED;
+import static org.wamblee.security.authorization.AuthorizationResult.UNSUPPORTED_RESOURCE;
+
+import org.wamblee.usermgt.User;
+
+/**
+ * Utility base class for implementation of authentication rules based on the
+ * <ul>
+ * <li>The path of the resource. To obtain the path of a resource, subclasses
+ * must implement {@link #getResourcePath(Object)}. Whether a path is
+ * appropriate is determined by a
+ * {@link org.wamblee.security.authorization.PathCondition}.</li>
+ * <li>The user identity with which the resource is accessed. Whether a user is
+ * appropriate is determined by a
+ * {@link org.wamblee.security.authorization.UserCondition}.</li>
+ * <li>The operation that is requested. Whether the operation is appropriate is
+ * determined by a {@link org.wamblee.security.authorization.OperationCondition}
+ * .</li>
+ * </ul>
+ * In case all three conditions match, the condition returns the configured
+ * result passed at construction (GRANTED or DENIED). If the resource is not of
+ * the specified type, the result is UNSUPPORTED_RESOURCE, otherwise, the result
+ * is UNDECIDED.
+ */
+public abstract class UrlAuthorizationRule extends AbstractPersistent implements
+    AuthorizationRule {
+    private static final Logger LOGGER = Logger
+        .getLogger(UrlAuthorizationRule.class);
+
+    /**
+     * Result that the rule will return in case there is a match.
+     */
+    private AuthorizationResult result;
+
+    /**
+     * A condition which specifies which users the rule is for.
+     */
+    private UserCondition userCondition;
+
+    /**
+     * Path the rule applies for.
+     */
+    private PathCondition pathCondition;
+
+    /**
+     * Resource class that the rule applies for.
+     */
+    private Class resourceClass;
+
+    /**
+     * Operation that this rule is for.
+     */
+    private OperationCondition operationCondition;
+
+    /**
+     * Constructs an authorization rule. IF the group and path match, then the
+     * provided result will be returned.
+     * 
+     * @param aResult
+     *            Result of the authorization when the path and group match.
+     * @param aUserCondition
+     *            Condition to match users.
+     * @param aPathCondition
+     *            Condition to match paths with.
+     * @param aResourceClass
+     *            Supported resource class this is for.
+     * @param aOperationCondition
+     *            Condition to match the operation with.
+     */
+    protected UrlAuthorizationRule(AuthorizationResult aResult,
+        UserCondition aUserCondition, PathCondition aPathCondition,
+        Class aResourceClass, OperationCondition aOperationCondition) {
+        if (!aResult.equals(GRANTED) && !aResult.equals(DENIED)) {
+            throw new IllegalArgumentException(
+                "Only GRANTED or DENIED may be used: " + aResult);
+        }
+
+        result = aResult;
+        userCondition = aUserCondition;
+        pathCondition = aPathCondition;
+        resourceClass = aResourceClass;
+        operationCondition = aOperationCondition;
+    }
+
+    /**
+     * For OR mapping.
+     * 
+     */
+    protected UrlAuthorizationRule(Class aResourceClass) {
+        result = null;
+        userCondition = null;
+        pathCondition = null;
+        resourceClass = aResourceClass;
+        operationCondition = null;
+    }
+
+    /**
+     * For OR mapping.
+     * 
+     */
+    protected UrlAuthorizationRule() {
+        result = null;
+        userCondition = null;
+        pathCondition = null;
+        resourceClass = null;
+        operationCondition = null;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.wamblee.security.authorization.AuthorizationRule#getSupportedTypes()
+     */
+    public Class[] getSupportedTypes() {
+        return new Class[] { resourceClass };
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.wamblee.security.authorization.AuthorizationRule#isAllowed(java.lang
+     * .Object, org.wamblee.security.authorization.Operation)
+     */
+    public AuthorizationResult isAllowed(Object aResource,
+        Operation aOperation, User aUser) {
+        if (!resourceClass.isInstance(aResource)) {
+            return UNSUPPORTED_RESOURCE;
+        }
+
+        String path = getResourcePath(aResource);
+
+        return isAllowed(path, aOperation, aUser);
+    }
+
+    /**
+     * Determines if the operation is allowed on the resource.
+     * 
+     * @param aPath
+     *            Path of the resource.
+     * @param aOperation
+     *            Operation to be done.
+     * @param aUser
+     *            Currently logged in user or null if no user is logged in.
+     * 
+     * @return Authorization result,
+     */
+    protected AuthorizationResult isAllowed(String aPath, Operation aOperation,
+        User aUser) {
+        if (!pathCondition.matches(aPath)) {
+            return UNDECIDED;
+        }
+
+        if (!operationCondition.matches(aOperation)) {
+            return UNDECIDED;
+        }
+
+        if (!userCondition.matches(aUser)) {
+            return UNDECIDED;
+        }
+
+        return result;
+    }
+
+    /**
+     * Gets the path of the resource.
+     * 
+     * @param aResource
+     *            Resource, guaranteed to be an instance of
+     *            {@link #resourceClass}.
+     * 
+     * @return Path of the resource.
+     */
+    protected abstract String getResourcePath(Object aResource);
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "UrlAUthorizationRule(result = " + result +
+            ", pathCondition = " + pathCondition + ", userCondition = " +
+            userCondition + ", resourceClass = " + resourceClass + ")";
+    }
+
+    /**
+     * Gets the authorization result for OR mapping.
+     * 
+     * @return Result.
+     */
+    protected String getAuthorizationResultString() {
+        if (result == null) {
+            return null;
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Sets the authorization result, for OR mapping.
+     * 
+     * @param aResult
+     *            Result.
+     */
+    protected void setAuthorizationResultString(String aResult) {
+        result = AuthorizationResult.valueOf(aResult);
+    }
+
+    protected String getResourceClassName() {
+        if (resourceClass == null) {
+            return "";
+        }
+
+        return resourceClass.getName();
+    }
+
+    protected void setResourceClassName(String aResourceClass) {
+        try {
+            resourceClass = Class.forName(aResourceClass);
+        } catch (ClassNotFoundException e) {
+            LOGGER.error("Cannot find resource class '" + aResourceClass + "'",
+                e);
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 
+     * @return Returns the operationCondition.
+     */
+    public OperationCondition getOperationCondition() {
+        return operationCondition;
+    }
+
+    /**
+     * 
+     * @param aOperationCondition
+     *            The operationCondition to set.
+     */
+    protected void setOperationCondition(OperationCondition aOperationCondition) {
+        operationCondition = aOperationCondition;
+    }
+
+    /**
+     * 
+     * @return Returns the pathCondition.
+     */
+    public PathCondition getPathCondition() {
+        return pathCondition;
+    }
+
+    /**
+     * 
+     * @param aPathCondition
+     *            The pathCondition to set.
+     */
+    protected void setPathCondition(PathCondition aPathCondition) {
+        pathCondition = aPathCondition;
+    }
+
+    /**
+     * 
+     * @return Returns the userCondition.
+     */
+    public UserCondition getUserCondition() {
+        return userCondition;
+    }
+
+    /**
+     * 
+     * @param aUserCondition
+     *            The userCondition to set.
+     */
+    protected void setUserCondition(UserCondition aUserCondition) {
+        userCondition = aUserCondition;
+    }
+}