From 7f88c24e8374f669ba1e12c3d5ff06892de3b04c Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Thu, 17 Jan 2019 14:56:04 -0800 Subject: [PATCH 1/9] Fix LetsEncrypt Dyn flow for duplicate CN/SAN --- lemur/common/utils.py | 11 +++++++++++ lemur/plugins/lemur_acme/dyn.py | 8 ++++++-- lemur/sources/service.py | 5 +++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lemur/common/utils.py b/lemur/common/utils.py index 62e59d69..f26f07df 100644 --- a/lemur/common/utils.py +++ b/lemur/common/utils.py @@ -12,6 +12,7 @@ import string import sqlalchemy from cryptography import x509 from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import rsa, ec from cryptography.hazmat.primitives.serialization import load_pem_private_key from flask_restful.reqparse import RequestParser @@ -226,3 +227,13 @@ def truthiness(s): """If input string resembles something truthy then return True, else False.""" return s.lower() in ('true', 'yes', 'on', 't', '1') + + +def find_matching_certificates_by_hash(cert, matching_certs): + """Given a Cryptography-formatted certificate cert, and Lemur-formatted certificates (matching_certs), + determine if any of the certificate hashes match and return the matches.""" + matching = [] + for c in matching_certs: + if parse_certificate(c).fingerprint(hashes.SHA256()) == cert.body.fingerprint(hashes.SHA256()): + matching.append(c) + return matching diff --git a/lemur/plugins/lemur_acme/dyn.py b/lemur/plugins/lemur_acme/dyn.py index 9bab3a65..5d419f7f 100644 --- a/lemur/plugins/lemur_acme/dyn.py +++ b/lemur/plugins/lemur_acme/dyn.py @@ -5,7 +5,7 @@ import dns.exception import dns.name import dns.query import dns.resolver -from dyn.tm.errors import DynectCreateError +from dyn.tm.errors import DynectCreateError, DynectGetError from dyn.tm.session import DynectSession from dyn.tm.zones import Node, Zone, get_all_zones from flask import current_app @@ -119,7 +119,11 @@ def delete_txt_record(change_id, account_number, domain, token): zone = Zone(zone_name) node = Node(zone_name, fqdn) - all_txt_records = node.get_all_records_by_type('TXT') + try: + all_txt_records = node.get_all_records_by_type('TXT') + except DynectGetError: + # No Text Records remain or host is not in the zone anymore because all records have been deleted. + return for txt_record in all_txt_records: if txt_record.txtdata == ("{}".format(token)): current_app.logger.debug("Deleting TXT record name: {0}".format(fqdn)) diff --git a/lemur/sources/service.py b/lemur/sources/service.py index 227f1bce..55d2ee62 100644 --- a/lemur/sources/service.py +++ b/lemur/sources/service.py @@ -17,7 +17,7 @@ from lemur.endpoints import service as endpoint_service from lemur.destinations import service as destination_service from lemur.certificates.schemas import CertificateUploadInputSchema -from lemur.common.utils import parse_certificate +from lemur.common.utils import find_matching_certificates_by_hash, parse_certificate from lemur.common.defaults import serial from lemur.plugins.base import plugins @@ -126,7 +126,8 @@ def sync_certificates(source, user): if not exists: cert = parse_certificate(certificate['body']) - exists = certificate_service.get_by_serial(serial(cert)) + matching_serials = certificate_service.get_by_serial(serial(cert)) + exists = find_matching_certificates_by_hash(cert, matching_serials) if not certificate.get('owner'): certificate['owner'] = user.email From d689f5cda3aad42ff7b6363c40332160ca3a395a Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Thu, 17 Jan 2019 14:59:57 -0800 Subject: [PATCH 2/9] Fix LetsEncrypt for duplicate CN/SAN --- requirements-dev.txt | 5 ++--- requirements-docs.txt | 18 +++++++++--------- requirements-tests.txt | 8 ++++---- requirements.txt | 16 ++++++++-------- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 21156588..c1f55581 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,12 +14,11 @@ flake8==3.5.0 identify==1.1.8 # via pre-commit idna==2.8 # via requests importlib-metadata==0.8 # via pre-commit -importlib-resources==1.0.2 # via pre-commit invoke==1.2.0 mccabe==0.6.1 # via flake8 nodeenv==1.3.3 pkginfo==1.5.0.1 # via twine -pre-commit==1.14.0 +pre-commit==1.14.2 pycodestyle==2.3.1 # via flake8 pyflakes==1.6.0 # via flake8 pygments==2.3.1 # via readme-renderer @@ -29,7 +28,7 @@ requests-toolbelt==0.8.0 # via twine requests==2.21.0 # via requests-toolbelt, twine six==1.12.0 # via bleach, cfgv, pre-commit, readme-renderer toml==0.10.0 # via pre-commit -tqdm==4.29.0 # via twine +tqdm==4.29.1 # via twine twine==1.12.1 urllib3==1.24.1 # via requests virtualenv==16.2.0 # via pre-commit diff --git a/requirements-docs.txt b/requirements-docs.txt index f3182456..a7df5395 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -7,18 +7,18 @@ acme==0.30.0 alabaster==0.7.12 # via sphinx alembic-autogenerate-enums==0.0.2 -alembic==1.0.5 -amqp==2.3.2 +alembic==1.0.6 +amqp==2.4.0 aniso8601==4.1.0 arrow==0.13.0 asn1crypto==0.24.0 asyncpool==1.0 babel==2.6.0 # via sphinx -bcrypt==3.1.5 +bcrypt==3.1.6 billiard==3.5.0.5 blinker==1.4 -boto3==1.9.76 -botocore==1.12.76 +boto3==1.9.80 +botocore==1.12.80 celery[redis]==4.2.1 certifi==2018.11.29 cffi==1.11.5 @@ -54,7 +54,7 @@ lockfile==0.12.2 mako==1.0.7 markupsafe==1.1.0 marshmallow-sqlalchemy==0.15.0 -marshmallow==2.17.0 +marshmallow==2.18.0 mock==2.0.0 ndg-httpsclient==0.5.1 packaging==18.0 # via sphinx @@ -69,7 +69,7 @@ pygments==2.3.1 # via sphinx pyjwt==1.7.1 pynacl==1.3.0 pyopenssl==18.0.0 -pyparsing==2.3.0 # via packaging +pyparsing==2.3.1 # via packaging pyrfc3339==1.1 python-dateutil==2.7.5 python-editor==1.0.3 @@ -87,8 +87,8 @@ sphinx-rtd-theme==0.4.2 sphinx==1.8.3 sphinxcontrib-httpdomain==1.7.0 sphinxcontrib-websupport==1.1.0 # via sphinx -sqlalchemy-utils==0.33.10 -sqlalchemy==1.2.15 +sqlalchemy-utils==0.33.11 +sqlalchemy==1.2.16 tabulate==0.8.2 urllib3==1.24.1 vine==1.2.0 diff --git a/requirements-tests.txt b/requirements-tests.txt index 490d74d1..2d54dce6 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -8,9 +8,9 @@ asn1crypto==0.24.0 # via cryptography atomicwrites==1.2.1 # via pytest attrs==18.2.0 # via pytest aws-xray-sdk==0.95 # via moto -boto3==1.9.76 # via moto +boto3==1.9.80 # via moto boto==2.49.0 # via moto -botocore==1.12.76 # via boto3, moto, s3transfer +botocore==1.12.80 # via boto3, moto, s3transfer certifi==2018.11.29 # via requests cffi==1.11.5 # via cryptography chardet==3.0.4 # via requests @@ -18,7 +18,7 @@ click==7.0 # via flask coverage==4.5.2 cryptography==2.4.2 # via moto docker-pycreds==0.4.0 # via docker -docker==3.6.0 # via moto +docker==3.7.0 # via moto docutils==0.14 # via botocore ecdsa==0.13 # via python-jose factory-boy==2.11.1 @@ -46,7 +46,7 @@ pycryptodome==3.7.2 # via python-jose pyflakes==2.0.0 pytest-flask==0.14.0 pytest-mock==1.10.0 -pytest==4.1.0 +pytest==4.1.1 python-dateutil==2.7.5 # via botocore, faker, freezegun, moto python-jose==2.0.2 # via moto pytz==2018.9 # via moto diff --git a/requirements.txt b/requirements.txt index bc72db0a..79268c8a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,17 +6,17 @@ # acme==0.30.0 alembic-autogenerate-enums==0.0.2 -alembic==1.0.5 # via flask-migrate -amqp==2.3.2 # via kombu +alembic==1.0.6 # via flask-migrate +amqp==2.4.0 # via kombu aniso8601==4.1.0 # via flask-restful arrow==0.13.0 asn1crypto==0.24.0 # via cryptography asyncpool==1.0 -bcrypt==3.1.5 # via flask-bcrypt, paramiko +bcrypt==3.1.6 # via flask-bcrypt, paramiko billiard==3.5.0.5 # via celery blinker==1.4 # via flask-mail, flask-principal, raven -boto3==1.9.76 -botocore==1.12.76 +boto3==1.9.80 +botocore==1.12.80 celery[redis]==4.2.1 certifi==2018.11.29 cffi==1.11.5 # via bcrypt, cryptography, pynacl @@ -51,7 +51,7 @@ lockfile==0.12.2 mako==1.0.7 # via alembic markupsafe==1.1.0 # via jinja2, mako marshmallow-sqlalchemy==0.15.0 -marshmallow==2.17.0 +marshmallow==2.18.0 mock==2.0.0 # via acme ndg-httpsclient==0.5.1 paramiko==2.4.2 @@ -77,8 +77,8 @@ requests[security]==2.21.0 retrying==1.3.3 s3transfer==0.1.13 # via boto3 six==1.12.0 -sqlalchemy-utils==0.33.10 -sqlalchemy==1.2.15 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils +sqlalchemy-utils==0.33.11 +sqlalchemy==1.2.16 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils tabulate==0.8.2 urllib3==1.24.1 # via botocore, requests vine==1.2.0 # via amqp From cb35f19d6ca4b0d84ed2f96e1e28ca482556411d Mon Sep 17 00:00:00 2001 From: Ronald Moesbergen Date: Mon, 21 Jan 2019 10:22:03 +0100 Subject: [PATCH 3/9] Add 'delete_cert' to enum log_type in logs table --- lemur/logs/models.py | 2 +- lemur/migrations/versions/9f79024fe67b_.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 lemur/migrations/versions/9f79024fe67b_.py diff --git a/lemur/logs/models.py b/lemur/logs/models.py index d4239e59..9f982c24 100644 --- a/lemur/logs/models.py +++ b/lemur/logs/models.py @@ -18,6 +18,6 @@ class Log(db.Model): __tablename__ = 'logs' id = Column(Integer, primary_key=True) certificate_id = Column(Integer, ForeignKey('certificates.id')) - log_type = Column(Enum('key_view', 'create_cert', 'update_cert', 'revoke_cert', name='log_type'), nullable=False) + log_type = Column(Enum('key_view', 'create_cert', 'update_cert', 'revoke_cert', 'delete_cert', name='log_type'), nullable=False) logged_at = Column(ArrowType(), PassiveDefault(func.now()), nullable=False) user_id = Column(Integer, ForeignKey('users.id'), nullable=False) diff --git a/lemur/migrations/versions/9f79024fe67b_.py b/lemur/migrations/versions/9f79024fe67b_.py new file mode 100644 index 00000000..ad22d5f3 --- /dev/null +++ b/lemur/migrations/versions/9f79024fe67b_.py @@ -0,0 +1,22 @@ +""" Add delete_cert to log_type enum + +Revision ID: 9f79024fe67b +Revises: ee827d1e1974 +Create Date: 2019-01-03 15:36:59.181911 + +""" + +# revision identifiers, used by Alembic. +revision = '9f79024fe67b' +down_revision = 'ee827d1e1974' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.sync_enum_values('public', 'log_type', ['create_cert', 'key_view', 'revoke_cert', 'update_cert'], ['create_cert', 'delete_cert', 'key_view', 'revoke_cert', 'update_cert']) + + +def downgrade(): + op.sync_enum_values('public', 'log_type', ['create_cert', 'delete_cert', 'key_view', 'revoke_cert', 'update_cert'], ['create_cert', 'key_view', 'revoke_cert', 'update_cert']) From 4c4fbf3e48d3644ac2869d7d5e1688248fb6f597 Mon Sep 17 00:00:00 2001 From: Ronald Moesbergen Date: Mon, 21 Jan 2019 10:25:28 +0100 Subject: [PATCH 4/9] Implement certificates delete API call by marking a cert as 'deleted' in the database. Only certificates that have expired can be deleted. --- lemur/certificates/views.py | 46 ++++++++++++++++++++++++++++++++ lemur/tests/conftest.py | 12 ++++++++- lemur/tests/factories.py | 7 ++++- lemur/tests/test_certificates.py | 19 ++++++++++--- 4 files changed, 78 insertions(+), 6 deletions(-) diff --git a/lemur/certificates/views.py b/lemur/certificates/views.py index 54c60924..948c44d6 100644 --- a/lemur/certificates/views.py +++ b/lemur/certificates/views.py @@ -6,6 +6,7 @@ .. moduleauthor:: Kevin Glisson """ import base64 +import arrow from builtins import str from flask import Blueprint, make_response, jsonify, g @@ -660,6 +661,51 @@ class Certificates(AuthenticatedResource): log_service.create(g.current_user, 'update_cert', certificate=cert) return cert + def delete(self, certificate_id, data=None): + """ + .. http:delete:: /certificates/1 + + Delete a certificate + + **Example request**: + + .. sourcecode:: http + + DELETE /certificates/1 HTTP/1.1 + Host: example.com + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + + :reqheader Authorization: OAuth token to authenticate + :statuscode 204: no error + :statuscode 403: unauthenticated + :statusoode 404: certificate not found + + """ + cert = service.get(certificate_id) + + if not cert: + return dict(message="Cannot find specified certificate"), 404 + + # allow creators + if g.current_user != cert.user: + owner_role = role_service.get_by_name(cert.owner) + permission = CertificatePermission(owner_role, [x.name for x in cert.roles]) + + if not permission.can(): + return dict(message='You are not authorized to delete this certificate'), 403 + + if arrow.get(cert.not_after) > arrow.utcnow(): + return dict(message='Certificate is still valid, only expired certificates can be deleted'), 412 + + service.update(certificate_id, deleted=True) + log_service.create(g.current_user, 'delete_cert', certificate=cert) + return '', 204 + class NotificationCertificatesList(AuthenticatedResource): """ Defines the 'certificates' endpoint """ diff --git a/lemur/tests/conftest.py b/lemur/tests/conftest.py index 9a48eb94..3f5fa2d8 100644 --- a/lemur/tests/conftest.py +++ b/lemur/tests/conftest.py @@ -15,7 +15,8 @@ from lemur.tests.vectors import SAN_CERT_KEY, INTERMEDIATE_KEY from .factories import ApiKeyFactory, AuthorityFactory, NotificationFactory, DestinationFactory, \ CertificateFactory, UserFactory, RoleFactory, SourceFactory, EndpointFactory, \ - RotationPolicyFactory, PendingCertificateFactory, AsyncAuthorityFactory, CryptoAuthorityFactory + RotationPolicyFactory, PendingCertificateFactory, AsyncAuthorityFactory, InvalidCertificateFactory, \ + CryptoAuthorityFactory def pytest_runtest_setup(item): @@ -168,6 +169,15 @@ def pending_certificate(session): return p +@pytest.fixture +def invalid_certificate(session): + u = UserFactory() + a = AsyncAuthorityFactory() + i = InvalidCertificateFactory(user=u, authority=a) + session.commit() + return i + + @pytest.fixture def admin_user(session): u = UserFactory() diff --git a/lemur/tests/factories.py b/lemur/tests/factories.py index 3717c64d..a4af3d43 100644 --- a/lemur/tests/factories.py +++ b/lemur/tests/factories.py @@ -20,7 +20,7 @@ from lemur.policies.models import RotationPolicy from lemur.api_keys.models import ApiKey from .vectors import SAN_CERT_STR, SAN_CERT_KEY, CSR_STR, INTERMEDIATE_CERT_STR, ROOTCA_CERT_STR, INTERMEDIATE_KEY, \ - WILDCARD_CERT_KEY + WILDCARD_CERT_KEY, INVALID_CERT_STR class BaseFactory(SQLAlchemyModelFactory): @@ -137,6 +137,11 @@ class CACertificateFactory(CertificateFactory): private_key = INTERMEDIATE_KEY +class InvalidCertificateFactory(CertificateFactory): + body = INVALID_CERT_STR + private_key = '' + + class AuthorityFactory(BaseFactory): """Authority factory.""" name = Sequence(lambda n: 'authority{0}'.format(n)) diff --git a/lemur/tests/test_certificates.py b/lemur/tests/test_certificates.py index a1df1c0d..4d412563 100644 --- a/lemur/tests/test_certificates.py +++ b/lemur/tests/test_certificates.py @@ -647,15 +647,26 @@ def test_certificate_put_with_data(client, certificate, issuer_plugin): @pytest.mark.parametrize("token,status", [ - (VALID_USER_HEADER_TOKEN, 405), - (VALID_ADMIN_HEADER_TOKEN, 405), - (VALID_ADMIN_API_TOKEN, 405), - ('', 405) + (VALID_USER_HEADER_TOKEN, 403), + (VALID_ADMIN_HEADER_TOKEN, 412), + (VALID_ADMIN_API_TOKEN, 412), + ('', 401) ]) def test_certificate_delete(client, token, status): assert client.delete(api.url_for(Certificates, certificate_id=1), headers=token).status_code == status +@pytest.mark.parametrize("token,status", [ + (VALID_USER_HEADER_TOKEN, 403), + (VALID_ADMIN_HEADER_TOKEN, 204), + (VALID_ADMIN_API_TOKEN, 204), + ('', 401) +]) +def test_invalid_certificate_delete(client, invalid_certificate, token, status): + assert client.delete( + api.url_for(Certificates, certificate_id=invalid_certificate.id), headers=token).status_code == status + + @pytest.mark.parametrize("token,status", [ (VALID_USER_HEADER_TOKEN, 405), (VALID_ADMIN_HEADER_TOKEN, 405), From 4b893ab5b49b622a1634ef54e7323b219390bf0f Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Fri, 5 Jan 2018 13:08:07 +0200 Subject: [PATCH 5/9] Expose full certificate RFC 4514 Distinguished Name string Using rfc4514_string() method added in cryptography version 2.5. --- lemur/certificates/models.py | 4 ++++ lemur/certificates/schemas.py | 1 + lemur/static/app/angular/certificates/view/view.tpl.html | 2 ++ lemur/tests/test_certificates.py | 6 ++++++ requirements.txt | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lemur/certificates/models.py b/lemur/certificates/models.py index 3eaba746..34305cc2 100644 --- a/lemur/certificates/models.py +++ b/lemur/certificates/models.py @@ -227,6 +227,10 @@ class Certificate(db.Model): def location(self): return defaults.location(self.parsed_cert) + @property + def distinguished_name(self): + return self.parsed_cert.subject.rfc4514_string() + @property def key_type(self): if isinstance(self.parsed_cert.public_key(), rsa.RSAPublicKey): diff --git a/lemur/certificates/schemas.py b/lemur/certificates/schemas.py index 6b457086..946bd541 100644 --- a/lemur/certificates/schemas.py +++ b/lemur/certificates/schemas.py @@ -206,6 +206,7 @@ class CertificateOutputSchema(LemurOutputSchema): cn = fields.String() common_name = fields.String(attribute='cn') + distinguished_name = fields.String() not_after = fields.DateTime() validity_end = ArrowDateTime(attribute='not_after') diff --git a/lemur/static/app/angular/certificates/view/view.tpl.html b/lemur/static/app/angular/certificates/view/view.tpl.html index ba17ffa6..28b4e08e 100644 --- a/lemur/static/app/angular/certificates/view/view.tpl.html +++ b/lemur/static/app/angular/certificates/view/view.tpl.html @@ -83,6 +83,8 @@
+
Distinguished Name
+
{{ certificate.distinguishedName }}
Certificate Authority
{{ certificate.authority ? certificate.authority.name : "Imported" }} ({{ certificate.issuer }})
Serial
diff --git a/lemur/tests/test_certificates.py b/lemur/tests/test_certificates.py index a1df1c0d..db2d27cf 100644 --- a/lemur/tests/test_certificates.py +++ b/lemur/tests/test_certificates.py @@ -619,6 +619,12 @@ def test_certificate_get_body(client): response_body = client.get(api.url_for(Certificates, certificate_id=1), headers=VALID_USER_HEADER_TOKEN).json assert response_body['serial'] == '211983098819107449768450703123665283596' assert response_body['serialHex'] == '9F7A75B39DAE4C3F9524C68B06DA6A0C' + assert response_body['distinguishedName'] == ('CN=LemurTrust Unittests Class 1 CA 2018,' + 'O=LemurTrust Enterprises Ltd,' + 'OU=Unittesting Operations Center,' + 'C=EE,' + 'ST=N/A,' + 'L=Earth') @pytest.mark.parametrize("token,status", [ diff --git a/requirements.txt b/requirements.txt index 79268c8a..d700de42 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ cffi==1.11.5 # via bcrypt, cryptography, pynacl chardet==3.0.4 # via requests click==7.0 # via flask cloudflare==2.1.0 -cryptography==2.4.2 +cryptography==2.5 dnspython3==1.15.0 dnspython==1.15.0 # via dnspython3 docutils==0.14 # via botocore From b4d1b80e04c6ead46635977fc9d21161718eb6e5 Mon Sep 17 00:00:00 2001 From: alwaysjolley Date: Tue, 29 Jan 2019 10:13:44 -0500 Subject: [PATCH 6/9] Adding support for cfssl auth mode signing --- lemur/plugins/lemur_cfssl/plugin.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lemur/plugins/lemur_cfssl/plugin.py b/lemur/plugins/lemur_cfssl/plugin.py index 030f290a..ead633bc 100644 --- a/lemur/plugins/lemur_cfssl/plugin.py +++ b/lemur/plugins/lemur_cfssl/plugin.py @@ -10,6 +10,9 @@ import json import requests +import base64 +import hmac +import hashlib from flask import current_app @@ -48,6 +51,21 @@ class CfsslIssuerPlugin(IssuerPlugin): data = {'certificate_request': csr} data = json.dumps(data) + try: + hex_key = current_app.config.get('CFSSL_KEY') + key=bytes.fromhex(hex_key) + except: + #unable to find CFSSL_KEY in config, continue using normal sign method + pass + else: + data=data.encode() + + token = base64.b64encode(hmac.new(key,data,digestmod=hashlib.sha256).digest()) + data = base64.b64encode(data) + + data = json.dumps({'token': token.decode('utf-8'), 'request': data.decode('utf-8')}) + + url = "{0}{1}".format(current_app.config.get('CFSSL_URL'), '/api/v1/cfssl/authsign') response = self.session.post(url, data=data.encode(encoding='utf_8', errors='strict')) if response.status_code > 399: metrics.send('cfssl_create_certificate_failure', 'counter', 1) From 254a3079f2ceb7408b42d3ec9626cbf69d4abb7e Mon Sep 17 00:00:00 2001 From: alwaysjolley Date: Tue, 29 Jan 2019 11:01:55 -0500 Subject: [PATCH 7/9] fix whitespace --- lemur/plugins/lemur_cfssl/plugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lemur/plugins/lemur_cfssl/plugin.py b/lemur/plugins/lemur_cfssl/plugin.py index ead633bc..d2abc2aa 100644 --- a/lemur/plugins/lemur_cfssl/plugin.py +++ b/lemur/plugins/lemur_cfssl/plugin.py @@ -53,14 +53,14 @@ class CfsslIssuerPlugin(IssuerPlugin): try: hex_key = current_app.config.get('CFSSL_KEY') - key=bytes.fromhex(hex_key) + key = bytes.fromhex(hex_key) except: #unable to find CFSSL_KEY in config, continue using normal sign method pass else: - data=data.encode() + data = data.encode() - token = base64.b64encode(hmac.new(key,data,digestmod=hashlib.sha256).digest()) + token = base64.b64encode(hmac.new(key, data, digestmod=hashlib.sha256).digest()) data = base64.b64encode(data) data = json.dumps({'token': token.decode('utf-8'), 'request': data.decode('utf-8')}) From c68a9cf80acd651ad18fe48a6c7d0e0a43ef7f29 Mon Sep 17 00:00:00 2001 From: alwaysjolley Date: Tue, 29 Jan 2019 11:10:56 -0500 Subject: [PATCH 8/9] fixing linting issues --- lemur/plugins/lemur_cfssl/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lemur/plugins/lemur_cfssl/plugin.py b/lemur/plugins/lemur_cfssl/plugin.py index d2abc2aa..4bfefc85 100644 --- a/lemur/plugins/lemur_cfssl/plugin.py +++ b/lemur/plugins/lemur_cfssl/plugin.py @@ -54,8 +54,8 @@ class CfsslIssuerPlugin(IssuerPlugin): try: hex_key = current_app.config.get('CFSSL_KEY') key = bytes.fromhex(hex_key) - except: - #unable to find CFSSL_KEY in config, continue using normal sign method + except (ValueError, NameError): + # unable to find CFSSL_KEY in config, continue using normal sign method pass else: data = data.encode() From d2317acfc550b35a1ad40b449c37d66e5f258cf8 Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Tue, 29 Jan 2019 15:17:40 -0800 Subject: [PATCH 9/9] allowing create_user with noninteractive PW;updating reqs --- lemur/manage.py | 19 +++++++++++-------- requirements-dev.txt | 11 ++++++----- requirements-docs.txt | 24 ++++++++++++------------ requirements-tests.txt | 18 +++++++++--------- requirements.txt | 24 ++++++++++++------------ 5 files changed, 50 insertions(+), 46 deletions(-) diff --git a/lemur/manage.py b/lemur/manage.py index b972e8a5..184b9aa6 100755 --- a/lemur/manage.py +++ b/lemur/manage.py @@ -273,10 +273,11 @@ class CreateUser(Command): Option('-u', '--username', dest='username', required=True), Option('-e', '--email', dest='email', required=True), Option('-a', '--active', dest='active', default=True), - Option('-r', '--roles', dest='roles', action='append', default=[]) + Option('-r', '--roles', dest='roles', action='append', default=[]), + Option('-p', '--password', dest='password', default=None) ) - def run(self, username, email, active, roles): + def run(self, username, email, active, roles, password): role_objs = [] for r in roles: role_obj = role_service.get_by_name(r) @@ -286,14 +287,16 @@ class CreateUser(Command): sys.stderr.write("[!] Cannot find role {0}\n".format(r)) sys.exit(1) - password1 = prompt_pass("Password") - password2 = prompt_pass("Confirm Password") + if not password: + password1 = prompt_pass("Password") + password2 = prompt_pass("Confirm Password") + password = password1 - if password1 != password2: - sys.stderr.write("[!] Passwords do not match!\n") - sys.exit(1) + if password1 != password2: + sys.stderr.write("[!] Passwords do not match!\n") + sys.exit(1) - user_service.create(username, password1, email, active, None, role_objs) + user_service.create(username, password, email, active, None, role_objs) sys.stdout.write("[+] Created new user: {0}\n".format(username)) diff --git a/requirements-dev.txt b/requirements-dev.txt index c1f55581..ac35f3e9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,16 +4,17 @@ # # pip-compile --no-index --output-file requirements-dev.txt requirements-dev.in # -aspy.yaml==1.1.1 # via pre-commit +aspy.yaml==1.1.2 # via pre-commit bleach==3.1.0 # via readme-renderer certifi==2018.11.29 # via requests cfgv==1.4.0 # via pre-commit chardet==3.0.4 # via requests docutils==0.14 # via readme-renderer flake8==3.5.0 -identify==1.1.8 # via pre-commit +identify==1.2.1 # via pre-commit idna==2.8 # via requests importlib-metadata==0.8 # via pre-commit +importlib-resources==1.0.2 # via pre-commit invoke==1.2.0 mccabe==0.6.1 # via flake8 nodeenv==1.3.3 @@ -24,13 +25,13 @@ pyflakes==1.6.0 # via flake8 pygments==2.3.1 # via readme-renderer pyyaml==3.13 # via aspy.yaml, pre-commit readme-renderer==24.0 # via twine -requests-toolbelt==0.8.0 # via twine +requests-toolbelt==0.9.0 # via twine requests==2.21.0 # via requests-toolbelt, twine six==1.12.0 # via bleach, cfgv, pre-commit, readme-renderer toml==0.10.0 # via pre-commit -tqdm==4.29.1 # via twine +tqdm==4.30.0 # via twine twine==1.12.1 urllib3==1.24.1 # via requests -virtualenv==16.2.0 # via pre-commit +virtualenv==16.3.0 # via pre-commit webencodings==0.5.1 # via bleach zipp==0.3.3 # via importlib-metadata diff --git a/requirements-docs.txt b/requirements-docs.txt index a7df5395..15085766 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -4,10 +4,10 @@ # # pip-compile --no-index --output-file requirements-docs.txt requirements-docs.in # -acme==0.30.0 +acme==0.30.2 alabaster==0.7.12 # via sphinx alembic-autogenerate-enums==0.0.2 -alembic==1.0.6 +alembic==1.0.7 amqp==2.4.0 aniso8601==4.1.0 arrow==0.13.0 @@ -17,15 +17,15 @@ babel==2.6.0 # via sphinx bcrypt==3.1.6 billiard==3.5.0.5 blinker==1.4 -boto3==1.9.80 -botocore==1.12.80 +boto3==1.9.86 +botocore==1.12.86 celery[redis]==4.2.1 certifi==2018.11.29 cffi==1.11.5 chardet==3.0.4 click==7.0 cloudflare==2.1.0 -cryptography==2.4.2 +cryptography==2.5 dnspython3==1.15.0 dnspython==1.15.0 docutils==0.14 @@ -57,18 +57,18 @@ marshmallow-sqlalchemy==0.15.0 marshmallow==2.18.0 mock==2.0.0 ndg-httpsclient==0.5.1 -packaging==18.0 # via sphinx +packaging==19.0 # via sphinx paramiko==2.4.2 pbr==5.1.1 pem==18.2.0 -psycopg2==2.7.6.1 -pyasn1-modules==0.2.3 +psycopg2==2.7.7 +pyasn1-modules==0.2.4 pyasn1==0.4.5 pycparser==2.19 pygments==2.3.1 # via sphinx pyjwt==1.7.1 pynacl==1.3.0 -pyopenssl==18.0.0 +pyopenssl==19.0.0 pyparsing==2.3.1 # via packaging pyrfc3339==1.1 python-dateutil==2.7.5 @@ -77,7 +77,7 @@ pytz==2018.9 pyyaml==3.13 raven[flask]==6.10.0 redis==2.10.6 -requests-toolbelt==0.8.0 +requests-toolbelt==0.9.0 requests[security]==2.21.0 retrying==1.3.3 s3transfer==0.1.13 @@ -88,8 +88,8 @@ sphinx==1.8.3 sphinxcontrib-httpdomain==1.7.0 sphinxcontrib-websupport==1.1.0 # via sphinx sqlalchemy-utils==0.33.11 -sqlalchemy==1.2.16 -tabulate==0.8.2 +sqlalchemy==1.2.17 +tabulate==0.8.3 urllib3==1.24.1 vine==1.2.0 werkzeug==0.14.1 diff --git a/requirements-tests.txt b/requirements-tests.txt index 2d54dce6..c326e951 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -8,30 +8,30 @@ asn1crypto==0.24.0 # via cryptography atomicwrites==1.2.1 # via pytest attrs==18.2.0 # via pytest aws-xray-sdk==0.95 # via moto -boto3==1.9.80 # via moto +boto3==1.9.86 # via moto boto==2.49.0 # via moto -botocore==1.12.80 # via boto3, moto, s3transfer +botocore==1.12.86 # via boto3, moto, s3transfer certifi==2018.11.29 # via requests cffi==1.11.5 # via cryptography chardet==3.0.4 # via requests click==7.0 # via flask coverage==4.5.2 -cryptography==2.4.2 # via moto +cryptography==2.5 # via moto docker-pycreds==0.4.0 # via docker docker==3.7.0 # via moto docutils==0.14 # via botocore ecdsa==0.13 # via python-jose factory-boy==2.11.1 -faker==1.0.1 +faker==1.0.2 flask==1.0.2 # via pytest-flask freezegun==0.3.11 future==0.17.1 # via python-jose -idna==2.8 # via cryptography, requests +idna==2.8 # via requests itsdangerous==1.1.0 # via flask jinja2==2.10 # via flask, moto jmespath==0.9.3 # via boto3, botocore jsondiff==1.1.1 # via moto -jsonpickle==1.0 # via aws-xray-sdk +jsonpickle==1.1 # via aws-xray-sdk markupsafe==1.1.0 # via jinja2 mock==2.0.0 # via moto more-itertools==5.0.0 # via pytest @@ -42,8 +42,8 @@ pluggy==0.8.1 # via pytest py==1.7.0 # via pytest pyaml==18.11.0 # via moto pycparser==2.19 # via cffi -pycryptodome==3.7.2 # via python-jose -pyflakes==2.0.0 +pycryptodome==3.7.3 # via python-jose +pyflakes==2.1.0 pytest-flask==0.14.0 pytest-mock==1.10.0 pytest==4.1.1 @@ -60,5 +60,5 @@ text-unidecode==1.2 # via faker urllib3==1.24.1 # via botocore, requests websocket-client==0.54.0 # via docker werkzeug==0.14.1 # via flask, moto, pytest-flask -wrapt==1.11.0 # via aws-xray-sdk +wrapt==1.11.1 # via aws-xray-sdk xmltodict==0.11.0 # via moto diff --git a/requirements.txt b/requirements.txt index 79268c8a..c595e509 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --no-index --output-file requirements.txt requirements.in # -acme==0.30.0 +acme==0.30.2 alembic-autogenerate-enums==0.0.2 -alembic==1.0.6 # via flask-migrate +alembic==1.0.7 # via flask-migrate amqp==2.4.0 # via kombu aniso8601==4.1.0 # via flask-restful arrow==0.13.0 @@ -15,15 +15,15 @@ asyncpool==1.0 bcrypt==3.1.6 # via flask-bcrypt, paramiko billiard==3.5.0.5 # via celery blinker==1.4 # via flask-mail, flask-principal, raven -boto3==1.9.80 -botocore==1.12.80 +boto3==1.9.86 +botocore==1.12.86 celery[redis]==4.2.1 certifi==2018.11.29 cffi==1.11.5 # via bcrypt, cryptography, pynacl chardet==3.0.4 # via requests click==7.0 # via flask cloudflare==2.1.0 -cryptography==2.4.2 +cryptography==2.5 dnspython3==1.15.0 dnspython==1.15.0 # via dnspython3 docutils==0.14 # via botocore @@ -39,7 +39,7 @@ flask-sqlalchemy==2.3.2 flask==1.0.2 future==0.17.1 gunicorn==19.9.0 -idna==2.8 # via cryptography, requests +idna==2.8 # via requests inflection==0.3.1 itsdangerous==1.1.0 # via flask jinja2==2.10 @@ -57,13 +57,13 @@ ndg-httpsclient==0.5.1 paramiko==2.4.2 pbr==5.1.1 # via mock pem==18.2.0 -psycopg2==2.7.6.1 -pyasn1-modules==0.2.3 # via python-ldap +psycopg2==2.7.7 +pyasn1-modules==0.2.4 # via python-ldap pyasn1==0.4.5 # via ndg-httpsclient, paramiko, pyasn1-modules, python-ldap pycparser==2.19 # via cffi pyjwt==1.7.1 pynacl==1.3.0 # via paramiko -pyopenssl==18.0.0 +pyopenssl==19.0.0 pyrfc3339==1.1 # via acme python-dateutil==2.7.5 # via alembic, arrow, botocore python-editor==1.0.3 # via alembic @@ -72,14 +72,14 @@ pytz==2018.9 # via acme, celery, flask-restful, pyrfc3339 pyyaml==3.13 # via cloudflare raven[flask]==6.10.0 redis==2.10.6 -requests-toolbelt==0.8.0 # via acme +requests-toolbelt==0.9.0 # via acme requests[security]==2.21.0 retrying==1.3.3 s3transfer==0.1.13 # via boto3 six==1.12.0 sqlalchemy-utils==0.33.11 -sqlalchemy==1.2.16 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils -tabulate==0.8.2 +sqlalchemy==1.2.17 # via alembic, flask-sqlalchemy, marshmallow-sqlalchemy, sqlalchemy-utils +tabulate==0.8.3 urllib3==1.24.1 # via botocore, requests vine==1.2.0 # via amqp werkzeug==0.14.1 # via flask