Skip to content
Merged
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
66 changes: 66 additions & 0 deletions http-tests/proxy/GET-proxied-ontology-ns.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -euo pipefail

initialize_dataset "$END_USER_BASE_URL" "$TMP_END_USER_DATASET" "$END_USER_ENDPOINT_URL"
initialize_dataset "$ADMIN_BASE_URL" "$TMP_ADMIN_DATASET" "$ADMIN_ENDPOINT_URL"
purge_cache "$END_USER_VARNISH_SERVICE"
purge_cache "$ADMIN_VARNISH_SERVICE"
purge_cache "$FRONTEND_VARNISH_SERVICE"

# add agent to the readers group to be able to read documents

add-agent-to-group.sh \
-f "$OWNER_CERT_FILE" \
-p "$OWNER_CERT_PWD" \
--agent "$AGENT_URI" \
"${ADMIN_BASE_URL}acl/groups/readers/"

# use a made-up hash-based namespace: not mapped as a static file, not a registered app
namespace_uri="http://made-up-test-ns.example/ns"
class1="${namespace_uri}#ClassOne"
class2="${namespace_uri}#ClassTwo"
ontology_doc="${ADMIN_BASE_URL}ontologies/namespace/"
namespace="${END_USER_BASE_URL}ns#"

# add two classes with URIs in the made-up namespace to the app's ontology

add-class.sh \
-f "$OWNER_CERT_FILE" \
-p "$OWNER_CERT_PWD" \
-b "$ADMIN_BASE_URL" \
--uri "$class1" \
--label "Class One" \
"$ontology_doc"

add-class.sh \
-f "$OWNER_CERT_FILE" \
-p "$OWNER_CERT_PWD" \
-b "$ADMIN_BASE_URL" \
--uri "$class2" \
--label "Class Two" \
"$ontology_doc"

# clear the in-memory ontology so the new classes are present on next request

clear-ontology.sh \
-f "$OWNER_CERT_FILE" \
-p "$OWNER_CERT_PWD" \
-b "$ADMIN_BASE_URL" \
--ontology "$namespace"

# request the namespace document URI (without fragment) via ?uri= proxy.
# the namespace document is not DataManager-mapped and not a registered app,
# so ProxyRequestFilter falls through to the OntModel DESCRIBE path, which
# returns descriptions of all #-fragment terms in that namespace.

response=$(curl -k -f -s \
-G \
-E "$AGENT_CERT_FILE":"$AGENT_CERT_PWD" \
-H "Accept: application/n-triples" \
--data-urlencode "uri=${namespace_uri}" \
"$END_USER_BASE_URL")

# verify both class descriptions are present in the response

echo "$response" | grep -q "$class1"
echo "$response" | grep -q "$class2"
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.atomgraph.core.util.ModelUtils;
import com.atomgraph.core.util.ResultSetUtils;
import com.atomgraph.linkeddatahub.apps.model.Dataset;
import org.apache.jena.ontology.Ontology;
import com.atomgraph.linkeddatahub.client.GraphStoreClient;
import com.atomgraph.linkeddatahub.client.filter.auth.IDTokenDelegationFilter;
import com.atomgraph.linkeddatahub.client.filter.auth.WebIDDelegationFilter;
Expand All @@ -36,6 +37,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.query.QueryFactory;
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotAcceptableException;
Expand Down Expand Up @@ -91,6 +94,7 @@ public class ProxyRequestFilter implements ContainerRequestFilter

@Inject com.atomgraph.linkeddatahub.Application system;
@Inject MediaTypes mediaTypes;
@Inject jakarta.inject.Provider<Optional<Ontology>> ontology;
@Context Request request;

@Override
Expand Down Expand Up @@ -123,6 +127,26 @@ public void filter(ContainerRequestContext requestContext) throws IOException
return;
}

// serve terms from the app's in-memory namespace ontology (full imports closure) via DESCRIBE.
// covers both slash-based term URIs (e.g. schema:category) and hash-based namespaces
// (e.g. sioc:UserAccount → ac:document-uri strips to sioc:ns, so we also describe all
// ?term where STR(?term) starts with "<targetURI>#")
if (getOntology().isPresent())
{
String describeQueryStr = "DESCRIBE <" + targetURI + "> ?term " +
"WHERE { ?term ?p ?o FILTER(STRSTARTS(STR(?term), CONCAT(STR(<" + targetURI + ">), \"#\"))) }";
try (QueryExecution qe = QueryExecution.create(QueryFactory.create(describeQueryStr), getOntology().get().getOntModel()))
{
Model description = qe.execDescribe();
if (!description.isEmpty())
{
if (log.isDebugEnabled()) log.debug("Serving URI from namespace ontology: {}", targetURI);
requestContext.abortWith(getResponse(description, Response.Status.OK));
return;
}
}
}

boolean isRegisteredApp = getSystem().matchApp(targetURI) != null;
if (!isRegisteredApp && !getSystem().isEnableLinkedDataProxy())
throw new NotAllowedException("Linked Data proxy not enabled");
Expand Down Expand Up @@ -312,6 +336,16 @@ public com.atomgraph.linkeddatahub.Application getSystem()
return system;
}

/**
* Returns the current application's namespace ontology, if available.
*
* @return optional ontology
*/
public Optional<Ontology> getOntology()
{
return ontology.get();
}

/**
* Returns the media types registry.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.atomgraph.client.MediaTypes;
import com.atomgraph.client.util.DataManager;
import com.atomgraph.linkeddatahub.server.security.AgentContext;
import org.apache.jena.ontology.Ontology;
import com.atomgraph.linkeddatahub.server.util.URLValidator;
import com.atomgraph.linkeddatahub.vocabulary.LAPP;
import jakarta.ws.rs.NotAllowedException;
Expand All @@ -34,6 +35,7 @@
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Optional;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Resource;
Expand All @@ -60,6 +62,7 @@ public class ProxyRequestFilterTest
@Mock com.atomgraph.linkeddatahub.Application system;
@Mock MediaTypes mediaTypes;
@Mock Request request;
@Mock Ontology ontology;

@InjectMocks ProxyRequestFilter filter;

Expand All @@ -85,6 +88,7 @@ public void setUp()
when(system.getDataManager()).thenReturn(dataManager);
when(dataManager.isMapped(anyString())).thenReturn(false);
when(system.isEnableLinkedDataProxy()).thenReturn(false);
filter.ontology = () -> Optional.empty();
}

/**
Expand Down
Loading