Merge branch 'master' into aid_openid_roles_provider_integration

This commit is contained in:
Hossein Shafagh 2019-05-07 09:06:02 -07:00 committed by GitHub
commit ff583981b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 154 additions and 36 deletions

View File

@ -113,7 +113,10 @@ def retrieve_user(user_api_url, access_token):
user_params = dict(access_token=access_token, schema='profile') user_params = dict(access_token=access_token, schema='profile')
# retrieve information about the current user. # retrieve information about the current user.
r = requests.get(user_api_url, params=user_params) r = requests.get(
user_api_url,
params=user_params,
headers={'Authorization': 'Bearer {}'.format(access_token)})
profile = r.json() profile = r.json()
user = user_service.get_by_email(profile['email']) user = user_service.get_by_email(profile['email'])

View File

@ -66,8 +66,9 @@ def create_txt_record(host, value, account_number):
return zone_id, r['id'] return zone_id, r['id']
def delete_txt_record(change_id, account_number, host, value): def delete_txt_record(change_ids, account_number, host, value):
cf = cf_api_call() cf = cf_api_call()
for change_id in change_ids:
zone_id, record_id = change_id zone_id, record_id = change_id
current_app.logger.debug("Removing record with id {0}".format(record_id)) current_app.logger.debug("Removing record with id {0}".format(record_id))
try: try:

View File

@ -17,11 +17,122 @@ from flask import current_app
from lemur.common.defaults import common_name from lemur.common.defaults import common_name
from lemur.common.utils import parse_certificate from lemur.common.utils import parse_certificate
from lemur.plugins.bases import DestinationPlugin from lemur.plugins.bases import DestinationPlugin
from lemur.plugins.bases import SourcePlugin
from cryptography import x509 from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
class VaultSourcePlugin(SourcePlugin):
""" Class for importing certificates from Hashicorp Vault"""
title = 'Vault'
slug = 'vault-source'
description = 'Discovers all certificates in a given path'
author = 'Christopher Jolley'
author_url = 'https://github.com/alwaysjolley/lemur'
options = [
{
'name': 'vaultUrl',
'type': 'str',
'required': True,
'validation': '^https?://[a-zA-Z0-9.:-]+$',
'helpMessage': 'Valid URL to Hashi Vault instance'
},
{
'name': 'vaultKvApiVersion',
'type': 'select',
'value': '2',
'available': [
'1',
'2'
],
'required': True,
'helpMessage': 'Version of the Vault KV API to use'
},
{
'name': 'vaultAuthTokenFile',
'type': 'str',
'required': True,
'validation': '(/[^/]+)+',
'helpMessage': 'Must be a valid file path!'
},
{
'name': 'vaultMount',
'type': 'str',
'required': True,
'validation': r'^\S+$',
'helpMessage': 'Must be a valid Vault secrets mount name!'
},
{
'name': 'vaultPath',
'type': 'str',
'required': True,
'validation': '^([a-zA-Z0-9_-]+/?)+$',
'helpMessage': 'Must be a valid Vault secrets path'
},
{
'name': 'objectName',
'type': 'str',
'required': True,
'validation': '[0-9a-zA-Z:_-]+',
'helpMessage': 'Object Name to search'
},
]
def get_certificates(self, options, **kwargs):
"""Pull certificates from objects in Hashicorp Vault"""
data = []
cert = []
body = ''
url = self.get_option('vaultUrl', options)
token_file = self.get_option('vaultAuthTokenFile', options)
mount = self.get_option('vaultMount', options)
path = self.get_option('vaultPath', options)
obj_name = self.get_option('objectName', options)
api_version = self.get_option('vaultKvApiVersion', options)
cert_filter = '-----BEGIN CERTIFICATE-----'
cert_delimiter = '-----END CERTIFICATE-----'
with open(token_file, 'r') as tfile:
token = tfile.readline().rstrip('\n')
client = hvac.Client(url=url, token=token)
client.secrets.kv.default_kv_version = api_version
path = '{0}/{1}'.format(path, obj_name)
secret = get_secret(client, mount, path)
for cname in secret['data']:
if 'crt' in secret['data'][cname]:
cert = secret['data'][cname]['crt'].split(cert_delimiter + '\n')
elif 'pem' in secret['data'][cname]:
cert = secret['data'][cname]['pem'].split(cert_delimiter + '\n')
else:
for key in secret['data'][cname]:
if secret['data'][cname][key].startswith(cert_filter):
cert = secret['data'][cname][key].split(cert_delimiter + '\n')
break
body = cert[0] + cert_delimiter
if 'chain' in secret['data'][cname]:
chain = secret['data'][cname]['chain']
elif len(cert) > 1:
if cert[1].startswith(cert_filter):
chain = cert[1] + cert_delimiter
else:
chain = None
else:
chain = None
data.append({'body': body, 'chain': chain, 'name': cname})
return [dict(body=c['body'], chain=c.get('chain'), name=c['name']) for c in data]
def get_endpoints(self, options, **kwargs):
""" Not implemented yet """
endpoints = []
return endpoints
class VaultDestinationPlugin(DestinationPlugin): class VaultDestinationPlugin(DestinationPlugin):
"""Hashicorp Vault Destination plugin for Lemur""" """Hashicorp Vault Destination plugin for Lemur"""
title = 'Vault' title = 'Vault'
@ -61,7 +172,7 @@ class VaultDestinationPlugin(DestinationPlugin):
'name': 'vaultMount', 'name': 'vaultMount',
'type': 'str', 'type': 'str',
'required': True, 'required': True,
'validation': '^\S+$', 'validation': r'^\S+$',
'helpMessage': 'Must be a valid Vault secrets mount name!' 'helpMessage': 'Must be a valid Vault secrets mount name!'
}, },
{ {
@ -85,6 +196,7 @@ class VaultDestinationPlugin(DestinationPlugin):
'available': [ 'available': [
'Nginx', 'Nginx',
'Apache', 'Apache',
'PEM',
'no chain' 'no chain'
], ],
'required': True, 'required': True,
@ -136,8 +248,8 @@ class VaultDestinationPlugin(DestinationPlugin):
"Exception compiling regex filter: invalid filter", "Exception compiling regex filter: invalid filter",
exc_info=True) exc_info=True)
with open(token_file, 'r') as file: with open(token_file, 'r') as tfile:
token = file.readline().rstrip('\n') token = tfile.readline().rstrip('\n')
client = hvac.Client(url=url, token=token) client = hvac.Client(url=url, token=token)
client.secrets.kv.default_kv_version = api_version client.secrets.kv.default_kv_version = api_version
@ -150,11 +262,15 @@ class VaultDestinationPlugin(DestinationPlugin):
secret = get_secret(client, mount, path) secret = get_secret(client, mount, path)
secret['data'][cname] = {} secret['data'][cname] = {}
if bundle == 'Nginx' and cert_chain: if bundle == 'Nginx':
secret['data'][cname]['crt'] = '{0}\n{1}'.format(body, cert_chain) secret['data'][cname]['crt'] = '{0}\n{1}'.format(body, cert_chain)
elif bundle == 'Apache' and cert_chain: secret['data'][cname]['key'] = private_key
elif bundle == 'Apache':
secret['data'][cname]['crt'] = body secret['data'][cname]['crt'] = body
secret['data'][cname]['chain'] = cert_chain secret['data'][cname]['chain'] = cert_chain
secret['data'][cname]['key'] = private_key
elif bundle == 'PEM':
secret['data'][cname]['pem'] = '{0}\n{1}\n{2}'.format(body, cert_chain, private_key)
else: else:
secret['data'][cname]['crt'] = body secret['data'][cname]['crt'] = body
secret['data'][cname]['key'] = private_key secret['data'][cname]['key'] = private_key
@ -184,7 +300,7 @@ def get_san_list(body):
def get_secret(client, mount, path): def get_secret(client, mount, path):
""" retreiive existing data from mount path and return dictionary """ """ retreive existing data from mount path and return dictionary """
result = {'data': {}} result = {'data': {}}
try: try:
if client.secrets.kv.default_kv_version == '1': if client.secrets.kv.default_kv_version == '1':

