Skip to content

Commit

Permalink
Add example of authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Feb 25, 2016
1 parent 55c6fad commit 8f28d2c
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 96 deletions.
55 changes: 55 additions & 0 deletions community/bolt/src/docs/dev/examples.asciidoc
Expand Up @@ -3,6 +3,61 @@


This section contains concrete examples showing how to perform tasks using the full Bolt protocol stack. This section contains concrete examples showing how to perform tasks using the full Bolt protocol stack.


=== Authentication

The first time you connect to neo4j with the default credentials you will be asked to update the password.

.Run query
[source,bolt_auth]
----
# Handshake
Client: <connect>
Client: 60 60 B0 17
Client: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Server: 00 00 00 01
Client: INIT "MyClient/1.0" { "scheme": "basic", "principal": "neo4j", "credentials": "neo4j"}
00 3F B1 01 8C 4D 79 43 6C 69 65 6E 74 2F 31 2E
30 A3 86 73 63 68 65 6D 65 85 62 61 73 69 63 89
70 72 69 6E 63 69 70 61 6C 85 6E 65 6F 34 6A 8B
63 72 65 64 65 6E 74 69 61 6C 73 85 6E 65 6F 34
6A 00 00
Server: FAILURE { "code": "Neo.ClientError.Security.CredentialsExpired",
"message": "The credentials have expired and needs to be updated."}
00 74 B1 7F A2 84 63 6F 64 65 D0 2B 4E 65 6F 2E
43 6C 69 65 6E 74 45 72 72 6F 72 2E 53 65 63 75
72 69 74 79 2E 43 72 65 64 65 6E 74 69 61 6C 73
45 78 70 69 72 65 64 87 6D 65 73 73 61 67 65 D0
35 54 68 65 20 63 72 65 64 65 6E 74 69 61 6C 73
20 68 61 76 65 20 65 78 70 69 72 65 64 20 61 6E
64 20 6E 65 65 64 73 20 74 6F 20 62 65 20 75 70
64 61 74 65 64 2E 00 00
Server: <disconnect>
Client: <connect>
Client: 60 60 B0 17
Client: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Server: 00 00 00 01
Client: INIT "MyClient/1.0" { "scheme": "basic", "principal": "neo4j", "credentials": "neo4j", "new-credentials": "secret"}
00 40 B1 01 8C 4D 79 43 6C 69 65 6E 74 2F 31 2E
30 A4 86 73 63 68 65 6D 65 85 62 61 73 69 63 89
70 72 69 6E 63 69 70 61 6C 85 6E 65 6F 34 6A 8B
63 72 65 64 65 6E 74 69 61 6C 73 85 6E 65 6F 34
6A 8F 00 16 6E 65 77 2D 63 72 65 64 65 6E 74 69
61 6C 73 86 73 65 63 72 65 74 00 00
Server: SUCCESS { }
00 03 b1 70 a0 00 00
----

=== Running a Cypher query === Running a Cypher query


This illustrates running a simple Cypher query without parameters, and retrieving the results. This illustrates running a simple Cypher query without parameters, and retrieving the results.
Expand Down
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.bolt.v1.docs;

import org.junit.Rule;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Supplier;

import org.neo4j.bolt.v1.transport.integration.Neo4jWithSocket;
import org.neo4j.bolt.v1.transport.socket.client.Connection;
import org.neo4j.bolt.v1.transport.socket.client.SecureSocketConnection;
import org.neo4j.bolt.v1.transport.socket.client.SecureWebSocketConnection;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.helpers.HostnamePort;

