Skip to content

Commit d752fde

Browse files
authored
Merge pull request #6464 from joewiz/feature/sm-permission-error-codes
2 parents 4061990 + a2917e7 commit d752fde

3 files changed

Lines changed: 88 additions & 5 deletions

File tree

exist-core/src/main/java/org/exist/xquery/ErrorCodes.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ public class ErrorCodes {
280280
public static final ErrorCode EXXQDY0007 = new EXistErrorCode("EXXQDY0007", "I/O error while streaming a binary resource to the response.");
281281
public static final ErrorCode EXXQST0001 = new EXistErrorCode("EXXQST0001", "Unable to find function implementation.");
282282

283+
// --- Security / permission error codes ---
284+
// Distinct codes so callers (e.g. HTTP API layers) can map a permission failure to
285+
// 403 and an invalid-argument failure to 400 by branching on $err:code, instead of
286+
// matching message text. Used by the sm: permission functions (PermissionsFunction).
287+
public static final ErrorCode EXXQDY0007 = new EXistErrorCode("EXXQDY0007", "Permission denied.");
288+
public static final ErrorCode EXXQDY0008 = new EXistErrorCode("EXXQDY0008", "Invalid argument.");
289+
283290
public static final ErrorCode ERROR = new EXistErrorCode("ERROR", "Error.");
284291

285292
public static class ErrorCode {

exist-core/src/main/java/org/exist/xquery/functions/securitymanager/PermissionsFunction.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.exist.xmldb.XmldbURI;
3636
import org.exist.xquery.BasicFunction;
3737
import org.exist.xquery.Cardinality;
38+
import org.exist.xquery.ErrorCodes;
3839
import org.exist.xquery.FunctionSignature;
3940
import org.exist.xquery.XPathException;
4041
import org.exist.xquery.XQueryContext;
@@ -289,8 +290,10 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro
289290

290291
transaction.commit();
291292

292-
} catch(final TransactionException | PermissionDeniedException e) {
293-
throw new XPathException(this, e);
293+
} catch(final PermissionDeniedException pde) {
294+
throw new XPathException(this, ErrorCodes.EXXQDY0007, pde);
295+
} catch(final TransactionException te) {
296+
throw new XPathException(this, te);
294297
}
295298
}
296299

@@ -301,7 +304,7 @@ private org.exist.dom.memtree.DocumentImpl functionGetPermissions(final XmldbURI
301304
try {
302305
return permissionsToXml(getPermissions(pathUri));
303306
} catch(final PermissionDeniedException pde) {
304-
throw new XPathException(this, "Permission to retrieve permissions is denied for user '" + context.getSubject().getName() + "' on '" + pathUri.toString() + "': " + pde.getMessage(), pde);
307+
throw new XPathException(this, ErrorCodes.EXXQDY0007, "Permission to retrieve permissions is denied for user '" + context.getSubject().getName() + "' on '" + pathUri.toString() + "': " + pde.getMessage(), pde);
305308
}
306309
}
307310

@@ -367,7 +370,7 @@ private Sequence functionChGrp(final DBBroker broker, final Txn transaction, fin
367370

368371
private Sequence functionHasAccess(final XmldbURI pathUri, final String modeStr) throws XPathException {
369372
if(modeStr == null || modeStr.isEmpty() || modeStr.length() > 3) {
370-
throw new XPathException(this, "Mode string must be partial i.e. rwx not rwxrwxrwx");
373+
throw new XPathException(this, ErrorCodes.EXXQDY0008, "Mode string must be partial i.e. rwx not rwxrwxrwx");
371374
}
372375

373376
int mode = 0;
@@ -399,7 +402,7 @@ private Sequence functionModeToOctal(final String modeStr) throws XPathException
399402
final String octal = mode == 0 ? "0" : "0" + Integer.toOctalString(mode);
400403
return new StringValue(this, octal);
401404
} catch(final SyntaxException se) {
402-
throw new XPathException(this, se.getMessage(), se);
405+
throw new XPathException(this, ErrorCodes.EXXQDY0008, se.getMessage(), se);
403406
}
404407
}
405408

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
: info@exist-db.org
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+
(:~
25+
: The sm: permission functions assign distinct error codes so callers can tell a
26+
: permission failure (EXXQDY0007) from an invalid-argument failure (EXXQDY0008)
27+
: by branching on $err:code rather than matching message text -- e.g. an HTTP API
28+
: mapping the former to 403 and the latter to 400.
29+
:)
30+
module namespace pec = "http://exist-db.org/test/securitymanager/permission-error-codes";
31+
32+
declare namespace test = "http://exist-db.org/xquery/xqsuite";
33+
declare namespace sm = "http://exist-db.org/xquery/securitymanager";
34+
35+
declare variable $pec:col := "/db/permission-error-codes-test";
36+
declare variable $pec:resource := $pec:col || "/locked.xml";
37+
38+
(: a resource owned by admin with no group/other access, so a non-owner non-dba
39+
(guest) is denied any chmod on it :)
40+
declare
41+
%test:setUp
42+
function pec:setup() {
43+
xmldb:create-collection("/db", "permission-error-codes-test"),
44+
xmldb:store($pec:col, "locked.xml", <locked/>),
45+
sm:chmod(xs:anyURI($pec:resource), "rwx------")
46+
};
47+
48+
declare
49+
%test:tearDown
50+
function pec:teardown() {
51+
if (xmldb:collection-available($pec:col)) then xmldb:remove($pec:col) else ()
52+
};
53+
54+
(: invalid argument -> EXXQDY0008: sm:has-access requires a partial (<=3 char) mode :)
55+
declare
56+
%test:assertError("EXXQDY0008")
57+
function pec:has-access-overlong-mode() {
58+
sm:has-access(xs:anyURI("/db"), "rwxrwxrwx")
59+
};
60+
61+
(: invalid argument -> EXXQDY0008: sm:mode-to-octal rejects a malformed symbolic mode :)
62+
declare
63+
%test:assertError("EXXQDY0008")
64+
function pec:mode-to-octal-bad-syntax() {
65+
sm:mode-to-octal("not-a-valid-mode")
66+
};
67+
68+
(: permission denied -> EXXQDY0007: guest is neither owner nor dba of the locked resource :)
69+
declare
70+
%test:assertError("EXXQDY0007")
71+
function pec:guest-chmod-denied() {
72+
system:as-user("guest", "guest", sm:chmod(xs:anyURI($pec:resource), "rwxr-xr-x"))
73+
};

0 commit comments

Comments
 (0)