View File

@ -18,7 +18,7 @@ invoke==1.2.0
mccabe==0.6.1 # via flake8 mccabe==0.6.1 # via flake8
nodeenv==1.3.3 nodeenv==1.3.3
pkginfo==1.5.0.1 # via twine pkginfo==1.5.0.1 # via twine
pre-commit==1.15.2 pre-commit==1.16.0
pycodestyle==2.3.1 # via flake8 pycodestyle==2.3.1 # via flake8
pyflakes==1.6.0 # via flake8 pyflakes==1.6.0 # via flake8
pygments==2.3.1 # via readme-renderer pygments==2.3.1 # via readme-renderer
@ -30,7 +30,7 @@ six==1.12.0 # via bleach, cfgv, pre-commit, readme-renderer
toml==0.10.0 # via pre-commit toml==0.10.0 # via pre-commit
tqdm==4.31.1 # via twine tqdm==4.31.1 # via twine
twine==1.13.0 twine==1.13.0
urllib3==1.24.2 # via requests urllib3==1.24.3 # via requests
virtualenv==16.5.0 # via pre-commit virtualenv==16.5.0 # via pre-commit
webencodings==0.5.1 # via bleach webencodings==0.5.1 # via bleach
zipp==0.4.0 # via importlib-metadata zipp==0.4.0 # via importlib-metadata

View File

