/*
* eXist SecurityManager Extension
* Copyright (C) 2010 Adam Retter <adam@existsolutions.com>
* www.adamretter.co.uk
*
* 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.xquery.functions.securitymanager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.exist.dom.QName;
import org.exist.security.Account;
import org.exist.security.SecurityManager;
import org.exist.security.Subject;
import org.exist.storage.DBBroker;
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.*;
/**
*
* @author Adam Retter <adam@existsolutions.com>
*/
public class FindGroupFunction extends BasicFunction {
private final static QName qnFindGroupsByGroupname = new QName("find-groups-by-groupname", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
private final static QName qnListGroups = new QName("list-groups", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
private final static QName qnFindGroupsWhereGroupnameContains = new QName("find-groups-where-groupname-contains", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
private final static QName qnGetUserGroups = new QName("get-user-groups", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
private final static QName qnGetUserPrimaryGroup = new QName("get-user-primary-group", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
private final static QName qnGroupExists = new QName("group-exists", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
// deprecated sm:get-groups
private final static QName qnGetGroups = new QName("get-groups", SecurityManagerModule.NAMESPACE_URI, SecurityManagerModule.PREFIX);
public final static FunctionSignature FNS_LIST_GROUPS = new FunctionSignature(
qnListGroups,
"List all groups",
null,
new FunctionReturnSequenceType(Type.STRING, Cardinality.ZERO_OR_MORE, "The list of groups")
);
public final static FunctionSignature FNS_GET_GROUPS = new FunctionSignature(
qnGetGroups,
"List all groups",
null,
new FunctionReturnSequenceType(Type.STRING, Cardinality.ZERO_OR_MORE, "The list of groups"),
FNS_LIST_GROUPS
);
public final static FunctionSignature FNS_FIND_GROUPS_BY_GROUPNAME = new FunctionSignature(
qnFindGroupsByGroupname,
"Finds groups whoose group name starts with a matching string",
new SequenceType[] {
new FunctionParameterSequenceType("starts-with", Type.STRING, Cardinality.EXACTLY_ONE, "The starting string against which to match group names")
},
new FunctionReturnSequenceType(Type.STRING, Cardinality.ZERO_OR_MORE, "The list of matching group names")
);
public final static FunctionSignature FNS_FIND_GROUPS_WHERE_GROUPNAME_CONTANINS = new FunctionSignature(
qnFindGroupsWhereGroupnameContains,
"Finds groups whoose group name contains the string fragment",
new SequenceType[] {
new FunctionParameterSequenceType("fragment", Type.STRING, Cardinality.EXACTLY_ONE, "The fragment against which to match group names")
},
new FunctionReturnSequenceType(Type.STRING, Cardinality.ZERO_OR_MORE, "The list of matching group names")
);
public final static FunctionSignature FNS_GET_USER_GROUPS = new FunctionSignature(
qnGetUserGroups,
"Returns the sequence of groups that the user $user is a member of. You must be a DBA or logged in as the user for which you are trying to retrieve group details for.",
new SequenceType[] {
new FunctionParameterSequenceType("user", Type.STRING, Cardinality.EXACTLY_ONE, "The username to retrieve the group membership list for.")
},
new FunctionReturnSequenceType(Type.STRING, Cardinality.ONE_OR_MORE, "The users group memberships")
);
public final static FunctionSignature FNS_GET_USER_PRIMARY_GROUP = new FunctionSignature(
qnGetUserPrimaryGroup,
"Returns the primary group of the user $user. You must be a DBA or logged in as the user for which you are trying to retrieve group details for.",
new SequenceType[] {
new FunctionParameterSequenceType("user", Type.STRING, Cardinality.EXACTLY_ONE, "The username to retrieve the primary group of.")
},
new FunctionReturnSequenceType(Type.STRING, Cardinality.EXACTLY_ONE, "The users primary group")
);
public final static FunctionSignature FNS_GROUP_EXISTS = new FunctionSignature(
qnGroupExists,
"Determines whether a user group exists.",
new SequenceType[] {
new FunctionParameterSequenceType("group", Type.STRING, Cardinality.EXACTLY_ONE, "The name of the user group to check for existence.")
},
new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE, "true if the user group exists, false otherwise.")
);
public FindGroupFunction(final XQueryContext context, final FunctionSignature signature) {
super(context, signature);
}
@Override
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
final DBBroker broker = getContext().getBroker();
final Subject currentUser = broker.getSubject();
if(!isCalledAs(qnGetUserGroups.getLocalName()) && currentUser.getName().equals(SecurityManager.GUEST_USER)) {
throw new XPathException("You must be an authenticated user");
}
final SecurityManager securityManager = broker.getBrokerPool().getSecurityManager();
final Sequence result;
if(isCalledAs(qnGetUserPrimaryGroup.getLocalName())) {
final String username = args[0].getStringValue();
result = new StringValue(securityManager.getAccount(username).getPrimaryGroup());
} else if(isCalledAs(qnGroupExists.getLocalName())) {
final String groupName = args[0].getStringValue();
result = BooleanValue.valueOf(securityManager.hasGroup(groupName));
} else {
final List<String> groupNames;
if(isCalledAs(qnListGroups.getLocalName()) || isCalledAs(qnGetGroups.getLocalName())) {
groupNames = securityManager.findAllGroupNames();
} else if(isCalledAs(qnFindGroupsByGroupname.getLocalName())) {
final String startsWith = args[0].getStringValue();
groupNames = securityManager.findGroupnamesWhereGroupnameStarts(startsWith);
} else if(isCalledAs(qnFindGroupsWhereGroupnameContains.getLocalName())) {
final String fragment = args[0].getStringValue();
groupNames = securityManager.findGroupnamesWhereGroupnameContains(fragment);
} else if(isCalledAs(qnGetUserGroups.getLocalName())) {
final String username = args[0].getStringValue();
if(!currentUser.hasDbaRole() && !currentUser.getName().equals(username)) {
throw new XPathException("You must be a DBA or enquiring about your own user account!");
}
final Account user = securityManager.getAccount(username);
groupNames = Arrays.asList(user.getGroups());
} else {
throw new XPathException("Unknown function");
}
//order a-z
Collections.sort(groupNames);
result = new ValueSequence();
for(final String groupName : groupNames) {
result.add(new StringValue(groupName));
}
}
return result;
}
}