/*
* 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 static org.wamblee.security.authorization.AuthorizationResult.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import org.wamblee.security.authentication.UserAdministration;
/**
* Utility base class for implementation of authentication rules based on the
*
* - 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.AbstractPathCondition}.
* - The user identity with which the resource is accessed. Whether a user is
* appropriate is determined by a
* {@link org.wamblee.security.authorization.AbstractUserCondition}.
* - The operation that is requested. Whether the operation is appropriate is
* determined by a {@link org.wamblee.security.authorization.AbstractOperationCondition}
* .
*
* 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.
*/
@Entity
@Access(AccessType.PROPERTY)
public abstract class UrlAuthorizationRule extends AbstractAuthorizationRule {
private static final Logger LOGGER = Logger
.getLogger(UrlAuthorizationRule.class.getName());
/**
* 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()
*/
@Transient
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, String aUser) {
if (!resourceClass.isInstance(aResource)) {
return UNSUPPORTED_RESOURCE;
}
String path = getResourcePath(aResource);
return isAllowedWithPath(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 isAllowedWithPath(String aPath, Operation aOperation,
String 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.
*/
@Column(name = "AUTH_RESULT", nullable = false)
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);
}
@Column(name = "RES_CLASSNAME", nullable = false)
protected String getResourceClassName() {
if (resourceClass == null) {
return "";
}
return resourceClass.getName();
}
protected void setResourceClassName(String aResourceClass) {
try {
resourceClass = Class.forName(aResourceClass);
} catch (ClassNotFoundException e) {
LOGGER.log(Level.SEVERE, "Cannot find resource class '" + aResourceClass + "'",
e);
throw new IllegalArgumentException(e.getMessage(), e);
}
}
/**
*
* @return Returns the operationCondition.
*/
@OneToOne(cascade = CascadeType.ALL, targetEntity = AbstractOperationCondition.class, orphanRemoval = true)
@JoinColumn(name = "OPER_COND_PK")
public OperationCondition getOperationCondition() {
return operationCondition;
}
/**
*
* @param aOperationCondition
* The operationCondition to set.
*/
protected void setOperationCondition(OperationCondition aOperationCondition) {
operationCondition = aOperationCondition;
}
/**
*
* @return Returns the pathCondition.
*/
@OneToOne(cascade = CascadeType.ALL, targetEntity = AbstractPathCondition.class, orphanRemoval = true)
@JoinColumn(name = "PATH_COND_PK")
public PathCondition getPathCondition() {
return pathCondition;
}
/**
*
* @param aPathCondition
* The pathCondition to set.
*/
protected void setPathCondition(PathCondition aPathCondition) {
pathCondition = aPathCondition;
}
/**
*
* @return Returns the userCondition.
*/
@OneToOne(cascade = CascadeType.ALL, targetEntity = AbstractUserCondition.class, orphanRemoval = true)
@JoinColumn(name = "USER_COND_PK")
public UserCondition getUserCondition() {
return userCondition;
}
/**
*
* @param aUserCondition
* The userCondition to set.
*/
protected void setUserCondition(UserCondition aUserCondition) {
userCondition = aUserCondition;
}
@Override
public void setUserAdministration(UserAdministration aAdmin) {
userCondition.setUserAdmin(aAdmin);
}
}