From fb909a5ce3c6b337f7979091edbc22bbeca0cabb Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Mon, 5 Sep 2016 15:20:30 +0200 Subject: [PATCH 1/2] Added support for custom auth tokens --- neo4j/v1/session.py | 28 ++++++++++++++++++++++------ test/test_session.py | 17 ++++++++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/neo4j/v1/session.py b/neo4j/v1/session.py index 8f889116..dd6fd1e5 100644 --- a/neo4j/v1/session.py +++ b/neo4j/v1/session.py @@ -24,7 +24,6 @@ instances that are in turn used for managing sessions. """ - from __future__ import division from collections import deque @@ -39,7 +38,6 @@ from .summary import ResultSummary from .types import hydrated - DEFAULT_MAX_POOL_SIZE = 50 localhost = re.compile(r"^(localhost|127(\.\d+){3})$", re.IGNORECASE) @@ -49,10 +47,14 @@ class AuthToken(object): """ Container for auth information """ - def __init__(self, scheme, principal, credentials): + def __init__(self, scheme, principal, credentials, realm=None, parameters=None): self.scheme = scheme self.principal = principal self.credentials = credentials + if realm: + self.realm = realm + if parameters: + self.parameters = parameters class GraphDatabase(object): @@ -135,7 +137,7 @@ def __init__(self, address, **config): self.encrypted = encrypted self.trust = trust = config.get("trust", TRUST_DEFAULT) if encrypted == ENCRYPTION_ON or \ - encrypted == ENCRYPTION_NON_LOCAL and not localhost.match(host): + encrypted == ENCRYPTION_NON_LOCAL and not localhost.match(host): if not SSL_AVAILABLE: raise RuntimeError("Bolt over TLS is only available in Python 2.7.9+ and Python 3.3+") ssl_context = SSLContext(PROTOCOL_SSLv23) @@ -510,14 +512,28 @@ def __ne__(self, other): return not self.__eq__(other) -def basic_auth(user, password): +def basic_auth(user, password, realm=None): """ Generate a basic auth token for a given user and password. :param user: user name :param password: current password + :param realm: specifies the authentication provider + :return: auth token for use with :meth:`GraphDatabase.driver` + """ + return AuthToken("basic", user, password, realm) + + +def custom_auth(principal, credentials, realm=None, scheme=None, parameters=None): + """ Generate a basic auth token for a given user and password. + + :param principal: specifies who is being authenticated + :param credentials: authenticates the principal + :param realm: specifies the authentication provider + :param scheme: specifies the type of authentication + :param parameters: parameters passed along to the authenticatin provider :return: auth token for use with :meth:`GraphDatabase.driver` """ - return AuthToken("basic", user, password) + return AuthToken(scheme, principal, credentials, realm, parameters) def run(connection, statement, parameters=None): diff --git a/test/test_session.py b/test/test_session.py index 9695f3d5..f9e54977 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -27,7 +27,7 @@ from neo4j.v1.constants import TRUST_ON_FIRST_USE from neo4j.v1.exceptions import CypherError, ProtocolError, ResultError -from neo4j.v1.session import GraphDatabase, basic_auth, Record, SSL_AVAILABLE +from neo4j.v1.session import GraphDatabase, basic_auth, custom_auth, Record, SSL_AVAILABLE from neo4j.v1.types import Node, Relationship, Path from test.util import ServerTestCase @@ -97,6 +97,21 @@ def test_fail_nicely_when_connecting_to_http_port(self): assert str(context.exception) == "Server responded HTTP. Make sure you are not trying to connect to the http " \ "endpoint (HTTP defaults to port 7474 whereas BOLT defaults to port 7687)" + def test_can_create_custom_auth_token(self): + token = custom_auth("neo4j", "neo4j", "native", "basic") + driver = GraphDatabase.driver("bolt://localhost", auth=token) + session = driver.session() + result = session.run("RETURN 1").consume() + session.close() + assert result is not None + + def test_can_create_custom_auth_token_with_additional_parameters(self): + token = custom_auth("neo4j", "neo4j", "native", "basic", {secret: 42}) + driver = GraphDatabase.driver("bolt://localhost", auth=token) + session = driver.session() + result = session.run("RETURN 1").consume() + session.close() + assert result is not None class SecurityTestCase(ServerTestCase): From 05370f86958d12eeb44cc0346af50e3c37c72a64 Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Tue, 6 Sep 2016 09:43:25 +0200 Subject: [PATCH 2/2] Fixes from code review --- neo4j/v1/session.py | 9 ++++++--- test/test_session.py | 10 +++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/neo4j/v1/session.py b/neo4j/v1/session.py index dd6fd1e5..3ce9b535 100644 --- a/neo4j/v1/session.py +++ b/neo4j/v1/session.py @@ -47,7 +47,10 @@ class AuthToken(object): """ Container for auth information """ - def __init__(self, scheme, principal, credentials, realm=None, parameters=None): + #: By default we should not send any realm + realm = None + + def __init__(self, scheme, principal, credentials, realm=None, **parameters): self.scheme = scheme self.principal = principal self.credentials = credentials @@ -523,7 +526,7 @@ def basic_auth(user, password, realm=None): return AuthToken("basic", user, password, realm) -def custom_auth(principal, credentials, realm=None, scheme=None, parameters=None): +def custom_auth(principal, credentials, realm, scheme, **parameters): """ Generate a basic auth token for a given user and password. :param principal: specifies who is being authenticated @@ -533,7 +536,7 @@ def custom_auth(principal, credentials, realm=None, scheme=None, parameters=None :param parameters: parameters passed along to the authenticatin provider :return: auth token for use with :meth:`GraphDatabase.driver` """ - return AuthToken(scheme, principal, credentials, realm, parameters) + return AuthToken(scheme, principal, credentials, realm, **parameters) def run(connection, statement, parameters=None): diff --git a/test/test_session.py b/test/test_session.py index f9e54977..2a9f9ffa 100644 --- a/test/test_session.py +++ b/test/test_session.py @@ -97,6 +97,14 @@ def test_fail_nicely_when_connecting_to_http_port(self): assert str(context.exception) == "Server responded HTTP. Make sure you are not trying to connect to the http " \ "endpoint (HTTP defaults to port 7474 whereas BOLT defaults to port 7687)" + def test_can_provide_realm_with_basic_auth_token(self): + token = basic_auth("neo4j", "neo4j", "native") + driver = GraphDatabase.driver("bolt://localhost", auth=token) + session = driver.session() + result = session.run("RETURN 1").consume() + session.close() + assert result is not None + def test_can_create_custom_auth_token(self): token = custom_auth("neo4j", "neo4j", "native", "basic") driver = GraphDatabase.driver("bolt://localhost", auth=token) @@ -106,7 +114,7 @@ def test_can_create_custom_auth_token(self): assert result is not None def test_can_create_custom_auth_token_with_additional_parameters(self): - token = custom_auth("neo4j", "neo4j", "native", "basic", {secret: 42}) + token = custom_auth("neo4j", "neo4j", "native", "basic", secret=42) driver = GraphDatabase.driver("bolt://localhost", auth=token) session = driver.session() result = session.run("RETURN 1").consume()