Search in sources :

Example 1 with EffectiveSubject

use of org.exist.security.EffectiveSubject in project exist by eXist-db.

the class ResourceFunctionExecutorImpl method getEffectiveSubject.

/**
 * If the compiled xquery is setUid and/or setGid
 * we return the EffectiveSubject that should be used
 * for execution
 *
 * @param xquery The XQuery to determine the effective subject for
 * @return Maybe an effective subject or empty if there is no setUid or setGid bits
 */
private Optional<EffectiveSubject> getEffectiveSubject(final CompiledXQuery xquery) {
    final Optional<EffectiveSubject> effectiveSubject;
    final Source src = xquery.getContext().getSource();
    if (src instanceof DBSource) {
        final DBSource dbSrc = (DBSource) src;
        final Permission perm = dbSrc.getPermissions();
        if (perm.isSetUid()) {
            if (perm.isSetGid()) {
                // setUid and SetGid
                effectiveSubject = Optional.of(new EffectiveSubject(perm.getOwner(), perm.getGroup()));
            } else {
                // just setUid
                effectiveSubject = Optional.of(new EffectiveSubject(perm.getOwner()));
            }
        } else if (perm.isSetGid()) {
            // just setGid, so we use the current user as the effective user
            effectiveSubject = Optional.of(new EffectiveSubject(xquery.getContext().getBroker().getCurrentSubject(), perm.getGroup()));
        } else {
            effectiveSubject = Optional.empty();
        }
    } else {
        effectiveSubject = Optional.empty();
    }
    return effectiveSubject;
}
Also used : EffectiveSubject(org.exist.security.EffectiveSubject) Permission(org.exist.security.Permission) DBSource(org.exist.source.DBSource) Source(org.exist.source.Source) DBSource(org.exist.source.DBSource)

Example 2 with EffectiveSubject

use of org.exist.security.EffectiveSubject in project exist by eXist-db.

the class ResourceFunctionExecutorImpl method execute.

@Override
public Sequence execute(final ResourceFunction resourceFunction, final Iterable<TypedArgumentValue> arguments, final HttpRequest request) throws RestXqServiceException {
    final RestXqServiceCompiledXQueryCache cache = RestXqServiceCompiledXQueryCacheImpl.getInstance();
    CompiledXQuery xquery = null;
    ProcessMonitor processMonitor = null;
    try (final DBBroker broker = getBrokerPool().getBroker()) {
        // ensure we can execute the function before going any further
        checkSecurity(broker, resourceFunction.getXQueryLocation());
        // get a compiled query service from the cache
        xquery = cache.getCompiledQuery(broker, resourceFunction.getXQueryLocation());
        // find the function that we will execute
        final UserDefinedFunction fn = findFunction(xquery, resourceFunction.getFunctionSignature());
        final XQueryContext xqueryContext = xquery.getContext();
        // set the request object - can later be used by the EXQuery Request Module
        xqueryContext.setAttribute(EXQ_REQUEST_ATTR, request);
        // TODO this is a workaround?
        declareVariables(xqueryContext);
        // START workaround: evaluate global variables in modules, as they are reset by XQueryContext.reset()
        final Expression rootExpr = xqueryContext.getRootExpression();
        for (int i = 0; i < rootExpr.getSubExpressionCount(); i++) {
            final Expression subExpr = rootExpr.getSubExpression(i);
            if (subExpr instanceof VariableDeclaration) {
                subExpr.eval(null);
            }
        }
        // END workaround
        // setup monitoring
        processMonitor = broker.getBrokerPool().getProcessMonitor();
        xqueryContext.getProfiler().traceQueryStart();
        processMonitor.queryStarted(xqueryContext.getWatchDog());
        // create a function call
        try (final FunctionReference fnRef = new FunctionReference(new FunctionCall(xqueryContext, fn))) {
            // convert the arguments
            final org.exist.xquery.value.Sequence[] fnArgs = convertToExistFunctionArguments(xqueryContext, fn, arguments);
            // execute the function call
            fnRef.analyze(new AnalyzeContextInfo());
            // if setUid/setGid, determine the effectiveSubject to use for execution
            final Optional<EffectiveSubject> effectiveSubject = getEffectiveSubject(xquery);
            try {
                // switch to effective user if setUid/setGid
                effectiveSubject.ifPresent(broker::pushSubject);
                final org.exist.xquery.value.Sequence result = fnRef.evalFunction(null, null, fnArgs);
                // copy for closure
                final CompiledXQuery xquery1 = xquery;
                // return a sequence adapter which returns the query when it is finished with the results
                return new SequenceAdapter(result, () -> {
                    if (xquery1 != null) {
                        // return the compiled query to the pool
                        cache.returnCompiledQuery(resourceFunction.getXQueryLocation(), xquery1);
                    }
                });
            } finally {
                // switch back from effective user if setUid/setGid
                if (effectiveSubject.isPresent()) {
                    broker.popSubject();
                }
            }
        }
    } catch (final URISyntaxException | EXistException | XPathException | PermissionDeniedException use) {
        // if an error occurred we should return the compiled query
        if (xquery != null) {
            // return the compiled query to the pool
            cache.returnCompiledQuery(resourceFunction.getXQueryLocation(), xquery);
        }
        throw new RestXqServiceException(use.getMessage(), use);
    } finally {
        // clear down monitoring
        if (processMonitor != null) {
            xquery.getContext().getProfiler().traceQueryEnd(xquery.getContext());
            processMonitor.queryCompleted(xquery.getContext().getWatchDog());
        }
    }
}
Also used : RestXqServiceCompiledXQueryCache(org.exist.extensions.exquery.restxq.RestXqServiceCompiledXQueryCache) RestXqServiceException(org.exquery.restxq.RestXqServiceException) SequenceAdapter(org.exist.extensions.exquery.restxq.impl.adapters.SequenceAdapter) URISyntaxException(java.net.URISyntaxException) FunctionReference(org.exist.xquery.value.FunctionReference) EffectiveSubject(org.exist.security.EffectiveSubject) org.exist.xquery(org.exist.xquery) ValueSequence(org.exist.xquery.value.ValueSequence) Sequence(org.exquery.xquery.Sequence) EXistException(org.exist.EXistException) ProcessMonitor(org.exist.storage.ProcessMonitor) DBBroker(org.exist.storage.DBBroker) PermissionDeniedException(org.exist.security.PermissionDeniedException)