@ -4,7 +4,7 @@
# #
# pip-compile --output-file requirements-docs.txt requirements-docs.in -U --no-index # pip-compile --output-file requirements-docs.txt requirements-docs.in -U --no-index
# #
acme==0.33.1 acme==0.34.1
alabaster==0.7.12 # via sphinx alabaster==0.7.12 # via sphinx
alembic-autogenerate-enums==0.0.2 alembic-autogenerate-enums==0.0.2
alembic==1.0.10 alembic==1.0.10
@ -17,8 +17,8 @@ babel==2.6.0 # via sphinx
bcrypt==3.1.6 bcrypt==3.1.6
billiard==3.6.0.0 billiard==3.6.0.0
blinker==1.4 blinker==1.4
boto3==1.9.138 boto3==1.9.143
botocore==1.12.138 botocore==1.12.143
celery[redis]==4.3.0 celery[redis]==4.3.0
certifi==2019.3.9 certifi==2019.3.9
certsrv==2.1.1 certsrv==2.1.1
@ -56,13 +56,12 @@ kombu==4.5.0
lockfile==0.12.2 lockfile==0.12.2
mako==1.0.9 mako==1.0.9
markupsafe==1.1.1 markupsafe==1.1.1
marshmallow-sqlalchemy==0.16.2 marshmallow-sqlalchemy==0.16.3
marshmallow==2.19.2 marshmallow==2.19.2
mock==2.0.0 mock==3.0.4
ndg-httpsclient==0.5.1 ndg-httpsclient==0.5.1
packaging==19.0 # via sphinx packaging==19.0 # via sphinx
paramiko==2.4.2 paramiko==2.4.2
pbr==5.2.0
pem==19.1.0 pem==19.1.0
psycopg2==2.8.2 psycopg2==2.8.2
pyasn1-modules==0.2.5 pyasn1-modules==0.2.5
@ -101,7 +100,7 @@ sqlalchemy-utils==0.33.11
sqlalchemy==1.3.3 sqlalchemy==1.3.3
tabulate==0.8.3 tabulate==0.8.3
twofish==0.3.0 twofish==0.3.0
urllib3==1.24.2 urllib3==1.24.3
vine==1.3.0 vine==1.3.0
werkzeug==0.15.2 werkzeug==0.15.2
xmltodict==0.12.0 xmltodict==0.12.0

View File

@ -9,9 +9,9 @@ atomicwrites==1.3.0 # via pytest
attrs==19.1.0 # via pytest attrs==19.1.0 # via pytest
aws-sam-translator==1.11.0 # via cfn-lint aws-sam-translator==1.11.0 # via cfn-lint
aws-xray-sdk==2.4.2 # via moto aws-xray-sdk==2.4.2 # via moto
boto3==1.9.138 # via aws-sam-translator, moto boto3==1.9.143 # via aws-sam-translator, moto
boto==2.49.0 # via moto boto==2.49.0 # via moto
botocore==1.12.138 # via aws-xray-sdk, boto3, moto, s3transfer botocore==1.12.143 # via aws-xray-sdk, boto3, moto, s3transfer
certifi==2019.3.9 # via requests certifi==2019.3.9 # via requests
cffi==1.12.3 # via cryptography cffi==1.12.3 # via cryptography
cfn-lint==0.19.1 # via moto cfn-lint==0.19.1 # via moto
@ -38,11 +38,10 @@ jsonpickle==1.1 # via aws-xray-sdk
jsonpointer==2.0 # via jsonpatch jsonpointer==2.0 # via jsonpatch
jsonschema==2.6.0 # via aws-sam-translator, cfn-lint jsonschema==2.6.0 # via aws-sam-translator, cfn-lint
markupsafe==1.1.1 # via jinja2 markupsafe==1.1.1 # via jinja2
mock==2.0.0 # via moto mock==3.0.4 # via moto
more-itertools==7.0.0 # via pytest more-itertools==7.0.0 # via pytest
moto==1.3.8 moto==1.3.8
nose==1.3.7 nose==1.3.7
pbr==5.2.0 # via mock
pluggy==0.9.0 # via pytest pluggy==0.9.0 # via pytest
py==1.8.0 # via pytest py==1.8.0 # via pytest
pyasn1==0.4.5 # via rsa pyasn1==0.4.5 # via rsa
@ -62,7 +61,7 @@ rsa==4.0 # via python-jose
s3transfer==0.2.0 # via boto3 s3transfer==0.2.0 # via boto3
six==1.12.0 # via aws-sam-translator, cfn-lint, cryptography, docker, docker-pycreds, faker, freezegun, mock, moto, pytest, python-dateutil, python-jose, requests-mock, responses, websocket-client six==1.12.0 # via aws-sam-translator, cfn-lint, cryptography, docker, docker-pycreds, faker, freezegun, mock, moto, pytest, python-dateutil, python-jose, requests-mock, responses, websocket-client
text-unidecode==1.2 # via faker text-unidecode==1.2 # via faker
urllib3==1.24.2 # via botocore, requests urllib3==1.24.3 # via botocore, requests
websocket-client==0.56.0 # via docker websocket-client==0.56.0 # via docker
werkzeug==0.15.2 # via flask, moto, pytest-flask werkzeug==0.15.2 # via flask, moto, pytest-flask
wrapt==1.11.1 # via aws-xray-sdk wrapt==1.11.1 # via aws-xray-sdk

