Repository: stratasan/stratatilities

Issue:
Add method to get vault client w/ LDAP auth
Will be helpful in notebook.stratasan.com. Ideally password is accessed w/
`getpass.getpass`.

Comments:

Patch:
diff --git a/.gitignore b/.gitignore
index 71e6852..7f9f422 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,6 @@ __pycache__/
 
 # Distribution / packaging
 .Python
-env/
 build/
 develop-eggs/
 dist/
@@ -20,9 +19,11 @@ lib64/
 parts/
 sdist/
 var/
+wheels/
 *.egg-info/
 .installed.cfg
 *.egg
+MANIFEST
 
 # PyInstaller
 #  Usually these files are written by a python script from a template
@@ -37,13 +38,15 @@ pip-delete-this-directory.txt
 # Unit test / coverage reports
 htmlcov/
 .tox/
+.nox/
 .coverage
 .coverage.*
 .cache
 nosetests.xml
 coverage.xml
-*,cover
+*.cover
 .hypothesis/
+.pytest_cache/
 
 # Translations
 *.mo
@@ -51,6 +54,15 @@ coverage.xml
 
 # Django stuff:
 *.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
 
 # Sphinx documentation
 docs/_build/
@@ -58,5 +70,45 @@ docs/_build/
 # PyBuilder
 target/
 
-# pyenv python configuration file
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
 .python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 3fa014f..f7024d9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,6 @@ language: python
 python:
   - 3.6
   - 3.5
-  - 2.7
 
 # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
 install:
diff --git a/stratatilities/auth.py b/stratatilities/auth.py
index 4e83835..bd0b4da 100644
--- a/stratatilities/auth.py
+++ b/stratatilities/auth.py
@@ -1,4 +1,5 @@
 import base64
+from getpass import getpass
 import json
 import logging
 import os
@@ -86,6 +87,27 @@ def get_vault_client(vault_addr=os.environ.get('VAULT_ADDR')):
     return hvac.Client(url=vault_addr, verify=False, token=vault_token)
 
 
+def get_vault_client_via_ldap(
+        username, mount_point='ldap',
+        vault_addr=os.environ.get('VAULT_ADDR')):
+    """ Return an authenticated vault client via LDAP.
+
+    Password will be acquired via `getpass.getpass`. Services should
+    use `get_vault_client` with IAM privileges.
+
+    InvalidRequest is raised from an incorrect password being entered
+    """
+    client = hvac.Client(url=vault_addr)
+    # with an incorrect password, an InvalidRequest is raised
+    client.auth.ldap.login(
+        username=username,
+        password=getpass('LDAP Password:'),
+        mount_point=mount_point
+    )
+    assert client.is_authenticated(), 'Client is not authenticated!'
+    return client
+
+
 def return_token(vault_addr=os.environ.get('VAULT_ADDR')):
     vault_token = os.environ.get('VAULT_TOKEN', None)
     if not vault_token:


Test patch:
diff --git a/tests/test_auth.py b/tests/test_auth.py
index 4bd63f6..37cf3ca 100644
--- a/tests/test_auth.py
+++ b/tests/test_auth.py
@@ -3,7 +3,9 @@ try:
 except ImportError:
     from unittest.mock import Mock, patch
 
-from stratatilities.auth import read_vault_secret, get_vault_client
+from stratatilities.auth import (
+    read_vault_secret, get_vault_client, get_vault_client_via_ldap
+)
 
 
 def test_get_vault_client():
@@ -22,7 +24,7 @@ def test_get_vault_client():
             )
 
 
-def test_read_vault_client():
+def test_read_vault_secret():
     client = Mock()
     path = 'path/to/sekret'
 
@@ -49,3 +51,24 @@ def test_read_vault_client():
     # return 'data' and not do a further key access
     answer = read_vault_secret(client, path, vault_value_key=None)
     assert answer == complex_value
+
+
+def test_get_vault_client_via_ldap():
+    with patch('stratatilities.auth.hvac') as hvac,\
+         patch('stratatilities.auth.getpass') as getpass:
+        username, vault_addr = 'username', 'https://vault.example.com'
+
+        hvac.Client.return_value.is_authenticated.return_value = True
+
+        client = get_vault_client_via_ldap(
+            username,
+            vault_addr=vault_addr
+        )
+        hvac.Client.assert_called_with(url=vault_addr)
+        assert hvac.Client.return_value == client
+        # the password will come from getpass when not supplied in the call
+        client.auth.ldap.login.assert_called_with(
+            username=username,
+            password=getpass.return_value,
+            mount_point='ldap'
+        )