/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2011 The eXist-db Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.security;
import java.io.IOException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.collections.Collection;
import org.exist.collections.triggers.TriggerException;
import org.exist.dom.persistent.DocumentImpl;
import org.exist.storage.DBBroker;
import org.exist.storage.lock.Lock.LockMode;
import org.exist.storage.txn.TransactionException;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import com.evolvedbinary.j8fu.function.ConsumerE;
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.XPathException;
/**
* Instantiates an appropriate Permission class based on the current configuration
*
* @author Adam Retter <adam@exist-db.org>
*/
public class PermissionFactory {
private final static Logger LOG = LogManager.getLogger(PermissionFactory.class);
/**
* Get the Default Resource permissions for the current Subject
* this includes incorporating their umask
*/
public static Permission getDefaultResourcePermission(final SecurityManager sm) {
//TODO consider loading Permission.DEFAULT_PERM from conf.xml instead
final Subject currentSubject = sm.getDatabase().getActiveBroker().getCurrentSubject();
final int mode = Permission.DEFAULT_RESOURCE_PERM & ~ currentSubject.getUserMask();
return new SimpleACLPermission(sm, currentSubject.getId(), currentSubject.getDefaultGroup().getId(), mode);
}
/**
* Get the Default Collection permissions for the current Subject
* this includes incorporating their umask
*/
public static Permission getDefaultCollectionPermission(final SecurityManager sm) {
//TODO consider loading Permission.DEFAULT_PERM from conf.xml instead
final Subject currentSubject = sm.getDatabase().getActiveBroker().getCurrentSubject();
final int mode = Permission.DEFAULT_COLLECTION_PERM & ~ currentSubject.getUserMask();
return new SimpleACLPermission(sm, currentSubject.getId(), currentSubject.getDefaultGroup().getId(), mode);
}
/**
* Get permissions for the current Subject
*/
public static Permission getPermission(final SecurityManager sm, final int mode) {
final Subject currentSubject = sm.getDatabase().getActiveBroker().getCurrentSubject();
return new SimpleACLPermission(sm, currentSubject.getId(), currentSubject.getDefaultGroup().getId(), mode);
}
/**
* Get permissions for the user, group and mode
*/
public static Permission getPermission(final SecurityManager sm, final int userId, final int groupId, final int mode) {
return new SimpleACLPermission(sm, userId, groupId, mode);
}
public static Permission getPermission(final SecurityManager sm, final String userName, final String groupName, final int mode) {
Permission permission = null;
try {
final Account owner = sm.getAccount(userName);
if(owner == null) {
throw new IllegalArgumentException("User was not found '" + (userName == null ? "" : userName) + "'");
}
final Group group = sm.getGroup(groupName);
if(group == null) {
throw new IllegalArgumentException("Group was not found '" + (userName == null ? "" : groupName) + "'");
}
permission = new SimpleACLPermission(sm, owner.getId(), group.getId(), mode);
} catch(final Throwable ex) {
LOG.error("Exception while instantiating security permission class.", ex);
}
return permission;
}
public static void updatePermissions(final DBBroker broker, final XmldbURI pathUri, final ConsumerE<Permission, PermissionDeniedException> permissionModifier) throws PermissionDeniedException {
DocumentImpl doc = null;
final TransactionManager transact = broker.getBrokerPool().getTransactionManager();
try(final Txn transaction = transact.beginTransaction()) {
final Collection collection = broker.openCollection(pathUri, LockMode.WRITE_LOCK);
if (collection == null) {
doc = broker.getXMLResource(pathUri, LockMode.WRITE_LOCK);
if(doc == null) {
transact.abort(transaction);
throw new XPathException("Resource or collection '" + pathUri.toString() + "' does not exist.");
}
final Permission permissions = doc.getPermissions();
permissionModifier.accept(permissions);
broker.storeXMLResource(transaction, doc);
transact.commit(transaction);
broker.flush();
} else {
// keep the write lock in the transaction
transaction.registerLock(collection.getLock(), LockMode.WRITE_LOCK);
final Permission permissions = collection.getPermissionsNoLock();
permissionModifier.accept(permissions);
broker.saveCollection(transaction, collection);
transact.commit(transaction);
broker.flush();
}
} catch(final XPathException | PermissionDeniedException | IOException | TriggerException | TransactionException e) {
throw new PermissionDeniedException("Permission to modify permissions is denied for user '" + broker.getCurrentSubject().getName() + "' on '" + pathUri.toString() + "': " + e.getMessage(), e);
} finally {
if(doc != null) {
doc.getUpdateLock().release(LockMode.WRITE_LOCK);
}
}
}
}