View File

@ -4,7 +4,7 @@
# #
# pip-compile --output-file requirements.txt requirements.in -U --no-index # pip-compile --output-file requirements.txt requirements.in -U --no-index
# #
acme==0.33.1 acme==0.34.1
alembic-autogenerate-enums==0.0.2 alembic-autogenerate-enums==0.0.2
alembic==1.0.10 # via flask-migrate alembic==1.0.10 # via flask-migrate
amqp==2.4.2 # via kombu amqp==2.4.2 # via kombu
@ -15,8 +15,8 @@ asyncpool==1.0
bcrypt==3.1.6 # via flask-bcrypt, paramiko bcrypt==3.1.6 # via flask-bcrypt, paramiko
billiard==3.6.0.0 # via celery billiard==3.6.0.0 # via celery
blinker==1.4 # via flask-mail, flask-principal, raven blinker==1.4 # via flask-mail, flask-principal, raven
boto3==1.9.138 boto3==1.9.143
botocore==1.12.138 botocore==1.12.143
celery[redis]==4.3.0 celery[redis]==4.3.0
certifi==2019.3.9 certifi==2019.3.9
certsrv==2.1.1 certsrv==2.1.1
@ -53,12 +53,11 @@ kombu==4.5.0
lockfile==0.12.2 lockfile==0.12.2
mako==1.0.9 # via alembic mako==1.0.9 # via alembic
markupsafe==1.1.1 # via jinja2, mako markupsafe==1.1.1 # via jinja2, mako
marshmallow-sqlalchemy==0.16.2 marshmallow-sqlalchemy==0.16.3
marshmallow==2.19.2 marshmallow==2.19.2
mock==2.0.0 # via acme mock==3.0.4 # via acme
ndg-httpsclient==0.5.1 ndg-httpsclient==0.5.1
paramiko==2.4.2 paramiko==2.4.2
pbr==5.2.0 # via mock
pem==19.1.0 pem==19.1.0
psycopg2==2.8.2 psycopg2==2.8.2
pyasn1-modules==0.2.5 # via pyjks, python-ldap pyasn1-modules==0.2.5 # via pyjks, python-ldap
@ -86,7 +85,7 @@ sqlalchemy-utils==0.33.11
sqlalchemy==1.3.3 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils sqlalchemy==1.3.3 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils
tabulate==0.8.3 tabulate==0.8.3
twofish==0.3.0 # via pyjks twofish==0.3.0 # via pyjks
urllib3==1.24.2 # via botocore, requests urllib3==1.24.3 # via botocore, requests
vine==1.3.0 # via amqp, celery vine==1.3.0 # via amqp, celery
werkzeug==0.15.2 # via flask werkzeug==0.15.2 # via flask
xmltodict==0.12.0 xmltodict==0.12.0

View File

@ -155,6 +155,7 @@ setup(
'digicert_cis_source = lemur.plugins.lemur_digicert.plugin:DigiCertCISSourcePlugin', 'digicert_cis_source = lemur.plugins.lemur_digicert.plugin:DigiCertCISSourcePlugin',
'csr_export = lemur.plugins.lemur_csr.plugin:CSRExportPlugin', 'csr_export = lemur.plugins.lemur_csr.plugin:CSRExportPlugin',
'sftp_destination = lemur.plugins.lemur_sftp.plugin:SFTPDestinationPlugin', 'sftp_destination = lemur.plugins.lemur_sftp.plugin:SFTPDestinationPlugin',
'vault_source = lemur.plugins.lemur_vault_dest.plugin:VaultSourcePlugin',
'vault_desination = lemur.plugins.lemur_vault_dest.plugin:VaultDestinationPlugin', 'vault_desination = lemur.plugins.lemur_vault_dest.plugin:VaultDestinationPlugin',
'adcs_issuer = lemur.plugins.lemur_adcs.plugin:ADCSIssuerPlugin', 'adcs_issuer = lemur.plugins.lemur_adcs.plugin:ADCSIssuerPlugin',
'adcs_source = lemur.plugins.lemur_adcs.plugin:ADCSSourcePlugin' 'adcs_source = lemur.plugins.lemur_adcs.plugin:ADCSSourcePlugin'