/* * eXist Open Source Native XML Database * Copyright (C) 2015 The eXist 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.exist.xquery.functions.securitymanager; import org.exist.EXistException; import org.exist.config.ConfigurationException; import org.exist.dom.QName; import org.exist.security.*; import org.exist.security.SecurityManager; import org.exist.security.internal.aider.GroupAider; import org.exist.xquery.BasicFunction; import org.exist.xquery.Cardinality; import org.exist.xquery.FunctionSignature; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.*; import java.util.ArrayList; import java.util.List; /** * * @author Adam Retter <adam.retter@googlemail.com> */ public class GroupManagementFunction extends BasicFunction { private final static QName qnCreateGroup = new QName("create-group", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX); private final static QName qnRemoveGroup = new QName("remove-group", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX); private final static QName qnDeleteGroup = new QName("delete-group", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX); public final static FunctionSignature FNS_CREATE_GROUP = new FunctionSignature( qnCreateGroup, "Creates a User Group. The current user will be set as the group's manager.", new SequenceType[]{ new FunctionParameterSequenceType("group-name", Type.STRING, Cardinality.EXACTLY_ONE, "The name of the group to create.") }, new SequenceType(Type.ITEM, Cardinality.EMPTY) ); public final static FunctionSignature FNS_CREATE_GROUP_WITH_METADATA = new FunctionSignature( qnCreateGroup, "Creates a User Group. The current user will be set as the group's manager.", new SequenceType[]{ new FunctionParameterSequenceType("group-name", Type.STRING, Cardinality.EXACTLY_ONE, "The name of the group to create."), new FunctionParameterSequenceType("description", Type.STRING, Cardinality.EXACTLY_ONE, "A description of the group.") }, new SequenceType(Type.ITEM, Cardinality.EMPTY) ); public final static FunctionSignature FNS_CREATE_GROUP_WITH_MANAGERS_WITH_METADATA = new FunctionSignature( qnCreateGroup, "Creates a User Group. The current user will be set as a manager of the group in addition to the specified managers.", new SequenceType[]{ new FunctionParameterSequenceType("group-name", Type.STRING, Cardinality.EXACTLY_ONE, "The name of the group to create."), new FunctionParameterSequenceType("managers", Type.STRING, Cardinality.ONE_OR_MORE, "The usernames of users that will be a manager of this group."), new FunctionParameterSequenceType("description", Type.STRING, Cardinality.EXACTLY_ONE, "A description of the group.") }, new SequenceType(Type.ITEM, Cardinality.EMPTY) ); public final static FunctionSignature FNS_REMOVE_GROUP = new FunctionSignature( qnRemoveGroup, "Remove a User Group. Any resources owned by the group will be moved to the 'guest' group.", new SequenceType[]{ new FunctionParameterSequenceType("group-name", Type.STRING, Cardinality.EXACTLY_ONE, "The group-id to delete") }, new SequenceType(Type.ITEM, Cardinality.EMPTY) ); public final static FunctionSignature FNS_DELETE_GROUP = new FunctionSignature( qnDeleteGroup, "Removes a User Group. Any resources owned by the group will be moved to the 'guest' group.", new SequenceType[]{ new FunctionParameterSequenceType("group-id", Type.STRING, Cardinality.EXACTLY_ONE, "The group-id to delete") }, new SequenceType(Type.ITEM, Cardinality.EMPTY), FNS_REMOVE_GROUP ); //TODO implement later /* public final static FunctionSignature FNS_DELETE_GROUP_WITH_SUCCESSOR = new FunctionSignature( qnRemoveGroup "Deletes an existing group identified by $group-id, any resources owned by the group will be moved to the group indicated by $successor-group-id.", new SequenceType[]{ new FunctionParameterSequenceType("group-id", Type.STRING, Cardinality.EXACTLY_ONE, "The group-id to delete"), new FunctionParameterSequenceType("successor-group-id", Type.STRING, Cardinality.EXACTLY_ONE, "The group-id that should take over ownership of any resources") }, new SequenceType(Type.ITEM, Cardinality.EMPTY) ); */ public GroupManagementFunction(final XQueryContext context, final FunctionSignature signature) { super(context, signature); } @Override public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException { final SecurityManager securityManager = context.getBroker().getBrokerPool().getSecurityManager(); final Subject currentSubject = context.getBroker().getCurrentSubject(); try { final String groupName = args[0].itemAt(0).getStringValue(); if(isCalledAs(qnCreateGroup.getLocalPart())) { if(securityManager.hasGroup(groupName)) { throw new XPathException("The group with name " + groupName + " already exists."); } if(!currentSubject.hasDbaRole()) { throw new XPathException("Only DBA users may create a user group."); } final Group group = new GroupAider(groupName); group.addManager(currentSubject); if(getSignature().getArgumentCount() == 3) { //set group managers final List<Account> groupManagers = getGroupManagers(securityManager, args[1]); group.addManagers(groupManagers); } //set metadata if(getSignature().getArgumentCount() >= 2) { group.setMetadataValue(EXistSchemaType.DESCRIPTION, args[getSignature().getArgumentCount() - 1].toString()); } securityManager.addGroup(context.getBroker(), group); } else if(isCalledAs(qnRemoveGroup.getLocalPart()) || isCalledAs(qnDeleteGroup.getLocalPart())) { if(!securityManager.hasGroup(groupName)) { throw new XPathException("The group with name " + groupName + " does not exist."); } final Group successorGroup; if(getArgumentCount() == 2) { final String successorGroupName = args[1].itemAt(0).getStringValue(); if(!currentSubject.hasGroup(successorGroupName)) { throw new PermissionDeniedException("You must be a member of the group for which permissions should be inherited by"); } successorGroup = securityManager.getGroup(successorGroupName); } else { successorGroup = securityManager.getGroup("guest"); } try { securityManager.deleteGroup(groupName); } catch(final EXistException ee) { throw new XPathException(this, ee); } } else { throw new XPathException("Unknown function call: " + getSignature()); } return Sequence.EMPTY_SEQUENCE; } catch(final PermissionDeniedException pde) { throw new XPathException(this, pde); } catch(final ConfigurationException ce) { throw new XPathException(this, ce); } catch(final EXistException ee) { throw new XPathException(this, ee); } } private List<Account> getGroupManagers(final SecurityManager securityManager, final Sequence seq) { final List<Account> managers = new ArrayList<Account>(); for(int i = 0; i < seq.getItemCount(); i++) { final Account account = securityManager.getAccount(seq.itemAt(i).toString()); managers.add(account); } return managers; } }