Skip to content

Commit f8a036c

Browse files
authored
Merge pull request #4349 from evolvedbinary/feature/system-as-user
Improvements to system:as-user
2 parents 60a32ba + 7269039 commit f8a036c

File tree

4 files changed

+161
-28
lines changed

4 files changed

+161
-28
lines changed

exist-core/src/main/java/org/exist/xquery/functions/system/AsUser.java

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,43 +21,59 @@
2121
*/
2222
package org.exist.xquery.functions.system;
2323

24+
import com.evolvedbinary.j8fu.function.SupplierE;
2425
import org.apache.logging.log4j.LogManager;
2526
import org.apache.logging.log4j.Logger;
26-
import org.exist.dom.QName;
2727
import org.exist.security.AuthenticationException;
2828
import org.exist.security.SecurityManager;
2929
import org.exist.security.Subject;
3030
import org.exist.storage.DBBroker;
3131
import org.exist.xquery.*;
32-
import org.exist.xquery.value.FunctionParameterSequenceType;
32+
import org.exist.xquery.value.FunctionReference;
3333
import org.exist.xquery.value.Item;
3434
import org.exist.xquery.value.Sequence;
35-
import org.exist.xquery.value.SequenceType;
3635
import org.exist.xquery.value.Type;
3736

37+
import static org.exist.xquery.FunctionDSL.*;
38+
import static org.exist.xquery.functions.system.SystemModule.functionSignature;
39+
3840
/**
3941
*/
4042
public class AsUser extends Function {
4143

4244
private final static Logger logger = LogManager.getLogger(AsUser.class);
4345

44-
public final static FunctionSignature signature = new FunctionSignature(
45-
new QName("as-user", SystemModule.NAMESPACE_URI, SystemModule.PREFIX),
46-
"A pseudo-function to execute a limited block of code as a different " +
47-
"user. The first argument is the name of the user, the second is the " +
48-
"password. If the user can be authenticated, the function will execute the " +
49-
"code block given in the third argument with the permissions of that user and" +
50-
"returns the result of the execution. Before the function completes, it switches " +
51-
"the current user back to the old user.",
52-
new SequenceType[] {
53-
new FunctionParameterSequenceType("username", Type.STRING, Cardinality.EXACTLY_ONE, "The username of the user to run the code against"),
54-
new FunctionParameterSequenceType("password", Type.STRING, Cardinality.ZERO_OR_ONE, "The password of the user to run the code against"),
55-
new FunctionParameterSequenceType("code-block", Type.ITEM, Cardinality.ZERO_OR_MORE, "The code block to run as the identified user")
56-
},
57-
new FunctionParameterSequenceType("result", Type.ITEM, Cardinality.ZERO_OR_MORE, "the results of the code block executed")
46+
private static String FS_AS_USER_NAME = "as-user";
47+
public final static FunctionSignature FS_AS_USER = functionSignature(
48+
FS_AS_USER_NAME,
49+
"A pseudo-function to execute a limited block of code as a different " +
50+
"user. The first argument is the name of the user, the second is the " +
51+
"password. If the user can be authenticated, the function will execute the " +
52+
"code block given in the third argument with the permissions of that user and" +
53+
"returns the result of the execution. Before the function completes, it switches " +
54+
"the current user back to the old user.",
55+
returnsOptMany(Type.ITEM, "the results of the code block executed"),
56+
param("username", Type.STRING, "The username of the user to run the code against"),
57+
optParam("password", Type.STRING, "The password of the user to run the code against"),
58+
optManyParam("code-block", Type.ITEM, "The code block to run as the identified user")
59+
);
60+
61+
private static String FS_FUNCTION_AS_USER_NAME = "function-as-user";
62+
public final static FunctionSignature FS_FUNCTION_AS_USER = functionSignature(
63+
FS_FUNCTION_AS_USER_NAME,
64+
"A pseudo-function to execute a function as a different " +
65+
"user. The first argument is the name of the user, the second is the " +
66+
"password. If the user can be authenticated, the function will execute the " +
67+
"function given in the third argument with the permissions of that user and" +
68+
"returns the result of the execution. Before the function completes, it switches " +
69+
"the current user back to the old user.",
70+
returnsOptMany(Type.ITEM, "the results of the code block executed"),
71+
param("username", Type.STRING, "The username of the user to run the code against"),
72+
optParam("password", Type.STRING, "The password of the user to run the code against"),
73+
param("function", Type.FUNCTION_REFERENCE, "The zero arity function to run as the identified user")
5874
);
5975

60-
public AsUser(final XQueryContext context) {
76+
public AsUser(final XQueryContext context, final FunctionSignature signature) {
6177
super(context, signature);
6278
}
6379

@@ -87,27 +103,40 @@ public Sequence eval(final Sequence contextSequence, final Item contextItem) thr
87103
throw exception;
88104
}
89105

90-
logger.info("Setting the effective user to: [{}]", username);
106+
final SupplierE<Sequence, XPathException> function;
107+
if (isCalledAs(FS_AS_USER_NAME)) {
108+
final Expression codeBlock = getArgument(2);
109+
function = () -> codeBlock.eval(contextSequence, contextItem);
110+
} else if (isCalledAs(FS_FUNCTION_AS_USER_NAME)) {
111+
final FunctionReference functionArg = (FunctionReference) getArgument(2).eval(contextSequence, contextItem).itemAt(0);
112+
final int functionArgArity = functionArg.getSignature().getArgumentCount();
113+
if (functionArgArity != 0) {
114+
throw new XPathException(this, "$function argument must be a zero arity function, but found a function with arity: " + functionArgArity);
115+
}
116+
function = () -> functionArg.evalFunction(null, null, null);
117+
} else {
118+
throw new XPathException(this, "Unknown function: " + getSignature().getName());
119+
}
120+
121+
if (logger.isTraceEnabled()) {
122+
logger.trace("Setting the effective user to: [{}]", username);
123+
}
91124
try {
92125
broker.pushSubject(user);
93-
return getArgument(2).eval(contextSequence, contextItem);
126+
return function.get();
94127
} finally {
95128
broker.popSubject();
96-
logger.info("Returned the effective user to: [{}]", broker.getCurrentSubject());
129+
if (logger.isTraceEnabled()) {
130+
logger.trace("Returned the effective user to: [{}]", broker.getCurrentSubject());
131+
}
97132
}
98133
}
99134

100-
/* (non-Javadoc)
101-
* @see org.exist.xquery.AbstractExpression#getDependencies()
102-
*/
103135
@Override
104136
public int getDependencies() {
105137
return getArgument(2).getDependencies();
106138
}
107139

108-
/* (non-Javadoc)
109-
* @see org.exist.xquery.PathExpr#returnsType()
110-
*/
111140
@Override
112141
public int returnsType() {
113142
return getArgument(2).returnsType();

exist-core/src/main/java/org/exist/xquery/functions/system/SystemModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public class SystemModule extends AbstractInternalModule {
6666
new FunctionDef(Shutdown.signatures[1], Shutdown.class),
6767
new FunctionDef(GetModuleLoadPath.signature, GetModuleLoadPath.class),
6868
new FunctionDef(TriggerSystemTask.signature, TriggerSystemTask.class),
69-
new FunctionDef(AsUser.signature, AsUser.class),
69+
new FunctionDef(AsUser.FS_AS_USER, AsUser.class),
70+
new FunctionDef(AsUser.FS_FUNCTION_AS_USER, AsUser.class),
7071
new FunctionDef(GetIndexStatistics.signature, GetIndexStatistics.class),
7172
new FunctionDef(UpdateStatistics.signature, UpdateStatistics.class),
7273
new FunctionDef(GetRunningXQueries.signature, GetRunningXQueries.class),
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package xquery.system;
23+
24+
import org.exist.test.runner.XSuite;
25+
import org.junit.runner.RunWith;
26+
27+
@RunWith(XSuite.class)
28+
@XSuite.XSuiteFiles({
29+
"src/test/xquery/system"
30+
})
31+
public class SystemTests {
32+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
6+
: http://www.exist-db.org
7+
:
8+
: This library is free software; you can redistribute it and/or
9+
: modify it under the terms of the GNU Lesser General Public
10+
: License as published by the Free Software Foundation; either
11+
: version 2.1 of the License, or (at your option) any later version.
12+
:
13+
: This library is distributed in the hope that it will be useful,
14+
: but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
: Lesser General Public License for more details.
17+
:
18+
: You should have received a copy of the GNU Lesser General Public
19+
: License along with this library; if not, write to the Free Software
20+
: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
:)
22+
xquery version "3.1";
23+
24+
module namespace sysau = "http://exist-db.org/test/system/as-user";
25+
26+
import module namespace sm = "http://exist-db.org/xquery/securitymanager";
27+
import module namespace system = "http://exist-db.org/xquery/system";
28+
29+
declare namespace test = "http://exist-db.org/xquery/xqsuite";
30+
31+
declare
32+
%test:assertEquals('admin')
33+
function sysau:function-as-user-admin-inline() {
34+
system:function-as-user("admin", "", function() {
35+
(sm:id()//sm:username)[last()]/string(.)
36+
})
37+
};
38+
39+
declare
40+
%test:assertEquals('guest')
41+
function sysau:function-as-user-guest-inline() {
42+
system:function-as-user("guest", "guest", function() {
43+
(sm:id()//sm:username)[last()]/string(.)
44+
})
45+
};
46+
47+
declare
48+
%test:assertEquals('admin')
49+
function sysau:function-as-user-admin-reference() {
50+
system:function-as-user("admin", "", sysau:get-effective-user-id#0)
51+
};
52+
53+
declare
54+
%test:assertEquals('guest')
55+
function sysau:function-as-user-guest-reference() {
56+
system:function-as-user("guest", "guest", sysau:get-effective-user-id#0)
57+
};
58+
59+
declare
60+
%test:assertError
61+
function sysau:function-as-user-unknown() {
62+
system:function-as-user("unknown", "", function() {
63+
()
64+
})
65+
};
66+
67+
declare
68+
%private
69+
function sysau:get-effective-user-id() as xs:string {
70+
(sm:id()//sm:username)[last()]/string(.)
71+
};

0 commit comments

Comments
 (0)