Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions exist-core/src/main/java/org/exist/xquery/ErrorCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ public class ErrorCodes {
public static final ErrorCode EXXQDY0006 = new EXistErrorCode("EXXQDY0006", "Unable to find named function when trying to execute a Library Module.");
public static final ErrorCode EXXQST0001 = new EXistErrorCode("EXXQST0001", "Unable to find function implementation.");

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

public static final ErrorCode ERROR = new EXistErrorCode("ERROR", "Error.");

public static class ErrorCode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.BasicFunction;
import org.exist.xquery.Cardinality;
import org.exist.xquery.ErrorCodes;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
Expand Down Expand Up @@ -289,8 +290,10 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro

transaction.commit();

} catch(final TransactionException | PermissionDeniedException e) {
throw new XPathException(this, e);
} catch(final PermissionDeniedException pde) {
throw new XPathException(this, ErrorCodes.EXXQDY0007, pde);
} catch(final TransactionException te) {
throw new XPathException(this, te);
}
}

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

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

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

int mode = 0;
Expand Down Expand Up @@ -399,7 +402,7 @@ private Sequence functionModeToOctal(final String modeStr) throws XPathException
final String octal = mode == 0 ? "0" : "0" + Integer.toOctalString(mode);
return new StringValue(this, octal);
} catch(final SyntaxException se) {
throw new XPathException(this, se.getMessage(), se);
throw new XPathException(this, ErrorCodes.EXXQDY0008, se.getMessage(), se);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
(:
: eXist-db Open Source Native XML Database
: Copyright (C) 2001 The eXist-db Authors
:
: info@exist-db.org
: http://www.exist-db.org
:
: This library 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.1 of the License, or (at your option) any later version.
:
: This library 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 library; if not, write to the Free Software
: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
:)
xquery version "3.1";

(:~
: The sm: permission functions assign distinct error codes so callers can tell a
: permission failure (EXXQDY0007) from an invalid-argument failure (EXXQDY0008)
: by branching on $err:code rather than matching message text -- e.g. an HTTP API
: mapping the former to 403 and the latter to 400.
:)
module namespace pec = "http://exist-db.org/test/securitymanager/permission-error-codes";

declare namespace test = "http://exist-db.org/xquery/xqsuite";
declare namespace sm = "http://exist-db.org/xquery/securitymanager";

declare variable $pec:col := "/db/permission-error-codes-test";
declare variable $pec:resource := $pec:col || "/locked.xml";

(: a resource owned by admin with no group/other access, so a non-owner non-dba
(guest) is denied any chmod on it :)
declare
%test:setUp
function pec:setup() {
xmldb:create-collection("/db", "permission-error-codes-test"),
xmldb:store($pec:col, "locked.xml", <locked/>),
sm:chmod(xs:anyURI($pec:resource), "rwx------")
};

declare
%test:tearDown
function pec:teardown() {
if (xmldb:collection-available($pec:col)) then xmldb:remove($pec:col) else ()
};

(: invalid argument -> EXXQDY0008: sm:has-access requires a partial (<=3 char) mode :)
declare
%test:assertError("EXXQDY0008")
function pec:has-access-overlong-mode() {
sm:has-access(xs:anyURI("/db"), "rwxrwxrwx")
};

(: invalid argument -> EXXQDY0008: sm:mode-to-octal rejects a malformed symbolic mode :)
declare
%test:assertError("EXXQDY0008")
function pec:mode-to-octal-bad-syntax() {
sm:mode-to-octal("not-a-valid-mode")
};

(: permission denied -> EXXQDY0007: guest is neither owner nor dba of the locked resource :)
declare
%test:assertError("EXXQDY0007")
function pec:guest-chmod-denied() {
system:as-user("guest", "guest", sm:chmod(xs:anyURI($pec:resource), "rwxr-xr-x"))
};
Loading