diff --git a/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java b/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java index edef6b9e92..266f8b566f 100644 --- a/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java +++ b/driver/src/main/java/org/neo4j/driver/v1/AuthTokens.java @@ -18,6 +18,8 @@ */ package org.neo4j.driver.v1; +import java.util.Map; + import org.neo4j.driver.internal.security.InternalAuthToken; import static org.neo4j.driver.v1.Values.parameters; @@ -46,6 +48,62 @@ public static AuthToken basic( String username, String password ) "credentials", password ).asMap( Values.ofValue() ) ); } + /** + * The basic authentication scheme, using a username and a password. + * @param username this is the "principal", identifying who this token represents + * @param password this is the "credential", proving the identity of the user + * @param realm this is the "realm", specifies the authentication provider + * @return an authentication token that can be used to connect to Neo4j + * @see GraphDatabase#driver(String, AuthToken) + */ + public static AuthToken basic( String username, String password, String realm ) + { + return new InternalAuthToken( parameters( + "scheme", "basic", + "principal", username, + "credentials", password, + "realm", realm).asMap( Values.ofValue() ) ); + } + + + /** + * A custom authentication token used for doing custom authentication on the server side. + * @param principal this used to identify who this token represents + * @param credentials this is credentials authenticating the principal + * @param realm this is the "realm:, specifying the authentication provider. + * @param scheme this it the authentication scheme, specifying what kind of authentication that should be used + * @return an authentication token that can be used to connect to Neo4j + * * @see GraphDatabase#driver(String, AuthToken) + */ + public static AuthToken custom( String principal, String credentials, String realm, String scheme) + { + return new InternalAuthToken( parameters( + "scheme", scheme, + "principal", principal, + "credentials", credentials, + "realm", realm).asMap( Values.ofValue() ) ); + } + + /** + * A custom authentication token used for doing custom authentication on the server side. + * @param principal this used to identify who this token represents + * @param credentials this is credentials authenticating the principal + * @param realm this is the "realm:, specifying the authentication provider. + * @param scheme this it the authentication scheme, specifying what kind of authentication that shoud be used + * @param parameters extra parameters to be sent along the authentication provider. + * @return an authentication token that can be used to connect to Neo4j + * * @see GraphDatabase#driver(String, AuthToken) + */ + public static AuthToken custom( String principal, String credentials, String realm, String scheme, Map parameters) + { + return new InternalAuthToken( parameters( + "scheme", scheme, + "principal", principal, + "credentials", credentials, + "realm", realm, + "parameters", parameters).asMap( Values.ofValue() ) ); + } + /** * No authentication scheme. This will only work if authentication is disabled * on the Neo4j Instance we are connecting to. diff --git a/driver/src/test/java/org/neo4j/driver/v1/AuthTokensTest.java b/driver/src/test/java/org/neo4j/driver/v1/AuthTokensTest.java new file mode 100644 index 0000000000..9eb7ec3905 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/v1/AuthTokensTest.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2002-2016 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * 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 org.neo4j.driver.v1; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import org.neo4j.driver.internal.security.InternalAuthToken; +import org.neo4j.driver.internal.value.ListValue; +import org.neo4j.driver.internal.value.MapValue; +import org.neo4j.driver.internal.value.StringValue; + +import static java.util.Arrays.asList; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; +import static org.neo4j.driver.v1.AuthTokens.basic; +import static org.neo4j.driver.v1.AuthTokens.custom; +import static org.neo4j.driver.v1.Values.values; + +public class AuthTokensTest +{ + + @Test + public void basicAuthWithoutRealm() + { + InternalAuthToken basic = (InternalAuthToken) basic( "foo", "bar" ); + + Map map = basic.toMap(); + + assertThat( map.size(), equalTo( 3 ) ); + assertThat( map.get( "scheme" ), equalTo( (Value) new StringValue( "basic" ) ) ); + assertThat( map.get( "principal" ), equalTo( (Value) new StringValue( "foo" ) ) ); + assertThat( map.get( "credentials" ), equalTo( (Value) new StringValue( "bar" ) ) ); + } + + @Test + public void basicAuthWithRealm() + { + InternalAuthToken basic = (InternalAuthToken) basic( "foo", "bar", "baz" ); + + Map map = basic.toMap(); + + assertThat( map.size(), equalTo( 4 ) ); + assertThat( map.get( "scheme" ), equalTo( (Value) new StringValue( "basic" ) ) ); + assertThat( map.get( "principal" ), equalTo( (Value) new StringValue( "foo" ) ) ); + assertThat( map.get( "credentials" ), equalTo( (Value) new StringValue( "bar" ) ) ); + assertThat( map.get( "realm" ), equalTo( (Value) new StringValue( "baz" ) ) ); + } + + @Test + public void customAuthWithoutParameters() + { + InternalAuthToken basic = (InternalAuthToken) custom( "foo", "bar", "baz", "my_scheme" ); + + Map map = basic.toMap(); + + assertThat( map.size(), equalTo( 4 ) ); + assertThat( map.get( "scheme" ), equalTo( (Value) new StringValue( "my_scheme" ) ) ); + assertThat( map.get( "principal" ), equalTo( (Value) new StringValue( "foo" ) ) ); + assertThat( map.get( "credentials" ), equalTo( (Value) new StringValue( "bar" ) ) ); + assertThat( map.get( "realm" ), equalTo( (Value) new StringValue( "baz" ) ) ); + } + + @Test + public void customAuthParameters() + { + HashMap parameters = new HashMap<>(); + parameters.put( "list", asList( 1, 2, 3 ) ); + InternalAuthToken basic = (InternalAuthToken) custom( "foo", "bar", "baz", "my_scheme", parameters ); + + + Map expectedParameters = new HashMap<>(); + expectedParameters.put( "list", new ListValue( values( 1, 2, 3 ) ) ); + Map map = basic.toMap(); + + assertThat( map.size(), equalTo( 5 ) ); + assertThat( map.get( "scheme" ), equalTo( (Value) new StringValue( "my_scheme" ) ) ); + assertThat( map.get( "principal" ), equalTo( (Value) new StringValue( "foo" ) ) ); + assertThat( map.get( "credentials" ), equalTo( (Value) new StringValue( "bar" ) ) ); + assertThat( map.get( "realm" ), equalTo( (Value) new StringValue( "baz" ) ) ); + assertThat( map.get( "parameters" ), equalTo( (Value) new MapValue( expectedParameters ) ) ); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/v1/integration/CredentialsIT.java b/driver/src/test/java/org/neo4j/driver/v1/integration/CredentialsIT.java index 8f87b053e2..068986461a 100644 --- a/driver/src/test/java/org/neo4j/driver/v1/integration/CredentialsIT.java +++ b/driver/src/test/java/org/neo4j/driver/v1/integration/CredentialsIT.java @@ -23,6 +23,8 @@ import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import java.util.HashMap; + import org.neo4j.driver.internal.security.InternalAuthToken; import org.neo4j.driver.v1.Driver; import org.neo4j.driver.v1.GraphDatabase; @@ -35,6 +37,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.neo4j.driver.v1.AuthTokens.basic; +import static org.neo4j.driver.v1.AuthTokens.custom; import static org.neo4j.driver.v1.Values.ofValue; import static org.neo4j.driver.v1.Values.parameters; @@ -85,6 +88,59 @@ public void shouldGetHelpfulErrorOnInvalidCredentials() throws Throwable } } + @Test + public void shouldBeAbleToProvideRealmWithBasicAuth() throws Throwable + { + // Given + String password = "secret"; + enableAuth( password ); + + // When & Then + try( Driver driver = GraphDatabase.driver( neo4j.uri(), + basic("neo4j", password, "native") ); + Session session = driver.session() ) + { + Value single = session.run( "CREATE () RETURN 1" ).single().get( 0 ); + assertThat( single.asLong(), equalTo( 1L ) ); + } + } + + @Test + public void shouldBeAbleToConnectWithCustomToken() throws Throwable + { + // Given + String password = "secret"; + enableAuth( password ); + + // When & Then + try( Driver driver = GraphDatabase.driver( neo4j.uri(), + custom("neo4j", password, "native", "basic" ) ); + Session session = driver.session() ) + { + Value single = session.run( "CREATE () RETURN 1" ).single().get( 0 ); + assertThat( single.asLong(), equalTo( 1L ) ); + } + } + + @Test + public void shouldBeAbleToConnectWithCustomTokenWithAdditionalParameters() throws Throwable + { + // Given + String password = "secret"; + enableAuth( password ); + HashMap parameters = new HashMap<>(); + parameters.put( "secret", 16 ); + + // When & Then + try( Driver driver = GraphDatabase.driver( neo4j.uri(), + custom("neo4j", password, "native", "basic", parameters ) ); + Session session = driver.session() ) + { + Value single = session.run( "CREATE () RETURN 1" ).single().get( 0 ); + assertThat( single.asLong(), equalTo( 1L ) ); + } + } + private void enableAuth( String password ) throws Exception { neo4j.restart( Neo4jSettings.TEST_SETTINGS