/*
* $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/security/SecurityImpl.java,v 1.44.2.3 2004/02/05 16:05:12 mholz Exp $
* $Revision: 1.44.2.3 $
* $Date: 2004/02/05 16:05:12 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* 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.apache.slide.security;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.slide.common.Namespace;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenWrapper;
import org.apache.slide.common.Uri;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.store.Store;
import org.apache.slide.structure.ActionNode;
import org.apache.slide.structure.LinkNode;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.SubjectNode;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.XMLValue;
import org.apache.slide.util.logger.Logger;
import org.jdom.JDOMException;
/**
* Security helper.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @version $Revision: 1.44.2.3 $
*/
public class SecurityImpl implements Security {
private static final String LOG_CHANNEL = SecurityImpl.class.getName();
protected Logger logger;
/**
* Constructor.
*/
public SecurityImpl() {}
/**
* Constructor.
*
* @param namespace Namespace
* @param namespaceConfig Namespace configuration
*/
public SecurityImpl(Namespace namespace, NamespaceConfig namespaceConfig) {
init(namespace, namespaceConfig);
}
public void init(Namespace namespace, NamespaceConfig namespaceConfig) {
this.namespace = namespace;
this.namespaceConfig = namespaceConfig;
this.rolesCache = new Hashtable();
aclInheritanceType = namespaceConfig.getAclInheritanceType();
logger = namespace.getLogger();
loadActionsCache(namespace, namespaceConfig);
}
// ----------------------------------------------------- Instance Variables
/**
* Namespace.
*/
protected Namespace namespace;
/**
* Namespace configuration.
*/
protected NamespaceConfig namespaceConfig;
/**
* Roles cache.
* Role name -> Role interface.
*/
protected Hashtable rolesCache;
protected int aclInheritanceType;
/**
* Cached all actions exsiting at namespace initialization
* and their aggregated actions
*/
private Map actionAggregation; // actionNode -> Set-of-aggregated-nodes (direct aggregates)
private Map actionAggregationClosure; // actionNode -> Set-of-aggregated-nodes (transitive closure)
// ------------------------------------------------------- Security Methods
/**
* Set a new set of permissions on an object.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void setPermissions(SlideToken token, String object,
Enumeration permissions)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
Uri objectUri = namespace.getUri(token, object);
ObjectNode objectNode = objectUri.getStore().retrieveObject(objectUri);
checkCredentials(token, objectNode,
namespaceConfig.getGrantPermissionAction());
checkCredentials(token, objectNode,
namespaceConfig.getRevokePermissionAction());
objectUri.getStore().revokePermissions(objectUri);
while (permissions.hasMoreElements()) {
NodePermission permission =
(NodePermission) permissions.nextElement();
objectUri.getStore().grantPermission(objectUri, permission);
}
}
/**
* Grants a new permission.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @param subject The subject to whom the permission is granted.
* @param action The action which the subject can perform
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void grantPermission(SlideToken token, ObjectNode object,
SubjectNode subject, ActionNode action)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
grantPermission(token, object, subject, action, true);
}
/**
* Grants a new permission.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @param subject Subject who can perform the action
* @param action Action which can be performed
* @param inheritable Create an inheritable permission
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void grantPermission(SlideToken token, ObjectNode object,
SubjectNode subject, ActionNode action,
boolean inheritable)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
NodePermission permission = new NodePermission(object, subject, action,
inheritable);
grantPermission(token, permission);
}
/**
* Grants a new permission.
*
* @param token Credentials token
* @param permission New permission
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void grantPermission(SlideToken token,
NodePermission permission)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
Uri objectUri = namespace.getUri(token, permission.getObjectUri());
ObjectNode object = objectUri.getStore()
.retrieveObject(objectUri);
// Checking if the permission is already present
Enumeration permissions = enumeratePermissions(token, object);
boolean alreadyPresent = false;
while (permissions.hasMoreElements() && !alreadyPresent) {
if (permission.equals(permissions.nextElement())) {
alreadyPresent = true;
}
}
if (!alreadyPresent) {
checkCredentials(token, object,
namespaceConfig.getGrantPermissionAction());
objectUri.getStore().grantPermission(objectUri, permission);
}
}
/**
* Deny a new permission.
*
* @param token Credentials token
* @param object Object on which permission is denied
* @param subject The subject to whom a action is denied
* @param action The action which is denied
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void denyPermission(SlideToken token, ObjectNode object,
SubjectNode subject, ActionNode action)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
denyPermission(token, object, subject, action, true);
}
/**
* Deny a new permission.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @param subject Subject who can perform the action
* @param action Action which can be performed
* @param inheritable Create an inheritable permission
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void denyPermission(SlideToken token, ObjectNode object,
SubjectNode subject, ActionNode action,
boolean inheritable)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
NodePermission permission = new NodePermission(object, subject, action,
inheritable, true);
denyPermission(token, permission);
}
/**
* Deny a new permission.
*
* @param token Credentials token
* @param permission New permission
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void denyPermission(SlideToken token,
NodePermission permission)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
// Make sure the permission we're about to set is indeed a negative
// permission
if (!permission.isNegative())
permission.setNegative(true);
grantPermission(token, permission);
}
/**
* Revokes a permission.
*
* @param token Credentials token
* @param object Object on which permission is revoked
* @param subject Subject who can perform the action
* @param action Action which can be performed
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void revokePermission(SlideToken token, ObjectNode object,
SubjectNode subject, ActionNode action)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
//Domain.info("Revoke permission on " + object.getUri());
checkCredentials(token, object, namespaceConfig
.getRevokePermissionAction());
NodePermission permission = new NodePermission(object, subject,
action);
Uri objectUri = namespace.getUri(token, object.getUri());
objectUri.getStore()
.revokePermission(objectUri, permission);
}
/**
* Revokes a permission.
*
* @param token Credentials token
* @param permission Permission to be removed
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void revokePermission(SlideToken token, NodePermission permission)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
Uri objectUri = namespace.getUri(token, permission.getObjectUri());
ObjectNode object = objectUri.getStore().retrieveObject(objectUri);
checkCredentials(token, object,
namespaceConfig.getRevokePermissionAction());
objectUri.getStore().revokePermission(objectUri, permission);
}
/**
* Check if the credentials given grants permission to perform
* the specified action on the specified subject.
*
* @param token Credentials token
* @param object Object on which the action is performed
* @param action Action performed
* @exception ServiceAccessException DataSource access error
* @exception AccessDeniedException The credentials does not grant
* the permission to perform the specified action
*/
public void checkCredentials(SlideToken token, ObjectNode object,
ActionNode action)
throws ServiceAccessException, AccessDeniedException {
if (!token.isForceSecurity()) {
return;
}
else if (token.isForceStoreEnlistment()) {
token = new SlideTokenWrapper(token, false); // read only access
}
try {
if (Configuration.useIntegratedSecurity()) {
// check if permission has already been checked
Boolean permission = token.checkPermissionCache(object, action);
if (permission == null) {
// if not checked before, check now
try {
Uri objectUri = namespace.getUri(token, object.getUri());
ObjectNode realObject = objectUri.getStore()
.retrieveObject(objectUri);
checkPermission(token, realObject, action);
token.cachePermission(object, action, true);
} catch (AccessDeniedException ade) {
token.cachePermission(object, action, false);
ade.fillInStackTrace();
throw ade;
}
}
else {
if (!(permission.booleanValue())) {
throw new AccessDeniedException
(object.getUri(),
getPrincipal(token).getPath().toString(),
action.getUri());
}
}
}
} catch (ObjectNotFoundException e) {
String subjectUri = "*** Could not determine principal ***";
try {
subjectUri = getPrincipal(token).getPath().toString();
} catch (Exception x) {}
throw new AccessDeniedException
(object.getUri(),
subjectUri,
action.getUri());
}
}
/**
* Check whether or not an actor can perform the specified activity
* on a collection.
*
* @param object Object on which access is tested
* @param subject Subject who seeks to perform the action
* @param action Action which is to be performed
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public void checkPermission(ObjectNode object, SubjectNode subject,
ActionNode action)
throws ServiceAccessException, AccessDeniedException,
ObjectNotFoundException {
if (!hasPermission(object, subject, action)) {
throw new AccessDeniedException(object.getUri(), subject.getUri(),
action.getUri());
}
}
/**
* Check whether or not an actor (principal) can perform the specified activity
* on the specified resource.
*
* @param token a SlideToken
* @param object Object on which access is tested
* @param action Action which is to be performed
*
* @throws ServiceAccessException
* @throws AccessDeniedException
* @throws ObjectNotFoundException
*/
public void checkPermission(SlideToken token, ObjectNode object, ActionNode action) throws ServiceAccessException, AccessDeniedException, ObjectNotFoundException {
if (!hasPermission(token, object, action)) {
throw new AccessDeniedException(object.getUri(), getPrincipal(token).getUri(),
action.getUri());
}
}
/**
* Check whether or not an actor can perform the specified activity
* on a collection.
*
* @param object Object on which access is tested
* @param subject Subject who seeks to perform the action
* @param action Action which is to be performed
* @return true if the action can be performed
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
*/
public boolean hasPermission(ObjectNode object, SubjectNode subject,
ActionNode action)
throws ServiceAccessException, ObjectNotFoundException {
// no check for default action (server intitialization)
if (action == ActionNode.DEFAULT) {
return true;
}
boolean granted = false;
boolean denied = false;
boolean rootObjectReached = false;
ObjectNode courObject = object;
Uri subjectUri = namespace.getUri(subject.getUri());
Uri actionUri = namespace.getUri(action.getUri());
// check if allready granded
while (!granted && !denied && !rootObjectReached) {
Uri courUri = namespace.getUri(courObject.getUri());
Enumeration permissions = courUri.getStore()
.enumeratePermissions(courUri);
while (permissions.hasMoreElements()) {
boolean oldGranted = granted;
boolean oldDenied = denied;
NodePermission permission =
(NodePermission) permissions.nextElement();
String permissionSubject = permission.getSubjectUri();
if (permissionSubject == SubjectNode.SELF_URI) {
boolean check;
check = object.getUri().equals(subjectUri.toString());
if (permission.isInheritable()) {
String subjectUriString = subjectUri.toString();
if(!subjectUriString.endsWith("/"))
subjectUriString = subjectUriString + "/";
check |= object.getUri().startsWith(subjectUriString);
}
// Self permission
granted = (!permission.isNegative())
&& (check)
&& (actionUri.toString()
.startsWith(permission.getActionUri()));
denied = (permission.isNegative())
&& (check)
&& (actionUri.toString()
.startsWith(permission.getActionUri()));
} else if (permission.isInheritable()
|| permission.getObjectUri().equals(object.getUri())) {
if (permissionSubject.startsWith("/")) {
// Node permission
String permSubj = permission.getSubjectUri();
if(!permSubj.endsWith("/"))
permSubj = permSubj + "/";
boolean match = subjectUri.toString().
equals(permission.getSubjectUri()) ||
subjectUri.toString().startsWith(permSubj);
match &= actionUri.toString().
startsWith(permission.getActionUri());
granted = (!permission.isNegative()) && match;
denied = permission.isNegative() && match;
} else if (permissionSubject.startsWith("+")) {
// Permission group which needs to be expanded
Uri permissionSubjectUri =
namespace.getUri(permissionSubject.substring(1));
ObjectNode group =
permissionSubjectUri.getStore().retrieveObject
(permissionSubjectUri);
// if the node is a GroupNode, expand it out to
// normal permissions
if (group instanceof
org.apache.slide.structure.GroupNode ) {
if (group.hasChildren()) {
Enumeration groupMembers =
group.enumerateChildren();
// parse thru the children of the group and
// check permissions on each
while (groupMembers.hasMoreElements()) {
oldGranted = granted;
oldDenied = denied;
Uri childUri =
namespace.getUri
((String) groupMembers.nextElement());
ObjectNode childNode =
childUri.getStore().retrieveObject
(childUri);
String childSubjectUri = childNode
instanceof LinkNode ?
((LinkNode) childNode)
.getLinkedUri() :
childNode.getUri() ;
String testUri;
if(!childSubjectUri.endsWith("/"))
testUri = childSubjectUri+"/";
else
testUri = childSubjectUri;
boolean match = subjectUri.toString().
equals(childSubjectUri) ||
subjectUri.toString().
startsWith(testUri);
match &= actionUri.toString().
startsWith(permission.getActionUri());
granted = (!permission.isNegative()) &&
match;
denied = permission.isNegative() && match;
granted = granted | oldGranted;
denied = denied | oldDenied;
}
}
}
} else {
// Role permission
granted = (!permission.isNegative())
&& (hasRole(subject, permissionSubject))
&& (actionUri.toString()
.startsWith(permission.getActionUri()));
denied = (permission.isNegative())
&& (hasRole(subject, permissionSubject))
&& (actionUri.toString()
.startsWith(permission.getActionUri()));
}
}
granted = granted | oldGranted;
denied = denied | oldDenied;
}
Uri parentUri = courUri.getParentUri();
if (parentUri != null) {
courObject = parentUri.getStore()
.retrieveObject(parentUri);
} else {
rootObjectReached = true;
}
}
// Negative permissions have priority (if they're defined on the same
// node)
if (denied) {
return false;
}
if (!granted) {
return false;
}
return true;
}
/**
* Check whether or not an actor (principal) can perform the specified activity
* on the specified resource.
*
* @param token a SlideToken
* @param object Object on which access is tested
* @param action Action which is to be performed
*
* @return true if the action can be performed
*
* @throws ServiceAccessException
* @throws ObjectNotFoundException
*/
public boolean hasPermission(SlideToken token, ObjectNode object, ActionNode action) throws ServiceAccessException, ObjectNotFoundException {
Boolean cachedPermission = token.checkPermissionCache(object, action);
if (cachedPermission != null) {
return cachedPermission.booleanValue();
}
else {
return hasPermission(object, (SubjectNode)getPrincipal(token), action);
}
}
/**
* Enumerates permissions on an object.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public Enumeration enumeratePermissions(SlideToken token,
ObjectNode object)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
return enumeratePermissions(token, object, false);
}
/**
* Enumerates permissions on an object.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public Enumeration enumeratePermissions(SlideToken token,
ObjectNode object,
boolean includeInherited)
throws ServiceAccessException, ObjectNotFoundException {
return enumeratePermissions(token, object.getUri(), includeInherited);
}
/**
* Enumerates permissions on an object.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public Enumeration enumeratePermissions(SlideToken token,
String object)
throws ServiceAccessException, ObjectNotFoundException,
AccessDeniedException {
return enumeratePermissions(token, object, false);
}
/**
* Enumerates permissions on an object.
*
* @param token Credentials token
* @param object Object on which permission is granted
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
* @exception AccessDeniedException Insufficent credentials
*/
public Enumeration enumeratePermissions(SlideToken token,
String object,
boolean includeInherited)
throws ServiceAccessException, ObjectNotFoundException {
Uri objectUri = namespace.getUri(token, object);
if (!includeInherited) {
return objectUri.getStore().enumeratePermissions(objectUri);
}
else {
ObjectNode objectNode = objectUri.getStore().retrieveObject(objectUri);
Iterator i = retrieveAclSourceNodes(token, objectNode).iterator();
Vector permissions = new Vector();
while (i.hasNext()) {
ObjectNode oNode = (ObjectNode)i.next();
Uri oUri = namespace.getUri(token, oNode.getUri());
Enumeration permEnum = oUri.getStore().enumeratePermissions(oUri);
while (permEnum.hasMoreElements()) {
NodePermission perm = (NodePermission)permEnum.nextElement();
if (object.equals(oNode.getUri())) {
permissions.add(perm);
}
else if (perm.isInheritable()) {
perm.setInheritedFrom(oNode.getUri());
permissions.add(perm);
}
}
}
return permissions.elements();
}
}
/**
* Retrieve the list of object nodes from which to get the ACLs.
* The specified object is returned as first element of the list.
*
* @param token a SlideToken
* @param object an ObjectNode
*
* @return a List of ObjectNode
*
* @throws ServiceAccessException
* @throws ObjectNotFoundException
*/
public List retrieveAclSourceNodes(SlideToken token, ObjectNode object)
throws ServiceAccessException, ObjectNotFoundException {
List result = new ArrayList();
if (token.isForceStoreEnlistment()) {
// get read-only token
token = new SlideTokenWrapper(token, false);
}
Uri uri;
switch (aclInheritanceType) {
case NamespaceConfig.ACL_INHERIT_TYPE_NONE:
uri = namespace.getUri(token, object.getUri());
result.add( uri.getStore().retrieveObject(uri) );
break;
case NamespaceConfig.ACL_INHERIT_TYPE_ROOT:
uri = namespace.getUri(token, object.getUri());
Uri rootUri = namespace.getUri(token, uri.getScope().toString());
result.add( uri.getStore().retrieveObject(uri) );
result.add( rootUri.getStore().retrieveObject(rootUri) );
break;
case NamespaceConfig.ACL_INHERIT_TYPE_PATH:
uri = namespace.getUri(token, object.getUri());
Enumeration enum = uri.getScopes();
while (enum.hasMoreElements()) {
Uri element = namespace.getUri(token, (String)enum.nextElement(), false);
ObjectNode objectNode = element.getStore().retrieveObject(element);
result.add(objectNode);
}
break;
case NamespaceConfig.ACL_INHERIT_TYPE_FULL:
//TODO
break;
default:
break;
}
return result;
}
/**
* Check whether or not the current user has the specified role.
*
* @param token Credentials token
* @param role Role
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
*/
public boolean hasRole(SlideToken token, String role)
throws ServiceAccessException, ObjectNotFoundException {
ObjectNode subject = getPrincipal(token);
return hasRole(subject, role);
}
/**
* Check whether or not the current user has the specified role.
*
* @param object Object node
* @param role Role
* @exception ServiceAccessException DataSource access error
* @exception ObjectNotFoundException Specified object was not found
* in the DataSource
*/
public boolean hasRole(ObjectNode object, String role)
throws ServiceAccessException, ObjectNotFoundException {
if (role.equals(namespaceConfig.NOBODY))
return true;
String associatedRole = namespaceConfig.getRoleMapping(role);
if ((associatedRole != null)
&& (associatedRole.equals(namespaceConfig.NOBODY)))
return true;
Class roleClass = (Class) rolesCache.get(role);
if ((roleClass == null) && (associatedRole != null)) {
roleClass = (Class) rolesCache.get(associatedRole);
if (roleClass == null) {
try {
roleClass = Class.forName(associatedRole);
rolesCache.put(role, roleClass);
rolesCache.put(associatedRole, roleClass);
} catch (ClassNotFoundException ex) {
}
}
}
if (roleClass == null) {
try {
roleClass = Class.forName(role);
rolesCache.put(role, roleClass);
} catch (ClassNotFoundException e) {
}
}
if (roleClass == null) {
return false;
}
if (roleClass.isInstance(object))
return true;
return false;
}
/**
* Return the list of roles the specified node has.
*
* @param object Object node
*/
public Enumeration getRoles(ObjectNode object) {
Vector result = new Vector();
result.addElement(namespaceConfig.NOBODY);
Class currentObjectClass = object.getClass();
while (!currentObjectClass.equals(ObjectNode.class)) {
Class[] interfaces = currentObjectClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
String className = interfaces[i].getName();
String associatedName =
namespaceConfig.getRoleMapping(className);
if (associatedName != null)
result.addElement(associatedName);
else
result.addElement(className);
}
currentObjectClass = currentObjectClass.getSuperclass();
if (currentObjectClass == null) {
// Illegal state
throw new IllegalStateException("Invalid node");
}
}
return result.elements();
}
/**
* Return the list of roles the specified token has.
*
* @param token Credentials token
*/
public Enumeration getRoles(SlideToken token)
throws ServiceAccessException, ObjectNotFoundException {
return getRoles(getPrincipal(token));
}
public Enumeration getRoles(SlideToken token, SubjectNode subjectNode)
throws ServiceAccessException, ObjectNotFoundException {
return getRoles(subjectNode);
}
/**
* Get the SubjectNode associated with the credentials token.
*
* @param token a SlideToken
* @return an ObjectNode
* @throws ServiceAccessException
* @throws ObjectNotFoundException
*/
public ObjectNode getPrincipal(SlideToken token)
throws ServiceAccessException, ObjectNotFoundException {
String user =
token.getCredentialsToken().getPublicCredentials();
if ((user == null) || user.equals("") || user.equals("/")) {
return SubjectNode.UNAUTHENTICATED;
}
Uri subjectUri = namespace.getUri
(token, namespaceConfig.getUsersPath()+"/"+user);
try {
return subjectUri.getStore().retrieveObject(subjectUri);
} catch (ObjectNotFoundException e) {
if (!namespaceConfig.isAutoCreateUsers()) {
throw e;
}
else {
try {
Uri parentUri = subjectUri.getParentUri();
ObjectNode parent =
subjectUri.getStore().retrieveObject(parentUri);
Enumeration childrenEnum = parent.enumerateChildren();
Enumeration linksEnum = parent.enumerateLinks();
Vector children = new Vector();
while (childrenEnum.hasMoreElements()) {
children.addElement(childrenEnum.nextElement());
}
children.addElement(subjectUri.toString());
Vector links = new Vector();
while (linksEnum.hasMoreElements()) {
links.addElement(linksEnum.nextElement());
}
// First, load the object's class
Class objectClass = Class.forName
(namespaceConfig.getAutoCreateUsersRole());
Class[] types = { String.class };
Object[] args = { subjectUri.toString() };
Constructor constructor =
objectClass.getConstructor(types);
ObjectNode object =
(ObjectNode) constructor.newInstance(args);
subjectUri.getStore().createObject(subjectUri, object);
Class[] types2 =
{ String.class, Vector.class, Vector.class };
Object[] args2 = { parentUri.toString(), children, links };
constructor = parent.getClass().getConstructor(types2);
object = (ObjectNode) constructor.newInstance(args2);
parentUri.getStore().storeObject(parentUri, object);
} catch (ClassNotFoundException ex) {
// Can't find role implementing class
throw new ObjectNotFoundException(subjectUri);
} catch (NoSuchMethodException ex) {
// Can't find appropriate constructor
throw new ObjectNotFoundException(subjectUri);
} catch (InstantiationException ex) {
// Can't instatiate object
throw new ObjectNotFoundException(subjectUri);
} catch (InvocationTargetException ex) {
// Can't invoke constructor
throw new ObjectNotFoundException(subjectUri);
} catch (IllegalAccessException ex) {
// Constructor is not public
throw new ObjectNotFoundException(subjectUri);
} catch (ObjectAlreadyExistsException ex) {
// Should never happen
e.printStackTrace();
throw new ObjectNotFoundException(subjectUri);
}
return subjectUri.getStore().retrieveObject(subjectUri);
}
}
}
private void loadActionsCache(Namespace namespace, NamespaceConfig namespaceConfig) {
try {
actionAggregation = new HashMap();
actionAggregationClosure = new HashMap();
String actionsPath = namespaceConfig.getActionsPath();
Uri actionsPathUri = namespace.getUri(actionsPath);
ObjectNode actionsPathNode = actionsPathUri.getStore().retrieveObject(actionsPathUri);
Enumeration actions = actionsPathNode.enumerateChildren();
while (actions.hasMoreElements()) {
ActionNode aNode = ActionNode.getActionNode((String)actions.nextElement());
Set directAggregates = getActionAggregates(aNode);
actionAggregation.put(aNode, directAggregates);
Set aClosure = new HashSet();
aClosure.add(aNode);
aClosure.addAll(directAggregates);
actionAggregationClosure.put(aNode, aClosure);
}
Iterator keys = actionAggregationClosure.keySet().iterator();
while (keys.hasNext()) {
ActionNode aNode = (ActionNode)keys.next();
Set aClosure = (Set)actionAggregationClosure.get(aNode);
actionAggregationClosure.put(aNode, buildClosure(aClosure));
}
// log success
if (logger.isEnabled(LOG_CHANNEL, Logger.INFO)) {
logger.log("Action aggregations loaded successfully", LOG_CHANNEL, Logger.INFO);
}
if (logger.isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
logger.log("\n@@@ Actions aggregations", LOG_CHANNEL, Logger.DEBUG);
Iterator i = actionAggregation.entrySet().iterator();
while (i.hasNext()) {
logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
}
logger.log("\n@@@ Action aggregations (transitive closure)", LOG_CHANNEL, Logger.DEBUG);
i = actionAggregationClosure.entrySet().iterator();
while (i.hasNext()) {
logger.log(" "+i.next(), LOG_CHANNEL, Logger.DEBUG);
}
}
}
catch (Throwable e) {
actionAggregation = null;
actionAggregationClosure = null;
}
}
private Set buildClosure(Set aClosure) {
Set result = new HashSet(aClosure);
int size = 0;
while (result.size() > size) {
size = result.size();
Set newResult = new HashSet();
Iterator i = result.iterator();
while (i.hasNext()) {
newResult.addAll((Set)actionAggregationClosure.get(i.next()));
}
result = newResult;
}
return result;
}
/**
* Get the direct aggregates
*
* @param aNode an ActionNode
* @return set of direct aggregates (ActionNode objects)
* @throws SlideException
* @throws JDOMException
*/
private Set getActionAggregates(ActionNode aNode) throws SlideException, JDOMException {
Set result = new HashSet();
Uri aNodeUri = namespace.getUri(aNode.getUri());
NodeRevisionDescriptor aNrd = aNodeUri.getStore().retrieveRevisionDescriptor(aNodeUri, new NodeRevisionNumber());
NodeProperty membersProp = aNrd.getProperty("privilege-member-set");
if (membersProp != null && membersProp.getValue() != null) {
XMLValue membersVal;
if (membersProp.getValue() instanceof XMLValue) {
membersVal = (XMLValue)membersProp.getValue();
}
else {
membersVal = new XMLValue((String)membersProp.getValue());
}
Iterator mUris = membersVal.getHrefStrings().iterator();
while (mUris.hasNext()) {
result.add(ActionNode.getActionNode((String)mUris.next()));
}
}
return result;
}
/**
* Return true, if-and-only-if checkAction matches permAction.
*
* @param checkAction the "current" action
* @param permAction the action to check against
* (from NodePermission or NodeLock)
*
* @return a boolean
*
*/
public boolean matchAction(SlideToken token, ActionNode checkAction, ActionNode permAction) throws ServiceAccessException {
if (permAction == ActionNode.ALL) {
return true;
}
else {
if (actionAggregationClosure != null) {
Set permActionSet = (Set)actionAggregationClosure.get(permAction);
if (permActionSet == null) {
logger.log("Unknown action " + permAction.getUri() , LOG_CHANNEL, Logger.WARNING);
return false;
} else {
return permActionSet.contains(checkAction);
}
}
else {
Uri u = namespace.getUri(token, checkAction.getUri());
Store s = u.getStore();
throw new ServiceAccessException(s, "Actions cache not loaded");
}
}
}
/**
* Return true, if-and-only-if checkSubject matches permSubject.
*
* @param token a SlideToken
* @param checkSubject the "current" principal
* @param matchSubject the principal to check against (e.g. user
* or group from NodePermission or NodeLock)
*
* @return a boolean
*
* @throws ServiceAccessException
*
*/
public boolean matchPrincipal(SlideToken token, SubjectNode checkSubject, SubjectNode matchSubject) throws ServiceAccessException {
Boolean b = token.checkMatchPrincipalCache(checkSubject, matchSubject);
if (b != null) {
return b.booleanValue();
}
else {
boolean match = matchPrincipal(token, checkSubject, matchSubject, namespaceConfig.getNestedRolesMaxDepth());
token.cacheMatchPrincipal(checkSubject, matchSubject, match);
return match;
}
}
/**
* Return true, if-and-only-if checkSubject matches permSubject.
*
* @param token a SlideToken
* @param checkSubject the "current" principal
* @param matchSubject the principal to check against (e.g. user
* or group from NodePermission or NodeLock)
*
* @return a boolean
*
* @throws ServiceAccessException
*
*/
public boolean matchPrincipal(SlideToken token, SubjectNode checkSubject, SubjectNode matchSubject, int level) throws ServiceAccessException {
if (matchSubject.equals(checkSubject)) {
return true;
}
else {
Uri groupUri = namespace.getUri(token, matchSubject.getUri());
try {
NodeRevisionDescriptor nrd =
groupUri.getStore().retrieveRevisionDescriptor(groupUri, new NodeRevisionNumber());
NodeProperty membersetProp = nrd.getProperty("group-member-set");
if (membersetProp != null && membersetProp.getValue() != null) {
XMLValue xmlVal = new XMLValue((String)membersetProp.getValue());
List memberNodes = xmlVal.getHrefNodes();
if (memberNodes.contains(checkSubject)) {
return true;
}
else if (level > 0) {
int nextLevel = level - 1;
boolean match = false;
Iterator i = memberNodes.iterator();
while (!match && i.hasNext()) {
SubjectNode nextMatchNode = (SubjectNode)i.next();
if (namespaceConfig.isRole(nextMatchNode.getUri())
|| namespaceConfig.isGroup(nextMatchNode.getUri())) {
match = matchPrincipal(token, checkSubject, nextMatchNode, nextLevel);
}
}
return match;
}
else {
return false;
}
}
else {
return false;
}
}
catch (RevisionDescriptorNotFoundException e) {
return false;
}
catch (ServiceAccessException e) {
throw e;
}
catch (JDOMException e) {
e.printStackTrace();
return false;
}
}
}
/**
* Method getActionAggregation
* @return a Map: actionNode -> Set-of-aggregated-nodes (direct aggregates)
*/
public Map getActionAggregation() {
return Collections.unmodifiableMap(actionAggregation);
}
}