/**
* OpenKM, Open Document Management System (http://www.openkm.com)
* Copyright (c) 2006-2011 Paco Avila & Josep Llort
*
* No bytes were intentionally harmed during the development of this application.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package com.openkm.cache;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.jcr.AccessDeniedException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.security.auth.Subject;
import org.apache.jackrabbit.core.HierarchyManager;
import org.apache.jackrabbit.core.ItemId;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.security.AMContext;
import org.apache.jackrabbit.core.security.AccessManager;
import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.openkm.bean.Document;
import com.openkm.bean.Note;
import com.openkm.bean.Permission;
import com.openkm.bean.cache.NodePermissions;
import com.openkm.core.Config;
import com.openkm.module.direct.DirectRepositoryModule;
/**
* @author pavila
*
*/
public class OKMAccessManager implements AccessManager {
private static Logger log = LoggerFactory.getLogger(OKMAccessManager.class);
private static final boolean DEBUG = true;
private Subject subject = null;
private HierarchyManager hierMgr = null;
private String principalUser = null;
private Set<String> principalRoles = null;
@Override
public void init(AMContext context) throws AccessDeniedException {
log.info("init(" + context + ")");
subject = context.getSubject();
principalRoles = new HashSet<String>();
log.info("##### " + subject.getPrincipals());
log.info("##### ##### ##### ##### ##### ##### ##### ");
for (Iterator<java.security.Principal> it = subject.getPrincipals().iterator(); it.hasNext();) {
Object obj = it.next();
log.info("##### " + obj.getClass());
if (obj instanceof java.security.acl.Group) {
java.security.acl.Group group = (java.security.acl.Group) obj;
log.info("Group: " + group.getName());
for (Enumeration<? extends java.security.Principal> groups = group.members(); groups.hasMoreElements();) {
java.security.Principal rol = (java.security.Principal) groups.nextElement();
log.info("Rol: " + rol.getName());
principalRoles.add(rol.getName());
}
} else if (obj instanceof java.security.Principal) {
java.security.Principal principal = (java.security.Principal) obj;
principalUser = principal.getName();
log.debug("Principal: " + principalUser);
} else if (obj instanceof org.apache.jackrabbit.core.security.UserPrincipal) {
// TODO Esto es sólo para que funcione en modo shell para el
// desarrollo
// de interfaz web.
org.apache.jackrabbit.core.security.UserPrincipal userPrincipal = (org.apache.jackrabbit.core.security.UserPrincipal) obj;
principalUser = userPrincipal.getName();
principalRoles.add(Config.DEFAULT_USER_ROLE);
log.debug("UserPrincipal: " + principalUser);
}
}
log.debug("PrincipalUser: " + principalUser);
log.debug("PrincipalRoles: " + principalRoles);
log.debug("##### ##### ##### ##### ##### ##### ##### ");
hierMgr = context.getHierarchyManager();
log.debug("init: void");
}
@Override
public void close() throws Exception {
if (DEBUG) log.debug("close()");
}
@Override
public void checkPermission(ItemId id, int permissions)
throws AccessDeniedException, ItemNotFoundException,
RepositoryException {
if (DEBUG) log.debug("checkPermission()");
// TODO Auto-generated method stub
if (DEBUG) log.debug("checkPermission: void");
}
@Override
@SuppressWarnings("deprecation")
public boolean isGranted(ItemId id, int permissions)
throws ItemNotFoundException, RepositoryException {
if (DEBUG) log.debug("isGranted("+ subject.getPrincipals()+ ", "+ id+ ", "
+ (permissions == AccessManager.READ ? "READ"
: (permissions == AccessManager.WRITE ? "WRITE"
: (permissions == AccessManager.REMOVE ? "REMOVE"
: "NONE"))) + ")");
boolean access = false;
if (principalRoles.contains(Config.DEFAULT_ADMIN_ROLE)) {
// An user with AdminRole has total access
access = true;
} else {
NodeId nodeId = null;
if (DEBUG) log.debug(subject.getPrincipals() + " Item Id: " + id);
// Workaround because of transiente node visibility
try {
if (DEBUG) log.debug(subject.getPrincipals() + " Item Path: " + hierMgr.getPath(id));
} catch (ItemNotFoundException e) {
access = true;
if (DEBUG) log.debug(subject.getPrincipals() + " hierMgr.getPath() > ItemNotFoundException: " + e.getMessage());
}
// Check for node id or property id
if (id instanceof NodeId) {
nodeId = (NodeId) id;
if (DEBUG) log.debug(subject.getPrincipals() + " This is a NODE");
} else {
PropertyId propertyId = (PropertyId) id;
nodeId = propertyId.getParentId();
if (DEBUG) log.debug(subject.getPrincipals() + " This is a PROPERTY");
}
if (access || hierMgr.getPath(nodeId).denotesRoot()) {
// Root node has full access
access = true;
} else {
NodePermissions nPerms = NodePermissionsManager.get(nodeId);
if (nPerms == null) {
Session systemSession = DirectRepositoryModule.getSystemSession();
Node node = null;
// Workaround because of transiente node visibility
try {
node = ((SessionImpl) systemSession).getNodeById(nodeId);
} catch (ItemNotFoundException e1) {
if (DEBUG)log.debug(subject.getPrincipals() + " systemSession.getNodeById() > ItemNotFoundException: " + e1.getMessage());
}
if (node == null) {
access = true;
} else {
if (DEBUG) log.debug(subject.getPrincipals() + " Node Name: " + node.getPath());
if (DEBUG) log.debug(subject.getPrincipals() + " Node Type: " + node.getPrimaryNodeType().getName());
if (node.isNodeType(Document.CONTENT_TYPE)) {
if (DEBUG) log.debug(subject.getPrincipals() + " Node is CONTENT_TYPE");
node = node.getParent();
if (DEBUG) log.debug(subject.getPrincipals() + " Real -> " + node.getPath());
} else if (node.isNodeType(Note.LIST_TYPE)) {
if (DEBUG) log.debug(subject.getPrincipals()+" Node is NOTE_LIST_TYPE");
node = node.getParent();
if (DEBUG) log.debug(subject.getPrincipals()+" Real -> "+node.getPath());
} else if (node.isNodeType(Note.TYPE)) {
if (DEBUG) log.debug(subject.getPrincipals()+" Node is NOTE_TYPE");
node = node.getParent().getParent();
} else if (node.isNodeType("nt:frozenNode")) {
if (DEBUG) log.debug(subject.getPrincipals() + " Node is FROZEN_NODE");
String realNodeId = node.getProperty("jcr:frozenUuid").getString();
node = systemSession.getNodeByUUID(realNodeId).getParent();
if (DEBUG) log.debug(subject.getPrincipals() + " Real -> " + node.getPath());
} else if (node.isNodeType("nt:version")) {
log.debug(subject.getPrincipals() + " Node is VERSION");
Node frozenNode = node.getNode("jcr:frozenNode");
log.debug(subject.getPrincipals() + " el congelado -> " + frozenNode.getPath());
String realNodeId = frozenNode.getProperty("jcr:frozenUuid").getString();
try {
node = systemSession.getNodeByUUID(realNodeId).getParent();
if (DEBUG) log.debug(subject.getPrincipals() + " Real -> " + node.getPath());
} catch (javax.jcr.ItemNotFoundException e) {
if (DEBUG) log.debug(subject.getPrincipals() + " **************");
if (DEBUG) log.debug(subject.getPrincipals() + " -> " + e.getMessage());
}
} else if (node.isNodeType("nt:versionHistory")) {
if (DEBUG) log.debug(subject.getPrincipals() + " Node is VERSION_HISTORY");
String realNodeId = node.getProperty("jcr:versionableUuid").getString();
try {
node = systemSession.getNodeByUUID(realNodeId).getParent();
if (DEBUG) log.debug(subject.getPrincipals() + " Real -> " + node.getPath());
} catch (javax.jcr.ItemNotFoundException e) {
if (DEBUG) log.debug(subject.getPrincipals() + " **************");
if (DEBUG) log.debug(subject.getPrincipals() + " **************");
if (DEBUG) log.debug(subject.getPrincipals() + " -> " + e.getMessage());
}
}
// Put permissions into cache
// READ
HashSet<String> sUsersRead = new HashSet<String>();
Value[] vUsersRead = node.getProperty(Permission.USERS_READ).getValues();
for (int i = 0; i < vUsersRead.length; i++) sUsersRead.add(vUsersRead[i].getString());
HashSet<String> sRolesRead = new HashSet<String>();
Value[] vRolesRead = node.getProperty(Permission.ROLES_READ).getValues();
for (int i = 0; i < vRolesRead.length; i++) sRolesRead.add(vRolesRead[i].getString());
// WRITE
HashSet<String> sUsersWrite = new HashSet<String>();
Value[] vUsersWrite = node.getProperty(Permission.USERS_WRITE).getValues();
for (int i = 0; i < vUsersWrite.length; i++) sUsersWrite.add(vUsersWrite[i].getString());
HashSet<String> sRolesWrite = new HashSet<String>();
Value[] vRolesWrite = node.getProperty(Permission.ROLES_WRITE).getValues();
for (int i = 0; i < vRolesWrite.length; i++) sRolesWrite.add(vRolesWrite[i].getString());
// DELETE
HashSet<String> sUsersDelete = new HashSet<String>();
Value[] vUsersDelete = node.getProperty(Permission.USERS_DELETE).getValues();
for (int i = 0; i < vUsersDelete.length; i++) sUsersDelete.add(vUsersDelete[i].getString());
HashSet<String> sRolesDelete = new HashSet<String>();
Value[] vRolesDelete = node.getProperty(Permission.ROLES_DELETE).getValues();
for (int i = 0; i < vRolesDelete.length; i++) sRolesDelete.add(vRolesDelete[i].getString());
// SECURITY
HashSet<String> sUsersSecurity= new HashSet<String>();
Value[] vUsersSecurity = node.getProperty(Permission.USERS_SECURITY).getValues();
for (int i = 0; i < vUsersSecurity.length; i++) sUsersSecurity.add(vUsersSecurity[i].getString());
HashSet<String> sRolesSecurity = new HashSet<String>();
Value[] vRolesSecurity = node.getProperty(Permission.ROLES_SECURITY).getValues();
for (int i = 0; i < vRolesSecurity.length; i++) sRolesSecurity.add(vRolesSecurity[i].getString());
nPerms = new NodePermissions();
nPerms.setUsersRead(sUsersRead);
nPerms.setRolesRead(sRolesRead);
nPerms.setUsersWrite(sUsersWrite);
nPerms.setRolesWrite(sRolesWrite);
nPerms.setUsersDelete(sUsersDelete);
nPerms.setRolesDelete(sRolesDelete);
nPerms.setUsersSecurity(sUsersSecurity);
nPerms.setRolesSecurity(sRolesSecurity);
NodePermissionsManager.put(nodeId, nPerms);
}
}
if (permissions == AccessManager.READ) {
access = checkRead(nPerms.getUsersRead(), nPerms.getRolesRead());
} else if (permissions == AccessManager.WRITE || permissions == AccessManager.REMOVE) {
access = checkWrite(nPerms.getUsersWrite(), nPerms.getRolesWrite());
}
}
}
// Workaround because of transiente node visibility
try {
if (DEBUG) log.debug(subject.getPrincipals() + " Path: " + hierMgr.getPath(id));
} catch (ItemNotFoundException e) {
if (DEBUG) log.debug(subject.getPrincipals() + " hierMgr.getPath() > ItemNotFoundException: " + e.getMessage());
}
if (DEBUG) log.debug(subject.getPrincipals() + " isGranted "
+ (permissions == AccessManager.READ ? "READ"
: (permissions == AccessManager.WRITE ? "WRITE"
: (permissions == AccessManager.REMOVE ? "REMOVE"
: "NONE"))) + ": " + access);
if (DEBUG) log.debug("-------------------------------------");
return access;
}
@Override
public boolean canAccess(String workspaceName)
throws NoSuchWorkspaceException, RepositoryException {
boolean access = true;
if (DEBUG) log.debug("canAccess(" + workspaceName + ")");
if (DEBUG) log.debug("canAccess: " + access);
return access;
}
/**
*
*/
private boolean checkRead(Set<String> usersRead, Set<String> rolesRead) {
if (DEBUG) log.debug("checkRead(" + usersRead + ", " + rolesRead + ")");
boolean access = false;
if (usersRead.contains(principalUser)) {
access = true;
} else {
for (Iterator<String> it = principalRoles.iterator(); it.hasNext();) {
if (rolesRead.contains(it.next())) {
access = true;
break;
}
}
}
if (DEBUG) log.debug("checkRead: " + access);
return access;
}
/**
*
*/
private boolean checkWrite(Set<String> usersWrite, Set<String> rolesWrite) {
if (DEBUG) log.debug("checkWrite(" + usersWrite + ", " + rolesWrite + ")");
boolean access = false;
if (usersWrite.contains(principalUser)) {
access = true;
} else {
for (Iterator<String> it = principalRoles.iterator(); it.hasNext();) {
if (rolesWrite.contains(it.next())) {
access = true;
break;
}
}
}
if (DEBUG) log.debug("checkWrite: " + access);
return access;
}
@Override
public boolean canRead(Path arg0) throws RepositoryException {
return false;
}
@Override
public void init(AMContext arg0, AccessControlProvider arg1, WorkspaceAccessManager arg2)
throws AccessDeniedException, Exception {
}
@Override
public boolean isGranted(Path arg0, int arg1) throws RepositoryException {
return false;
}
@Override
public boolean isGranted(Path arg0, Name arg1, int arg2) throws RepositoryException {
return false;
}
//@Override
// TODO Enable @Override when use jackrabbit 1.6
public void checkPermission(Path arg0, int arg1) throws AccessDeniedException, RepositoryException {
}
}