@RunWith( Parameterized.class )
public class BoltAuthDocTest extends BoltFullDocTest
{
@Rule
public Neo4jWithSocket server = new Neo4jWithSocket( settings -> {
settings.put( GraphDatabaseSettings.auth_enabled, "true" );
} );

@Parameterized.Parameter( 0 )
public String testName;

@Parameterized.Parameter( 1 )
public DocExchangeExample example;

@Parameterized.Parameter( 2 )
public Supplier<Connection> client;

@Parameterized.Parameter( 3 )
public HostnamePort address;

@Parameterized.Parameters( name = "{0}" )
public static Collection<Object[]> documentedFullProtocolExamples()
{
Collection<Object[]> mappings = new ArrayList<>();

// Load the documented mappings
HostnamePort address = new HostnamePort( "localhost:7687" );

for ( DocExchangeExample ex : DocsRepository.docs().read(
"dev/examples.asciidoc",
"code[data-lang=\"bolt_auth\"]",
DocExchangeExample.exchange_example ) )
{
mappings.add( new Object[]{"Socket - " + ex.name(), ex,
(Supplier<Connection>) SecureSocketConnection::new, address});
mappings.add( new Object[]{"WebSocket - " + ex.name(), ex,
(Supplier<Connection>) SecureWebSocketConnection::new , address} );
}
return mappings;
}

@Override
protected Connection createClient()
{
return client.get();
}

@Override
protected HostnamePort address()
{
return address;
}

@Override
protected DocExchangeExample example()
{
return example;
}
}
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.bolt.v1.docs;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import org.neo4j.bolt.v1.messaging.message.Message;
import org.neo4j.bolt.v1.transport.socket.client.Connection;
import org.neo4j.helpers.HostnamePort;
import org.neo4j.kernel.impl.util.HexPrinter;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.neo4j.bolt.v1.messaging.util.MessageMatchers.message;
import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.dechunk;
import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.recvOneMessage;

public abstract class BoltFullDocTest
{
private Connection client;

@Test
public void serverShouldBehaveAsDocumented() throws Throwable
{
for ( DocExchangeExample.Event event : example() )
{
if ( event.from().equalsIgnoreCase( "client" ) )
{
// Play out a client action
switch ( event.type() )
{
case CONNECT:
client.connect( address() );
break;
case DISCONNECT:
client.disconnect();
break;
case SEND:
// Ensure the documented binary representation matches the human-readable version in the docs
if ( event.hasHumanReadableValue() )
{
assertThat( "'" + event.humanReadableMessage() + "' should serialize to the documented " +
"binary data.",
hex( event.payload() ),
equalTo( hex( DocSerialization.packAndChunk( event.humanReadableMessage(), 64 ) ) ) );
}
client.send( event.payload() );
break;
default:
throw new RuntimeException( "Unknown client event: " + event.type() );
}
}
else if ( event.from().equalsIgnoreCase( "server" ) )
{
// Assert that the server does what the docs say
switch ( event.type() )
{
case DISCONNECT:
// There's not really a good way to verify that the remote connection is closed, we can read and
// time out, or write perhaps, but that's buggy and racy.. not sure how to test this on this
// level.
client.disconnect();
client = createClient();
break;
case SEND:
if ( event.hasHumanReadableValue() )
{
// Ensure the documented binary representation matches the human-readable version in the docs
assertThat( "'" + event.humanReadableMessage() + "' should serialize to the documented " +
"binary data.",
hex( event.payload() ),
equalTo( hex( DocSerialization.packAndChunk( event.humanReadableMessage(), 1024 * 8 ) ) ) );

// Ensure that the server replies as documented
Message serverMessage = recvOneMessage( client );
assertThat(
"The message recieved from the server should match the documented binary representation. " +
"Human-readable message is <" + event.humanReadableMessage() + ">, received message was: " + serverMessage,
serverMessage,
equalTo( message( dechunk( event.payload() ) ) ) );
}
else
{
// Raw data assertions - used for documenting the version negotiation, for instance
assertThat( "The data recieved from the server should match the documented binary representation.",
hex( client.recv( event.payload().length ) ),
equalTo( hex( event.payload() ) ) );
}

break;
default:
throw new RuntimeException( "Unknown server event: " + event.type() );
}
}
}
}

@Before
public void setUp()
{
client = createClient();
}

@After
public void shutdown() throws Exception
{
if ( client != null )
{
client.disconnect();
}
}

protected abstract Connection createClient();
protected abstract HostnamePort address();
protected abstract DocExchangeExample example();

private static String hex( byte[] payload )
{
return HexPrinter.hex( payload, 4, " " );
}
}

0 comments on commit 8f28d2c

Please sign in to comment.