├── .gitignore ├── NOTICE ├── .github └── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── README.md ├── src ├── test │ └── java │ │ └── com │ │ └── amazonaws │ │ └── neptune │ │ ├── integration │ │ ├── NeptuneRdf4JIntegrationTest.java │ │ └── NeptuneJenaIntegrationTest.java │ │ ├── NeptuneSPARQLConnectionIntegrationTestUtil.java │ │ └── client │ │ ├── rdf4j │ │ └── NeptuneSparqlRepositoryTest.java │ │ └── jena │ │ └── AwsSigningHttpClientTest.java └── main │ └── java │ └── com │ └── amazonaws │ └── neptune │ └── client │ ├── rdf4j │ ├── NeptuneRdf4JSigV4Example.java │ └── NeptuneSparqlRepository.java │ └── jena │ ├── NeptuneJenaSigV4Example.java │ └── AwsSigningHttpClient.java ├── CONTRIBUTING.md ├── COPYING ├── LICENSE └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.iml 3 | *.idea 4 | 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Amazon Neptune Sparql Java Sigv4 2 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Amazon Neptune Sparql Java Sigv4 2 | 3 | A SPARQL client for [Amazon Neptune](https://aws.amazon.com/neptune) that includes AWS Signature Version 4 signing. Implemented as an RDF4J repository and Jena HTTP Client. This library relies on [amazon-neptune-sigv4-signer](https://github.com/aws/amazon-neptune-sigv4-signer/). 4 | 5 | For example usage refer to: 6 | 7 | - [NeptuneJenaSigV4Example.java](https://github.com/aws/amazon-neptune-sparql-java-sigv4/blob/master/src/main/java/com/amazonaws/neptune/client/jena/NeptuneJenaSigV4Example.java) 8 | - [NeptuneRdf4JSigV4Example.java](https://github.com/aws/amazon-neptune-sparql-java-sigv4/blob/master/src/main/java/com/amazonaws/neptune/client/rdf4j/NeptuneRdf4JSigV4Example.java) 9 | 10 | For the official Amazon Neptune page refer to: https://aws.amazon.com/neptune 11 | 12 | ## License 13 | 14 | This library is licensed under the Apache 2.0 License. 15 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/neptune/integration/NeptuneRdf4JIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.integration; 17 | 18 | import com.amazonaws.neptune.client.rdf4j.NeptuneSparqlRepository; 19 | import org.eclipse.rdf4j.query.TupleQuery; 20 | import org.eclipse.rdf4j.query.Update; 21 | import org.eclipse.rdf4j.repository.Repository; 22 | import org.eclipse.rdf4j.repository.RepositoryConnection; 23 | import org.junit.jupiter.api.AfterEach; 24 | import org.junit.jupiter.api.BeforeEach; 25 | import org.junit.jupiter.api.Test; 26 | import org.junit.jupiter.api.condition.EnabledIfSystemProperty; 27 | import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; 28 | 29 | import java.util.UUID; 30 | 31 | import static com.amazonaws.neptune.NeptuneSPARQLConnectionIntegrationTestUtil.getInsertQuery; 32 | import static com.amazonaws.neptune.NeptuneSPARQLConnectionIntegrationTestUtil.getSelectQuery; 33 | import static org.junit.jupiter.api.Assertions.*; 34 | 35 | @EnabledIfSystemProperty(named = "neptune.endpoint", matches = ".*") 36 | class NeptuneRdf4JIntegrationTest { 37 | 38 | private Repository repository; 39 | private String testGraphUri; 40 | String neptuneEndpoint = System.getProperty("neptune.endpoint").concat("/sparql"); 41 | String regionName = System.getProperty("aws.region", "us-west-1"); 42 | 43 | @BeforeEach 44 | void setUp() throws Exception { 45 | 46 | repository = new NeptuneSparqlRepository( 47 | neptuneEndpoint, 48 | DefaultCredentialsProvider.builder().build(), 49 | regionName 50 | ); 51 | repository.init(); 52 | 53 | testGraphUri = "http://neptune.aws.com/ontology/testing/" + UUID.randomUUID(); 54 | } 55 | 56 | @Test 57 | void testInsertAndQueryWithRdf4J(){ 58 | 59 | try (RepositoryConnection conn = repository.getConnection()) { 60 | // Insert test data 61 | Update update = conn.prepareUpdate(getInsertQuery(testGraphUri)); 62 | update.execute(); 63 | System.out.println("✓ RDF4J Insert completed successfully"); 64 | 65 | // Query and verify data 66 | TupleQuery tupleQuery = conn.prepareTupleQuery(getSelectQuery(testGraphUri)); 67 | 68 | long resultCount = tupleQuery.evaluate().stream().count(); 69 | 70 | assertEquals(1, resultCount, "Should find exactly 1 result"); 71 | 72 | } catch (Exception e) { 73 | fail("RDF4J Insert and Query test failed: " + e.getMessage()); 74 | } 75 | } 76 | 77 | @AfterEach 78 | void tearDown() { 79 | String deleteQuery = String.format("DROP GRAPH <%s>", testGraphUri); 80 | 81 | try (RepositoryConnection conn = repository.getConnection()) { 82 | Update update = conn.prepareUpdate(deleteQuery); 83 | update.execute(); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/neptune/NeptuneSPARQLConnectionIntegrationTestUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune; 17 | 18 | /** 19 | * Base class providing utility methods for Neptune integration tests. 20 | *

21 | * This class contains helper methods for generating common SPARQL queries 22 | * used in integration testing with Amazon Neptune. It provides standardized 23 | * query templates for inserting, selecting, and clearing test data. 24 | *

25 | * The queries use named graphs to isolate test data and avoid conflicts 26 | * between different test runs or test methods. 27 | * 28 | * @author AWS Neptune Team 29 | * @since 1.0 30 | */ 31 | public class NeptuneSPARQLConnectionIntegrationTestUtil { 32 | 33 | /** 34 | * Generates a SPARQL INSERT query for adding test data to a named graph. 35 | *

36 | * Creates a simple triple with test URNs that can be used to verify 37 | * that data insertion operations are working correctly. 38 | * 39 | * @param namedGraph the URI of the named graph where data should be inserted 40 | * @return a SPARQL INSERT DATA query string 41 | */ 42 | public static String getInsertQuery(String namedGraph) { 43 | return String.format( 44 | "INSERT DATA {" + 45 | " GRAPH <%s> {" + 46 | " " + // Simple test triple 47 | " }" + 48 | "}", namedGraph); 49 | } 50 | 51 | /** 52 | * Generates a SPARQL SELECT query for retrieving all triples from a named graph. 53 | *

54 | * Returns all subject-predicate-object triples stored in the specified 55 | * named graph, useful for verifying that data was inserted correctly. 56 | * 57 | * @param namedGraph the URI of the named graph to query 58 | * @return a SPARQL SELECT query string that retrieves all triples from the graph 59 | */ 60 | public static String getSelectQuery(String namedGraph) { 61 | return String.format( 62 | "SELECT * {" + 63 | " GRAPH <%s> {" + 64 | " ?s ?p ?o " + // Select all triples in the graph 65 | " }" + 66 | "}", namedGraph); 67 | } 68 | 69 | /** 70 | * Generates a SPARQL CLEAR query for removing all data from a named graph. 71 | *

72 | * Removes all triples from the specified named graph, useful for cleaning 73 | * up test data after test execution to ensure test isolation. 74 | * 75 | * @param namedGraph the URI of the named graph to clear 76 | * @return a SPARQL CLEAR GRAPH query string 77 | */ 78 | public static String getClearQuery(String namedGraph) { 79 | return String.format( 80 | "CLEAR GRAPH <%s>", namedGraph); // Remove all triples from the graph 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws/amazon-neptune-sparql-java-sigv4/issues), or [recently closed](https://github.com/aws/amazon-neptune-sparql-java-sigv4/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/amazon-neptune-sparql-java-sigv4/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/aws/amazon-neptune-sparql-java-sigv4/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/neptune/client/rdf4j/NeptuneRdf4JSigV4Example.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.client.rdf4j; 17 | 18 | import com.amazonaws.neptune.auth.NeptuneSigV4SignerException; 19 | import org.eclipse.rdf4j.query.BindingSet; 20 | import org.eclipse.rdf4j.query.TupleQueryResult; 21 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 22 | import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; 23 | 24 | /** 25 | * Example demonstrating how to connect to Amazon Neptune using Eclipse RDF4J with AWS Signature V4 authentication. 26 | *

27 | * This example shows how to: 28 | *

33 | *

34 | * The example uses the default AWS credentials provider, which will automatically 35 | * discover credentials from the environment, AWS profiles, or IAM roles. 36 | * 37 | * @author AWS Neptune Team 38 | * @since 1.0 39 | */ 40 | public class NeptuneRdf4JSigV4Example { 41 | 42 | /** 43 | * Main method demonstrating Neptune connection with RDF4J and AWS Signature V4. 44 | *

45 | * Requires two command line arguments: endpoint URL and region name. 46 | * Ensure your AWS credentials are properly configured in your environment. 47 | *

48 | * Example usage: 49 | * {@code java NeptuneRdf4JSigV4Example https://my-cluster.cluster-xyz.us-west-2.neptune.amazonaws.com:8182/sparql us-west-2} 50 | * 51 | * @param args command line arguments: [0] endpoint URL, [1] region name 52 | * @throws NeptuneSigV4SignerException if there's an error with AWS signature signing 53 | */ 54 | public static void main(final String[] args) throws NeptuneSigV4SignerException { 55 | if (args.length < 2) { 56 | System.err.println("Usage: java NeptuneRdf4JSigV4Example "); 57 | System.exit(1); 58 | } 59 | 60 | final String endpointUrl = args[0]; 61 | final String regionName = args[1]; 62 | 63 | // Use default AWS credentials provider (checks environment, profiles, IAM roles) 64 | final AwsCredentialsProvider awsCredentialsProvider = DefaultCredentialsProvider.create(); 65 | 66 | // Create Neptune SPARQL repository with AWS Signature V4 authentication 67 | final NeptuneSparqlRepository repository = new NeptuneSparqlRepository( 68 | endpointUrl, 69 | awsCredentialsProvider, 70 | regionName 71 | ); 72 | 73 | // Sample SPARQL query to retrieve triples 74 | final String queryString = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"; 75 | 76 | // Execute the query and get results 77 | final TupleQueryResult result = repository.getConnection().prepareTupleQuery(queryString).evaluate(); 78 | 79 | // Process and print each result binding 80 | while (result.hasNext()) { 81 | final BindingSet bindingSet = result.next(); 82 | System.out.println(bindingSet); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/neptune/client/jena/NeptuneJenaSigV4Example.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.client.jena; 17 | 18 | import org.apache.jena.rdfconnection.RDFConnection; 19 | import org.apache.jena.rdfconnection.RDFConnectionRemote; 20 | import org.apache.jena.rdfconnection.RDFConnectionRemoteBuilder; 21 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 22 | import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; 23 | import software.amazon.awssdk.regions.Region; 24 | 25 | import java.net.http.HttpClient; 26 | 27 | /** 28 | * Example demonstrating how to connect to Amazon Neptune using Apache Jena with AWS Signature V4 authentication. 29 | *

30 | * This example shows how to: 31 | *

36 | *

37 | * The example uses the default AWS credentials provider, which will automatically 38 | * discover credentials from the environment, AWS profiles, or IAM roles. 39 | * 40 | * @author AWS Neptune Team 41 | * @since 1.0 42 | */ 43 | public class NeptuneJenaSigV4Example { 44 | 45 | /** 46 | * Main method demonstrating Neptune connection with Jena and AWS Signature V4. 47 | *

48 | * Requires two command line arguments: endpoint URL and region name. 49 | * Ensure your AWS credentials are properly configured in your environment. 50 | *

51 | * Example usage: 52 | * {@code java NeptuneJenaSigV4Example https://my-cluster.cluster-xyz.us-west-2.neptune.amazonaws.com:8182 us-west-2} 53 | * 54 | * @param args command line arguments: [0] endpoint URL, [1] region name 55 | */ 56 | public static void main(String... args) { 57 | if (args.length < 2) { 58 | System.err.println("Usage: java NeptuneJenaSigV4Example "); 59 | System.exit(1); 60 | } 61 | 62 | final String endpoint = args[0]; 63 | final String regionName = args[1]; 64 | 65 | // Use default AWS credentials provider (checks environment, profiles, IAM roles) 66 | final AwsCredentialsProvider awsCredentialsProvider = DefaultCredentialsProvider.builder().build(); 67 | 68 | // Sample SPARQL query to retrieve triples 69 | String query = "SELECT * { ?s ?p ?o } LIMIT 100"; 70 | 71 | // Create signing HTTP client for Neptune authentication 72 | HttpClient signingClient = new AwsSigningHttpClient( 73 | "neptune-db", // AWS service name for Neptune 74 | Region.of(regionName), 75 | awsCredentialsProvider, 76 | query 77 | ); 78 | 79 | // Build Jena RDF connection with the signing client 80 | RDFConnectionRemoteBuilder builder = RDFConnectionRemote.create() 81 | .httpClient(signingClient) 82 | .destination(endpoint) 83 | .queryEndpoint("sparql") // Neptune SPARQL query endpoint 84 | .updateEndpoint("sparql"); // Neptune SPARQL update endpoint 85 | 86 | // Execute the query using try-with-resources for automatic connection cleanup 87 | try (RDFConnection conn = builder.build()) { 88 | System.out.println("> Printing query result: "); 89 | conn.querySelect(query, System.out::println); 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/neptune/client/rdf4j/NeptuneSparqlRepositoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.client.rdf4j; 17 | 18 | import com.amazonaws.neptune.auth.NeptuneSigV4SignerException; 19 | import org.junit.jupiter.api.Test; 20 | import org.mockito.Mock; 21 | import org.mockito.MockitoAnnotations; 22 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; 23 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 24 | 25 | import static org.junit.jupiter.api.Assertions.*; 26 | import static org.mockito.Mockito.when; 27 | 28 | /** 29 | * Unit tests for NeptuneSparqlRepository. 30 | *

31 | * Tests both authenticated and unauthenticated repository configurations. 32 | */ 33 | class NeptuneSparqlRepositoryTest { 34 | 35 | @Mock 36 | private AwsCredentialsProvider mockCredentialsProvider; 37 | 38 | private final String testEndpoint = "https://test-cluster.cluster-xyz.us-east-1.neptune.amazonaws.com:8182"; 39 | private final String testRegion = "us-east-1"; 40 | 41 | @Test 42 | void testAuthenticatedRepositoryCreation() throws NeptuneSigV4SignerException { 43 | MockitoAnnotations.openMocks(this); 44 | 45 | // Mock credentials provider 46 | when(mockCredentialsProvider.resolveCredentials()) 47 | .thenReturn(AwsBasicCredentials.create("test-access-key", "test-secret-key")); 48 | 49 | // Test creating repository with authentication 50 | NeptuneSparqlRepository repository = new NeptuneSparqlRepository( 51 | testEndpoint, 52 | mockCredentialsProvider, 53 | testRegion 54 | ); 55 | 56 | assertNotNull(repository); 57 | assertEquals(testEndpoint , repository.toString()); 58 | } 59 | 60 | @Test 61 | void testNullEndpointThrowsException() { 62 | // Test that null endpoint throws appropriate exception 63 | assertThrows(Exception.class, () -> { 64 | new NeptuneSparqlRepository(null); 65 | }); 66 | } 67 | 68 | @Test 69 | void testNullCredentialsProviderThrowsException() { 70 | // Test that null credentials provider throws exception for authenticated repository 71 | assertThrows(Exception.class, () -> { 72 | new NeptuneSparqlRepository(testEndpoint, null, testRegion); 73 | }); 74 | } 75 | 76 | @Test 77 | void testNullRegionThrowsException() { 78 | MockitoAnnotations.openMocks(this); 79 | 80 | when(mockCredentialsProvider.resolveCredentials()) 81 | .thenReturn(AwsBasicCredentials.create("test-access-key", "test-secret-key")); 82 | 83 | // Test that null region throws exception for authenticated repository 84 | assertThrows(Exception.class, () -> { 85 | new NeptuneSparqlRepository(testEndpoint, mockCredentialsProvider, null); 86 | }); 87 | } 88 | 89 | @Test 90 | void testRepositoryConnection() { 91 | // Test that repository can provide connections 92 | NeptuneSparqlRepository repository = new NeptuneSparqlRepository(testEndpoint); 93 | 94 | assertDoesNotThrow(() -> { 95 | // This would normally connect to Neptune, but in unit tests we just verify no exceptions 96 | var connection = repository.getConnection(); 97 | assertNotNull(connection); 98 | connection.close(); 99 | }); 100 | } 101 | 102 | @Test 103 | void testRepositoryInitialization() { 104 | NeptuneSparqlRepository repository = new NeptuneSparqlRepository(testEndpoint); 105 | 106 | // Test repository initialization 107 | assertDoesNotThrow(() -> { 108 | repository.init(); 109 | assertTrue(repository.isInitialized()); 110 | }); 111 | } 112 | 113 | @Test 114 | void testRepositoryShutdown() { 115 | NeptuneSparqlRepository repository = new NeptuneSparqlRepository(testEndpoint); 116 | 117 | // Test repository shutdown 118 | assertDoesNotThrow(() -> { 119 | repository.init(); 120 | repository.shutDown(); 121 | }); 122 | } 123 | } -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/neptune/client/jena/AwsSigningHttpClientTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.client.jena; 17 | 18 | import org.junit.jupiter.api.BeforeEach; 19 | import org.junit.jupiter.api.Test; 20 | import org.mockito.Mock; 21 | import org.mockito.MockitoAnnotations; 22 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; 23 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 24 | import software.amazon.awssdk.regions.Region; 25 | 26 | import java.io.IOException; 27 | import java.net.URI; 28 | import java.net.http.HttpRequest; 29 | import java.net.http.HttpResponse; 30 | import java.time.Duration; 31 | 32 | import static org.junit.jupiter.api.Assertions.*; 33 | import static org.mockito.Mockito.when; 34 | 35 | /** 36 | * Unit tests for AwsSigningHttpClient. 37 | *

38 | * Tests the AWS Signature V4 signing functionality and HTTP client delegation behavior. 39 | */ 40 | class AwsSigningHttpClientTest { 41 | 42 | @Mock 43 | private AwsCredentialsProvider mockCredentialsProvider; 44 | 45 | private AwsSigningHttpClient signingClient; 46 | private final String testRequestBody = "SELECT * { ?s ?p ?o } LIMIT 10"; 47 | private final Region testRegion = Region.US_EAST_1; 48 | private final String serviceName = "neptune-db"; 49 | 50 | @BeforeEach 51 | void setUp() { 52 | MockitoAnnotations.openMocks(this); 53 | 54 | // Mock credentials provider 55 | when(mockCredentialsProvider.resolveCredentials()) 56 | .thenReturn(AwsBasicCredentials.create("test-access-key", "test-secret-key")); 57 | 58 | signingClient = new AwsSigningHttpClient( 59 | serviceName, 60 | testRegion, 61 | mockCredentialsProvider, 62 | testRequestBody 63 | ); 64 | } 65 | 66 | @Test 67 | void testDelegateMethodsReturnNonNull() { 68 | // Test that delegate methods return expected values 69 | assertNotNull(signingClient.cookieHandler()); 70 | assertNotNull(signingClient.followRedirects()); 71 | assertNotNull(signingClient.proxy()); 72 | assertNotNull(signingClient.sslContext()); 73 | assertNotNull(signingClient.sslParameters()); 74 | assertNotNull(signingClient.authenticator()); 75 | assertNotNull(signingClient.version()); 76 | assertNotNull(signingClient.executor()); 77 | } 78 | 79 | @Test 80 | void testSendWithValidRequest() throws IOException, InterruptedException { 81 | // Create a simple GET request for testing 82 | HttpRequest request = HttpRequest.newBuilder() 83 | .uri(URI.create("https://example.com/sparql")) 84 | .GET() 85 | .build(); 86 | 87 | HttpResponse.BodyHandler bodyHandler = HttpResponse.BodyHandlers.ofString(); 88 | 89 | // This test verifies that the method doesn't throw exceptions 90 | // In a real scenario, this would make an actual HTTP call 91 | assertDoesNotThrow(() -> { 92 | try { 93 | signingClient.send(request, bodyHandler); 94 | } catch (IOException | InterruptedException e) { 95 | // Expected for mock/test scenarios where no actual server exists 96 | assertTrue(e.getMessage().contains("example.com") || 97 | e.getMessage().contains("Connection") || 98 | e.getMessage().contains("resolve")); 99 | } 100 | }); 101 | } 102 | 103 | @Test 104 | void testSendAsyncWithValidRequest() { 105 | HttpRequest request = HttpRequest.newBuilder() 106 | .uri(URI.create("https://example.com/sparql")) 107 | .POST(HttpRequest.BodyPublishers.ofString(testRequestBody)) 108 | .build(); 109 | 110 | HttpResponse.BodyHandler bodyHandler = HttpResponse.BodyHandlers.ofString(); 111 | 112 | // Test that sendAsync returns a CompletableFuture 113 | assertDoesNotThrow(() -> { 114 | var future = signingClient.sendAsync(request, bodyHandler); 115 | assertNotNull(future); 116 | }); 117 | } 118 | 119 | @Test 120 | void testSendAsyncWithPushPromiseHandler() { 121 | HttpRequest request = HttpRequest.newBuilder() 122 | .uri(URI.create("https://example.com/sparql")) 123 | .POST(HttpRequest.BodyPublishers.ofString(testRequestBody)) 124 | .build(); 125 | 126 | HttpResponse.BodyHandler bodyHandler = HttpResponse.BodyHandlers.ofString(); 127 | 128 | // Test that sendAsync with null push promise handler returns a CompletableFuture 129 | assertDoesNotThrow(() -> { 130 | var future = signingClient.sendAsync(request, bodyHandler, null); 131 | assertNotNull(future); 132 | }); 133 | } 134 | 135 | @Test 136 | void testRequestWithEmptyBody() { 137 | HttpRequest request = HttpRequest.newBuilder() 138 | .uri(URI.create("https://example.com/sparql")) 139 | .GET() 140 | .build(); 141 | 142 | // Test that requests without body are handled correctly 143 | assertDoesNotThrow(() -> { 144 | try { 145 | signingClient.send(request, HttpResponse.BodyHandlers.ofString()); 146 | } catch (IOException | InterruptedException e) { 147 | // Expected for test scenarios 148 | assertTrue(e.getMessage().contains("example.com") || 149 | e.getMessage().contains("Connection") || 150 | e.getMessage().contains("resolve")); 151 | } 152 | }); 153 | } 154 | 155 | @Test 156 | void testRequestWithHeaders() { 157 | HttpRequest request = HttpRequest.newBuilder() 158 | .uri(URI.create("https://example.com/sparql")) 159 | .header("Content-Type", "application/sparql-query") 160 | .header("Accept", "application/sparql-results+json") 161 | .POST(HttpRequest.BodyPublishers.ofString(testRequestBody)) 162 | .build(); 163 | 164 | // Test that requests with custom headers are handled correctly 165 | assertDoesNotThrow(() -> { 166 | try { 167 | signingClient.send(request, HttpResponse.BodyHandlers.ofString()); 168 | } catch (IOException | InterruptedException e) { 169 | // Expected for test scenarios 170 | assertTrue(e.getMessage().contains("example.com") || 171 | e.getMessage().contains("Connection") || 172 | e.getMessage().contains("resolve")); 173 | } 174 | }); 175 | } 176 | } -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/neptune/client/rdf4j/NeptuneSparqlRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.client.rdf4j; 17 | 18 | import com.amazonaws.neptune.auth.NeptuneApacheHttpSigV4Signer; 19 | import com.amazonaws.neptune.auth.NeptuneSigV4Signer; 20 | import com.amazonaws.neptune.auth.NeptuneSigV4SignerException; 21 | import org.apache.http.HttpException; 22 | import org.apache.http.HttpRequestInterceptor; 23 | import org.apache.http.client.HttpClient; 24 | import org.apache.http.client.methods.HttpUriRequest; 25 | import org.apache.http.impl.client.HttpClientBuilder; 26 | import org.eclipse.rdf4j.repository.sparql.SPARQLRepository; 27 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 28 | 29 | 30 | /** 31 | * SPARQL repository implementation for connecting to Amazon Neptune instances. 32 | *

33 | * This repository extends Eclipse RDF4J's SPARQLRepository to provide seamless integration 34 | * with Amazon Neptune databases. It supports both authenticated and unauthenticated connections: 35 | *

41 | *

42 | * For authenticated connections, the repository automatically signs HTTP requests using 43 | * AWS Signature V4 as described in the 44 | * AWS documentation. 45 | *

46 | * Usage Examples: 47 | *

{@code
 48 |  * // Unauthenticated connection
 49 |  * NeptuneSparqlRepository repo = new NeptuneSparqlRepository("https://my-neptune-cluster:8182");
 50 |  * 
 51 |  * // Authenticated connection
 52 |  * NeptuneSparqlRepository repo = new NeptuneSparqlRepository(
 53 |  *     "https://my-neptune-cluster:8182",
 54 |  *     DefaultCredentialsProvider.create(),
 55 |  *     "us-east-1"
 56 |  * );
 57 |  * }
58 | * 59 | * @author AWS Neptune Team 60 | * @since 1.0 61 | */ 62 | public class NeptuneSparqlRepository extends SPARQLRepository { 63 | 64 | /** 65 | * The name of the region in which Neptune is running. 66 | */ 67 | private final String regionName; 68 | 69 | /** 70 | * Whether authentication is enabled. 71 | */ 72 | private final boolean authenticationEnabled; 73 | 74 | /** 75 | * The credentials provider, offering credentials for signing the request. 76 | */ 77 | private final AwsCredentialsProvider awsCredentialsProvider; 78 | 79 | /** 80 | * The signature V4 signer used to sign the request. 81 | */ 82 | private NeptuneSigV4Signer v4Signer; 83 | 84 | /** 85 | * Creates a Neptune SPARQL repository without authentication. 86 | *

87 | * Use this constructor for Neptune instances that don't require IAM authentication. 88 | * The repository will connect directly to the Neptune SPARQL endpoint without 89 | * adding any AWS signature headers. 90 | * 91 | * @param endpointUrl the fully qualified Neptune cluster endpoint URL 92 | * (e.g., "https://my-cluster.cluster-xyz.us-east-1.neptune.amazonaws.com:8182/sparql") 93 | */ 94 | public NeptuneSparqlRepository(final String endpointUrl) { 95 | super(endpointUrl); 96 | // all the fields below are only relevant for authentication and can be ignored 97 | this.authenticationEnabled = false; 98 | this.awsCredentialsProvider = null; // only needed if auth is enabled 99 | this.regionName = null; // only needed if auth is enabled 100 | } 101 | 102 | /** 103 | * Creates a Neptune SPARQL repository with AWS Signature V4 authentication. 104 | *

105 | * Use this constructor for Neptune instances that require IAM authentication. 106 | * The repository will automatically sign all HTTP requests using AWS Signature V4 107 | * before sending them to Neptune. 108 | * 109 | * @param endpointUrl fully qualified Neptune cluster endpoint URL 110 | * (e.g., "https://my-cluster.cluster-xyz.us-east-1.neptune.amazonaws.com:8182/sparql") 111 | * @param awsCredentialsProvider the AWS credentials provider for obtaining signing credentials 112 | * (e.g., DefaultCredentialsProvider.create()) 113 | * @param regionName the AWS region name where the Neptune cluster is located (e.g., "us-east-1") 114 | * @throws NeptuneSigV4SignerException if there's an error initializing the AWS signature signer 115 | */ 116 | public NeptuneSparqlRepository( 117 | final String endpointUrl, 118 | final AwsCredentialsProvider awsCredentialsProvider, 119 | final String regionName) 120 | throws NeptuneSigV4SignerException { 121 | 122 | super(endpointUrl); 123 | 124 | this.authenticationEnabled = true; 125 | this.awsCredentialsProvider = awsCredentialsProvider; 126 | this.regionName = regionName; 127 | 128 | initAuthenticatingHttpClient(); 129 | 130 | } 131 | 132 | /** 133 | * Initializes the HTTP client with AWS Signature V4 signing capability. 134 | *

135 | * This method configures an Apache HTTP client with a request interceptor that 136 | * automatically signs outgoing requests using AWS Signature V4. The interceptor 137 | * is added last in the chain to ensure it operates on the final request. 138 | * 139 | * @throws NeptuneSigV4SignerException if there's an error initializing the AWS signature signer 140 | */ 141 | protected void initAuthenticatingHttpClient() throws NeptuneSigV4SignerException { 142 | 143 | if (!authenticationEnabled) { 144 | return; // Authentication not enabled, skip HTTP client configuration 145 | } 146 | 147 | // Initialize AWS Signature V4 signer for Apache HTTP requests 148 | v4Signer = new NeptuneApacheHttpSigV4Signer(regionName, awsCredentialsProvider); 149 | 150 | /* 151 | * Configure HTTP client with signing interceptor. 152 | * The interceptor is added last to ensure it operates on the final version 153 | * of the request after all other interceptors have processed it. 154 | */ 155 | final HttpClient v4SigningClient = HttpClientBuilder 156 | .create() 157 | .addInterceptorLast((HttpRequestInterceptor) (req, ctx) -> { 158 | // Ensure the request is the expected type 159 | if (req instanceof HttpUriRequest httpUriReq) { 160 | try { 161 | // Sign the request using AWS Signature V4 162 | v4Signer.signRequest(httpUriReq); 163 | } catch (NeptuneSigV4SignerException e) { 164 | throw new HttpException("Failed to sign Neptune request with AWS Signature V4: ", e); 165 | } 166 | } else { 167 | // This should never happen with standard HTTP clients 168 | throw new HttpException("Request is not an HttpUriRequest instance"); 169 | } 170 | }).build(); 171 | 172 | setHttpClient(v4SigningClient); 173 | 174 | } 175 | 176 | } 177 | 178 | -------------------------------------------------------------------------------- /src/test/java/com/amazonaws/neptune/integration/NeptuneJenaIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.integration; 17 | 18 | import com.amazonaws.neptune.client.jena.AwsSigningHttpClient; 19 | import org.apache.jena.atlas.web.HttpException; 20 | import org.apache.jena.rdfconnection.RDFConnection; 21 | import org.apache.jena.rdfconnection.RDFConnectionRemote; 22 | import org.junit.jupiter.api.AfterEach; 23 | import org.junit.jupiter.api.BeforeEach; 24 | import org.junit.jupiter.api.Test; 25 | import org.junit.jupiter.api.condition.EnabledIfSystemProperty; 26 | import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; 27 | import software.amazon.awssdk.regions.Region; 28 | 29 | import java.net.http.HttpClient; 30 | import java.util.UUID; 31 | 32 | import static com.amazonaws.neptune.NeptuneSPARQLConnectionIntegrationTestUtil.*; 33 | import static org.junit.jupiter.api.Assertions.*; 34 | 35 | @EnabledIfSystemProperty(named = "neptune.endpoint", matches = ".*") 36 | class NeptuneJenaIntegrationTest { 37 | 38 | private HttpClient signingClient; 39 | private String testGraphUri; 40 | private String testGraphUri2; 41 | private final String regionName = System.getProperty( 42 | "aws.region", 43 | "us-west-1" 44 | ); 45 | private final String neptuneEndpoint = System.getProperty( 46 | "neptune.endpoint" 47 | ); 48 | private DefaultCredentialsProvider credentialsProvider; 49 | 50 | 51 | @BeforeEach 52 | void setUp() { 53 | 54 | credentialsProvider = DefaultCredentialsProvider.builder().build(); 55 | 56 | testGraphUri = "http://neptune.aws.com/ontology/testing/" + UUID.randomUUID(); 57 | testGraphUri2 = "http://neptune.aws.com/ontology/testing/" + UUID.randomUUID(); 58 | } 59 | 60 | @AfterEach 61 | void cleanup() { 62 | 63 | String deleteQuery = getClearQuery(testGraphUri); 64 | 65 | signingClient = new AwsSigningHttpClient( 66 | "neptune-db", 67 | Region.of(regionName), 68 | credentialsProvider, 69 | deleteQuery 70 | ); 71 | 72 | try (RDFConnection conn = RDFConnectionRemote.create() 73 | .httpClient(signingClient) 74 | .destination(neptuneEndpoint) 75 | .updateEndpoint("sparql") 76 | .build()) { 77 | 78 | conn.update(deleteQuery); 79 | } 80 | 81 | } 82 | 83 | /** 84 | * Tests Neptune SPARQL operations with Jena, demonstrating the critical requirement 85 | * that the request body (SPARQL query) must be provided when creating the signing client. 86 | *

87 | * AWS Signature V4 Body Requirement: 88 | * AWS Signature Version 4 requires the request body to be included in the signature 89 | * calculation to ensure request integrity and prevent tampering. The signature is 90 | * computed using a hash of the request body along with other request components 91 | * (headers, URI, method, etc.). This means: 92 | *

97 | *

98 | * Why This Matters for SPARQL: 99 | * SPARQL queries are sometimes sent as HTTP POST requests with the query in the request body. 100 | * Since AWS Signature V4 includes the body hash in the signature calculation, 101 | * we must provide the exact SPARQL query text when creating the AwsSigningHttpClient. 102 | * This ensures the signature matches what Neptune expects when it validates the request. 103 | *

104 | * This test verifies that the signing process works correctly by: 105 | *

    106 | *
  1. Creating a signing client with the INSERT query body
  2. 107 | *
  3. Executing the INSERT operation (which must match the signed body)
  4. 108 | *
  5. Verifying the data was inserted by querying it back
  6. 109 | *
110 | */ 111 | @Test 112 | void testInsertAndQueryWithJena() { 113 | // Generate the SPARQL INSERT query that will be sent in the request body 114 | String insertQuery = getInsertQuery(testGraphUri); 115 | 116 | signingClient = new AwsSigningHttpClient( 117 | "neptune-db", 118 | Region.of(regionName), 119 | credentialsProvider, 120 | insertQuery // This exact query body will be used for signature calculation 121 | ); 122 | 123 | try (RDFConnection conn = RDFConnectionRemote.create() 124 | .httpClient(signingClient) 125 | .destination(neptuneEndpoint) 126 | .queryEndpoint("sparql") 127 | .updateEndpoint("sparql") 128 | .build()) { 129 | 130 | // Execute the INSERT - the request body must match what was used for signing 131 | conn.update(insertQuery); 132 | System.out.println("✓ Insert completed successfully"); 133 | 134 | final int[] resultCount = {0}; 135 | 136 | // Query the inserted data to verify the operation succeeded 137 | // As this SELECT query uses GET, there is no request body. 138 | conn.querySelect(getSelectQuery(testGraphUri), result -> { 139 | resultCount[0]++; 140 | }); 141 | 142 | assertEquals(1, resultCount[0], "Should find exactly 1 result"); 143 | } 144 | } 145 | 146 | /** 147 | * Tests that a new signing client must be created for each request with a different body. 148 | *

149 | * CRITICAL: The query string itself must be provided to the signing client because 150 | * AWS Signature V4 requires the request body to be included in signature calculation. 151 | * The signature includes a hash of the request body to ensure integrity. 152 | * Because of this, a new signingClient must be created for every request that contains a body (POST, PUT). 153 | */ 154 | @Test 155 | void testSecondInsertRequiresNewClientForCorrectSignatureCreation() { 156 | // Generate the SPARQL INSERT query that will be sent in the request body 157 | String insertQuery = getInsertQuery(testGraphUri); 158 | String insertQuery2 = getInsertQuery(testGraphUri2); 159 | 160 | signingClient = new AwsSigningHttpClient( 161 | "neptune-db", 162 | Region.of(regionName), 163 | credentialsProvider, 164 | insertQuery // This exact query body will be used for signature calculation 165 | ); 166 | 167 | try (RDFConnection conn = RDFConnectionRemote.create() 168 | .httpClient(signingClient) 169 | .destination(neptuneEndpoint) 170 | .queryEndpoint("sparql") 171 | .updateEndpoint("sparql") 172 | .build()) { 173 | 174 | // Execute the INSERT - the request body must match what was used for signing 175 | conn.update(insertQuery); 176 | System.out.println("✓ Insert completed successfully"); 177 | conn.update(insertQuery2); 178 | fail("Should throw exception"); 179 | } catch (HttpException hje) { 180 | assertTrue(hje.getMessage().contains("403 - Forbidden")); 181 | } 182 | 183 | HttpClient signingClient2 = new AwsSigningHttpClient( 184 | "neptune-db", 185 | Region.of(regionName), 186 | credentialsProvider, 187 | insertQuery2 188 | ); 189 | try (RDFConnection conn = RDFConnectionRemote.create() 190 | .httpClient(signingClient2) 191 | .destination(neptuneEndpoint) 192 | .queryEndpoint("sparql") 193 | .updateEndpoint("sparql") 194 | .build()) { 195 | 196 | // Execute the INSERT - the request body must match what was used for signing 197 | conn.update(insertQuery2); 198 | System.out.println( 199 | "✓ Insert 2 now completes successfully as new client and " + 200 | "connection as auth header is correctly built using the body from insert 2." 201 | ); 202 | } 203 | } 204 | 205 | 206 | } -------------------------------------------------------------------------------- /src/main/java/com/amazonaws/neptune/client/jena/AwsSigningHttpClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazonaws.neptune.client.jena; 17 | 18 | import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; 19 | import software.amazon.awssdk.auth.signer.Aws4Signer; 20 | import software.amazon.awssdk.auth.signer.params.Aws4SignerParams; 21 | import software.amazon.awssdk.http.SdkHttpFullRequest; 22 | import software.amazon.awssdk.http.SdkHttpMethod; 23 | import software.amazon.awssdk.regions.Region; 24 | 25 | import javax.net.ssl.SSLContext; 26 | import javax.net.ssl.SSLParameters; 27 | import java.io.ByteArrayInputStream; 28 | import java.io.IOException; 29 | import java.net.Authenticator; 30 | import java.net.CookieHandler; 31 | import java.net.ProxySelector; 32 | import java.net.http.HttpClient; 33 | import java.net.http.HttpRequest; 34 | import java.net.http.HttpResponse; 35 | import java.nio.charset.StandardCharsets; 36 | import java.time.Duration; 37 | import java.util.Optional; 38 | import java.util.concurrent.CompletableFuture; 39 | import java.util.concurrent.Executor; 40 | 41 | /** 42 | * AWS Signature Version 4 signing HTTP client for Amazon Neptune SPARQL requests. 43 | *

44 | * This class extends the standard Java HttpClient to automatically sign HTTP requests 45 | * using AWS Signature Version 4 authentication. It's specifically designed for use with 46 | * Amazon Neptune database instances that require IAM authentication. 47 | *

48 | * The client wraps a delegate HttpClient and intercepts requests to add the necessary 49 | * AWS authentication headers (Authorization and x-amz-date) before forwarding them 50 | * to the underlying client. 51 | *

52 | * A new HTTP client and connection must be created every time the request contains a BODY. 53 | *

54 | * 55 | * @author Charles Ivie 56 | */ 57 | public class AwsSigningHttpClient extends HttpClient { 58 | 59 | /** The underlying HTTP client that handles actual network communication */ 60 | private final HttpClient delegate; 61 | 62 | /** The request body content used for signature calculation */ 63 | private final String requestBody; 64 | 65 | /** AWS credentials provider for obtaining signing credentials */ 66 | private final AwsCredentialsProvider credentialsProvider; 67 | 68 | /** AWS service name for signing (typically "neptune-db") */ 69 | private final String serviceName; 70 | 71 | /** AWS region where the Neptune instance is located */ 72 | private final Region region; 73 | 74 | /** 75 | * Creates a new AWS signing HTTP client. 76 | * 77 | * @param serviceName the AWS service name for signing (e.g., "neptune-db") 78 | * @param region the AWS region where the Neptune instance is located 79 | * @param credentialsProvider the AWS credentials provider for authentication 80 | * @param requestBody the request body content used for signature calculation 81 | */ 82 | public AwsSigningHttpClient( 83 | String serviceName, 84 | Region region, 85 | AwsCredentialsProvider credentialsProvider, 86 | String requestBody) { 87 | this.requestBody = requestBody; 88 | this.credentialsProvider = credentialsProvider; 89 | this.serviceName = serviceName; 90 | this.region = region; 91 | // The delegate client will handle the actual network communication. 92 | this.delegate = HttpClient.newHttpClient(); 93 | } 94 | 95 | /** 96 | * Sends a synchronous HTTP request with AWS Signature V4 authentication. 97 | * 98 | * @param the response body type 99 | * @param request the HTTP request to send 100 | * @param responseBodyHandler the response body handler 101 | * @return the HTTP response 102 | * @throws IOException if an I/O error occurs 103 | * @throws InterruptedException if the operation is interrupted 104 | */ 105 | @Override 106 | public HttpResponse send(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) 107 | throws IOException, InterruptedException { 108 | return delegate.send(buildSignedRequest(request), responseBodyHandler); 109 | } 110 | 111 | /** 112 | * Sends an asynchronous HTTP request with AWS Signature V4 authentication. 113 | * 114 | * @param the response body type 115 | * @param request the HTTP request to send 116 | * @param responseBodyHandler the response body handler 117 | * @return a CompletableFuture containing the HTTP response 118 | */ 119 | @Override 120 | public CompletableFuture> sendAsync(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) { 121 | return delegate.sendAsync(buildSignedRequest(request), responseBodyHandler); 122 | } 123 | 124 | /** 125 | * Builds a signed HTTP request by adding AWS Signature V4 authentication headers. 126 | * 127 | * @param request the original HTTP request 128 | * @return a new HTTP request with AWS authentication headers added 129 | */ 130 | private HttpRequest buildSignedRequest(HttpRequest request) { 131 | // Create a builder from the original request, copying all headers 132 | HttpRequest.Builder signedRequestBuilder = HttpRequest.newBuilder(request, (name, value) -> true); 133 | 134 | // Convert the Java HTTP request to AWS SDK format for signing 135 | SdkHttpFullRequest awsRequestForSigning = toSdkRequest(request, requestBody); 136 | 137 | // Configure the AWS Signature V4 signer parameters 138 | Aws4SignerParams signerParams = Aws4SignerParams.builder() 139 | .awsCredentials(credentialsProvider.resolveCredentials()) 140 | .signingName(serviceName) 141 | .signingRegion(region) 142 | .build(); 143 | 144 | // Sign the request using AWS Signature V4 145 | SdkHttpFullRequest signedSdkRequest = Aws4Signer.create().sign(awsRequestForSigning, signerParams); 146 | 147 | // Add the authentication headers to the original request 148 | return signedRequestBuilder 149 | .header("Authorization", signedSdkRequest.headers().get("Authorization").get(0)) 150 | .header("x-amz-date", signedSdkRequest.headers().get("x-amz-date").get(0)) 151 | .build(); 152 | } 153 | 154 | 155 | // Delegate all other abstract methods to the wrapped client 156 | @Override 157 | public Optional cookieHandler() { 158 | return delegate.cookieHandler(); 159 | } 160 | 161 | @Override 162 | public Optional connectTimeout() { 163 | return delegate.connectTimeout(); 164 | } 165 | 166 | @Override 167 | public Redirect followRedirects() { 168 | return delegate.followRedirects(); 169 | } 170 | 171 | @Override 172 | public Optional proxy() { 173 | return delegate.proxy(); 174 | } 175 | 176 | @Override 177 | public SSLContext sslContext() { 178 | return delegate.sslContext(); 179 | } 180 | 181 | @Override 182 | public SSLParameters sslParameters() { 183 | return delegate.sslParameters(); 184 | } 185 | 186 | @Override 187 | public Optional authenticator() { 188 | return delegate.authenticator(); 189 | } 190 | 191 | @Override 192 | public Version version() { 193 | return delegate.version(); 194 | } 195 | 196 | @Override 197 | public Optional executor() { 198 | return delegate.executor(); 199 | } 200 | 201 | /** 202 | * Sends an asynchronous HTTP request with push promise support and AWS Signature V4 authentication. 203 | * 204 | * @param the response body type 205 | * @param r the HTTP request to send 206 | * @param h the response body handler 207 | * @param p the push promise handler 208 | * @return a CompletableFuture containing the HTTP response 209 | */ 210 | @Override 211 | public CompletableFuture> sendAsync(HttpRequest r, HttpResponse.BodyHandler h, HttpResponse.PushPromiseHandler p) { 212 | return delegate.sendAsync(buildSignedRequest(r), h, p); 213 | } 214 | 215 | /** 216 | * Converts a Java HttpRequest to an AWS SDK SdkHttpFullRequest for signing. 217 | * 218 | * @param originalHttpRequest the original Java HTTP request 219 | * @param originalBody the request body content 220 | * @return an AWS SDK HTTP request ready for signing 221 | */ 222 | private SdkHttpFullRequest toSdkRequest(HttpRequest originalHttpRequest, String originalBody) { 223 | // Build the AWS SDK request with URI and HTTP method 224 | SdkHttpFullRequest.Builder sdkRequestBuilder = SdkHttpFullRequest.builder() 225 | .uri(originalHttpRequest.uri()) 226 | .method(SdkHttpMethod.fromValue(originalHttpRequest.method())); 227 | 228 | // Add request body if present 229 | if (originalHttpRequest.bodyPublisher().isPresent()) { 230 | sdkRequestBuilder.contentStreamProvider(() -> new ByteArrayInputStream(originalBody.getBytes(StandardCharsets.UTF_8))); 231 | } 232 | 233 | // Copy all headers from the original request 234 | originalHttpRequest.headers().map().forEach((headerName, headerValues) -> { 235 | for (String headerValue : headerValues) { 236 | sdkRequestBuilder.putHeader(headerName, headerValue); 237 | } 238 | }); 239 | 240 | return sdkRequestBuilder.build(); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2018 Amazon.com, Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2018 Amazon.com, Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 15 | 17 | 18 | 4.0.0 19 | com.amazonaws 20 | amazon-neptune-sparql-java-sigv4 21 | jar 22 | 4.0.1-SNAPSHOT 23 | 24 | amazon-neptune-sparql-java-sigv4 25 | 26 | A SPARQL client for Amazon Neptune that includes AWS Signature Version 4 signing. 27 | A NeptuneSparqlRepository for RDF4j and a AwsSigningHttpClient to use when creating a JENA repository connection. 28 | 29 | https://github.com/aws/amazon-neptune-sparql-java-sigv4 30 | 31 | 32 | 33 | Apache License, Version 2.0 34 | https://aws.amazon.com/apache2.0 35 | repo 36 | 37 | 38 | 39 | 40 | 41 | amazonwebservices 42 | Amazon Web Services 43 | https://aws.amazon.com 44 | 45 | developer 46 | 47 | 48 | 49 | 50 | 51 | 52 | ossrh 53 | https://aws.oss.sonatype.org/content/repositories/snapshots/ 54 | 55 | 56 | ossrh 57 | https://aws.oss.sonatype.org/content/groups/staging/ 58 | 59 | 60 | 61 | 62 | scm:git:git@github.com:aws/amazon-neptune-sparql-java-sigv4.git 63 | scm:git:git@github.com:aws/amazon-neptune-sparql-java-sigv4.git 64 | git@github.com:aws/amazon-neptune-sparql-java-sigv4.git 65 | 66 | 67 | 68 | UTF-8 69 | 17 70 | 17 71 | 5.1.6 72 | 5.5.0 73 | 2.34.5 74 | 5.10.2 75 | 5.12.0 76 | 77 | 3.13.0 78 | 3.3.1 79 | 3.10.1 80 | 3.2.8 81 | 1.7.0 82 | 5.5.1 83 | 2.0.16 84 | 85 | 86 | 87 | 88 | 89 | com.fasterxml.jackson.core 90 | jackson-core 91 | 2.18.2 92 | 93 | 94 | com.fasterxml.jackson.core 95 | jackson-databind 96 | 2.18.2 97 | 98 | 99 | com.fasterxml.jackson.dataformat 100 | jackson-dataformat-cbor 101 | 2.18.2 102 | 103 | 104 | 105 | 106 | 107 | 108 | org.eclipse.rdf4j 109 | rdf4j-repository-sparql 110 | ${rdf4j.version} 111 | 112 | 113 | 114 | 115 | org.apache.jena 116 | jena-arq 117 | ${jena.version} 118 | 119 | 120 | 121 | org.apache.jena 122 | jena-rdfconnection 123 | ${jena.version} 124 | 125 | 126 | 127 | org.apache.httpcomponents.client5 128 | httpclient5 129 | ${httpclient5.version} 130 | 131 | 132 | 133 | 134 | com.amazonaws 135 | amazon-neptune-sigv4-signer 136 | ${project.version} 137 | 138 | 139 | 140 | 141 | software.amazon.awssdk 142 | auth 143 | ${aws.sdk.version} 144 | 145 | 146 | 147 | software.amazon.awssdk 148 | http-auth-aws 149 | ${aws.sdk.version} 150 | 151 | 152 | 153 | software.amazon.awssdk 154 | regions 155 | ${aws.sdk.version} 156 | 157 | 158 | 159 | org.slf4j 160 | slf4j-simple 161 | ${slf4j-simple.version} 162 | 163 | 164 | 165 | 166 | org.junit.jupiter 167 | junit-jupiter 168 | ${junit.version} 169 | test 170 | 171 | 172 | 173 | org.mockito 174 | mockito-core 175 | ${mockito.version} 176 | test 177 | 178 | 179 | 180 | org.mockito 181 | mockito-junit-jupiter 182 | ${mockito.version} 183 | test 184 | 185 | 186 | 187 | 188 | 189 | release 190 | 191 | 192 | 193 | 194 | 195 | org.apache.maven.plugins 196 | maven-source-plugin 197 | ${maven-source-plugin.version} 198 | 199 | 200 | attach-sources 201 | 202 | jar-no-fork 203 | 204 | 205 | 206 | 207 | 208 | 209 | org.apache.maven.plugins 210 | maven-compiler-plugin 211 | ${maven-compiler-plugin.version} 212 | 213 | ${maven.compiler.source} 214 | ${maven.compiler.target} 215 | 216 | 217 | 218 | 219 | 220 | org.apache.maven.plugins 221 | maven-javadoc-plugin 222 | ${maven-javadoc-plugin.version} 223 | 224 | Amazon Neptune Sparql Java Sigv4 225 | UTF-8 226 | 227 | Copyright © 2018 Amazon.com. All Rights Reserved.]]> 228 | 229 | -Xdoclint:none 230 | 231 | 232 | 233 | attach-javadocs 234 | 235 | jar 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | org.apache.maven.plugins 244 | maven-gpg-plugin 245 | ${maven-gpg-plugin.version} 246 | 247 | 248 | sign-artifacts 249 | verify 250 | 251 | sign 252 | 253 | 254 | ${gpg.keyname} 255 | ${gpg.passphrase} 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | org.sonatype.plugins 264 | nexus-staging-maven-plugin 265 | ${nexus-staging-maven-plugin.version} 266 | true 267 | 268 | ossrh 269 | https://aws.oss.sonatype.org/ 270 | true 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | --------------------------------------------------------------------------------