Example 3 with EffectiveSubject

use of org.exist.security.EffectiveSubject in project exist by eXist-db.

the class XQuery method execute.

public Sequence execute(final DBBroker broker, final CompiledXQuery expression, Sequence contextSequence, final Properties outputProperties, final boolean resetContext) throws XPathException, PermissionDeniedException {
    // check execute permissions
    if (expression.getContext().getSource() instanceof DBSource) {
        ((DBSource) expression.getContext().getSource()).validate(Permission.EXECUTE);
    }
    final long start = System.currentTimeMillis();
    final XQueryContext context = expression.getContext();
    expression.reset();
    if (resetContext) {
        // context.setBroker(broker);
        context.getWatchDog().reset();
    }
    if (context.requireDebugMode()) {
        final Debuggee debuggee = broker.getBrokerPool().getDebuggee();
        if (debuggee != null) {
            debuggee.joint(expression);
        }
    }
    // do any preparation before execution
    context.prepareForExecution();
    final Subject callingUser = broker.getCurrentSubject();
    // if setUid or setGid, become Effective User
    EffectiveSubject effectiveSubject = null;
    final Source src = expression.getContext().getSource();
    if (src instanceof DBSource) {
        final DBSource dbSrc = (DBSource) src;
        final Permission perm = dbSrc.getPermissions();
        if (perm.isSetUid()) {
            if (perm.isSetGid()) {
                // setUid and SetGid
                effectiveSubject = new EffectiveSubject(perm.getOwner(), perm.getGroup());
            } else {
                // just setUid
                effectiveSubject = new EffectiveSubject(perm.getOwner());
            }
        } else if (perm.isSetGid()) {
            // just setGid, so we use the current user as the effective user
            effectiveSubject = new EffectiveSubject(callingUser, perm.getGroup());
        }
    }
    try {
        if (effectiveSubject != null) {
            // switch to effective user (e.g. setuid/setgid)
            broker.pushSubject(effectiveSubject);
        }
        context.getProfiler().traceQueryStart();
        broker.getBrokerPool().getProcessMonitor().queryStarted(context.getWatchDog());
        try {
            // support for XQuery 3.0 - declare context item :=
            if (contextSequence == null) {
                if (context.getContextItemDeclartion() != null) {
                    contextSequence = context.getContextItemDeclartion().eval(null, null);
                }
            }
            final Sequence result = expression.eval(contextSequence);
            if (LOG.isDebugEnabled()) {
                final NumberFormat nf = NumberFormat.getNumberInstance();
                LOG.debug("Execution took {} ms", nf.format(System.currentTimeMillis() - start));
            }
            if (outputProperties != null) {
                // must be done before context.reset!
                context.checkOptions(outputProperties);
            }
            return result;
        } finally {
            context.getProfiler().traceQueryEnd(context);
            // track query stats before context is reset
            broker.getBrokerPool().getProcessMonitor().queryCompleted(context.getWatchDog());
            expression.reset();
            if (resetContext) {
                context.reset();
            }
        }
    } finally {
        if (effectiveSubject != null) {
            broker.popSubject();
        }
    }
}
Also used : EffectiveSubject(org.exist.security.EffectiveSubject) Debuggee(org.exist.debuggee.Debuggee) Permission(org.exist.security.Permission) DBSource(org.exist.source.DBSource) Sequence(org.exist.xquery.value.Sequence) Subject(org.exist.security.Subject) EffectiveSubject(org.exist.security.EffectiveSubject) StringSource(org.exist.source.StringSource) Source(org.exist.source.Source) DBSource(org.exist.source.DBSource) FileSource(org.exist.source.FileSource) NumberFormat(java.text.NumberFormat)

Aggregations

EffectiveSubject (org.exist.security.EffectiveSubject)3 Permission (org.exist.security.Permission)2 DBSource (org.exist.source.DBSource)2 Source (org.exist.source.Source)2 URISyntaxException (java.net.URISyntaxException)1 NumberFormat (java.text.NumberFormat)1 EXistException (org.exist.EXistException)1 Debuggee (org.exist.debuggee.Debuggee)1 RestXqServiceCompiledXQueryCache (org.exist.extensions.exquery.restxq.RestXqServiceCompiledXQueryCache)1 SequenceAdapter (org.exist.extensions.exquery.restxq.impl.adapters.SequenceAdapter)1 PermissionDeniedException (org.exist.security.PermissionDeniedException)1 Subject (org.exist.security.Subject)1 FileSource (org.exist.source.FileSource)1 StringSource (org.exist.source.StringSource)1 DBBroker (org.exist.storage.DBBroker)1 ProcessMonitor (org.exist.storage.ProcessMonitor)1 org.exist.xquery (org.exist.xquery)1 FunctionReference (org.exist.xquery.value.FunctionReference)1 Sequence (org.exist.xquery.value.Sequence)1 ValueSequence (org.exist.xquery.value.ValueSequence)1