All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.telicent.jena.abac.fuseki.FMod_ABAC Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (c) Telicent Ltd.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package io.telicent.jena.abac.fuseki;

import java.util.Collection;
import java.util.Set;
import java.util.function.Function;

import io.telicent.jena.abac.ABAC;
import io.telicent.jena.abac.core.DatasetGraphABAC;
import org.apache.jena.atlas.logging.FmtLog;
import org.apache.jena.fuseki.Fuseki;
import org.apache.jena.fuseki.FusekiException;
import org.apache.jena.fuseki.main.FusekiServer;
import org.apache.jena.fuseki.main.FusekiServer.Builder;
import org.apache.jena.fuseki.main.sys.FusekiModule;
import org.apache.jena.fuseki.server.*;
import org.apache.jena.fuseki.servlets.ActionProcessor;
import org.apache.jena.fuseki.servlets.HttpAction;
import org.apache.jena.rdf.model.*;
import org.apache.jena.sparql.core.DatasetGraph;
import org.slf4j.Logger;

/**
 * Fuseki module for ABAC. This module looks for {@link DatasetGraphABAC} and ensures
 * certain operations are the correct ones that apply ABAC security.
 * {@code Operation.Query}, {@code Operation.GSP_R}, {@code Operation.Upload}.
 * 

* Data change operations -- {@code Operation.Update} and {@code Operation.Patch} -- * generate warnings. These are best handled as a separate data service, with its own * API authorization setup, that modify the underlying database. */ public class FMod_ABAC implements FusekiModule { public static int LEVEL = 100; private final static Logger LOG = ABAC.AzLOG; private static void init() { SysFusekiABAC.init(); } private final Function getUser; public FMod_ABAC() { this(ServerABAC.userForRequest()); } private FMod_ABAC(Function getUser) { this.getUser = getUser; init(); } @Override public String name() { return "RDF ABAC"; } @Override public void prepare(FusekiServer.Builder serverBuilder, Set datasetNames, Model configModel) { FmtLog.info(Fuseki.configLog, "ABAC Fuseki Module"); // Operation registration needs to be in InitFusekiABAC/SysFusekiABAC // because parsing a config file involves checks which touchthese constants. // i.e. do not call "serverBuilder.registerOperation(operation, handler)" here. for ( String name : datasetNames ) { prepare1(serverBuilder, name, configModel); } } // Inspect the configuration. private void prepare1(Builder serverBuilder, String name, Model configModel) { if ( configModel == null ) return; DatasetGraph dsg = serverBuilder.getDataset(name); if ( dsg == null ) return; if ( dsg instanceof DatasetGraphABAC dsgz) { FmtLog.info(LOG, "ABAC Dataset: %s", name); FmtLog.info(LOG, " Default label: %s", display(dsgz.getDefaultLabel())); FmtLog.info(LOG, " Access attr : %s", display(dsgz.getAccessAttributes())); } } private String display(Object value) { if ( value != null ) return value.toString(); return "not set"; } @Override public void configDataAccessPoint(DataAccessPoint dap, Model configModel) { DatasetGraph dsg = dap.getDataService().getDataset(); if ( ! ( dsg instanceof DatasetGraphABAC ) ) { // Not ABAC. return; } // Replace the standard query handler and upload functions for this DataService ActionProcessor procQuery = new ABAC_SPARQL_QueryDataset(getUser); ActionProcessor procGSPR = new ABAC_GSP_R(getUser); ActionProcessor procUpload = new ABAC_ChangeDispatch(); // Replace standard processors with ABAC ones. replaceOperation(dap, Operation.Query, procQuery); replaceOperation(dap, Operation.GSP_R, procGSPR); replaceOperation(dap, Operation.Upload, procUpload); // Warn about the use of these operations. warnOperation(dap, Operation.Update); warnOperation(dap, Operation.Patch); } private void replaceOperation(DataAccessPoint dap, Operation operation, ActionProcessor proc) { DataService dataService = dap.getDataService(); dataService.getEndpoints(operation).forEach(ep->{ // Endpoint ep2 = Endpoint.create() // .operation(ep.getOperation()) // .processor(proc) // .endpointName(ep.getName()) // .build(); // Mutates the endpoint. ep.setProcessor(proc); }); } private void warnOperation(DataAccessPoint dap, Operation operation) { DataService dataService = dap.getDataService(); dataService.getEndpoints(operation).forEach(ep->{ FmtLog.warn(Fuseki.configLog, "Update operation for DatasetGraphABAC mnot recommended"); }); } // Reverse lookup: find the resource for the registry entry name in the configuration file. private Resource findDatasetResource(String name, Model configModel) { StmtIterator sIter = configModel.listStatements(null, FusekiVocab.pServiceName, ResourceFactory.createPlainLiteral(name)); // If not found try by canonical name, try again non-canonical (or SPARQL query) if ( ! sIter.hasNext() && DataAccessPoint.isCanonical(name)) { String name2 = name.substring(1); sIter = configModel.listStatements(null, FusekiVocab.pServiceName, ResourceFactory.createPlainLiteral(name2)); } try { if ( sIter.hasNext() ) { Statement s = sIter.next(); if ( sIter.hasNext() ) throw new FusekiException("Multiple endpoints for name '+name+'"); Resource subject = s.getSubject(); return subject; } throw new FusekiException("Can't find the dataset in the configuration: '"+name+"'") ; } finally { sIter.close(); } } /** Check the server */ @Override public void server(FusekiServer server) { server.getDataAccessPointRegistry().forEach((name,dap) -> { DatasetGraph dsg = dap.getDataService().getDataset(); if ( dsg instanceof DatasetGraphABAC ) checkDataset(dap); }); } // Check ActionProcessors are authorization ones. private void checkDataset(DataAccessPoint dap) { Collection endpoints = dap.getDataService().getEndpoints(); endpoints.forEach(ep->{ ActionProcessor proc = ep.getProcessor(); if ( proc != null && ! isAuthzProcessor(proc) ) { FmtLog.warn(Fuseki.configLog, "%s: Non-authorization operation processor on DatasetGraphAuthz: class %s", dap.getName(), proc.getClass().getSimpleName()); } }); } private boolean isAuthzProcessor(ActionProcessor proc) { return (proc instanceof ABAC_Processor); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy