diff --git a/.travis.yml b/.travis.yml
index f1abf3f3..f38555a0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,6 +20,8 @@ cache:
env:
global:
- PIP_DOWNLOAD_CACHE=".pip_download_cache"
+ # The following line is a temporary workaround for this issue: https://github.com/pypa/setuptools/issues/2230
+ - SETUPTOOLS_USE_DISTUTILS=stdlib
# do not load /etc/boto.cfg with Python 3 incompatible plugin
# https://github.com/travis-ci/travis-ci/issues/5246#issuecomment-166460882
- BOTO_CONFIG=/doesnotexist
diff --git a/Makefile b/Makefile
index 069eb29b..3312a41d 100644
--- a/Makefile
+++ b/Makefile
@@ -50,8 +50,10 @@ reset-db:
setup-git:
@echo "--> Installing git hooks"
- git config branch.autosetuprebase always
- cd .git/hooks && ln -sf ../../hooks/* ./
+ if [ -d .git/hooks ]; then \
+ git config branch.autosetuprebase always; \
+ cd .git/hooks && ln -sf ../../hooks/* ./; \
+ fi
@echo ""
clean:
diff --git a/lemur/authorities/schemas.py b/lemur/authorities/schemas.py
index 0700c15b..7f9f57d4 100644
--- a/lemur/authorities/schemas.py
+++ b/lemur/authorities/schemas.py
@@ -23,6 +23,7 @@ from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.common import validators, missing
from lemur.common.fields import ArrowDateTime
+from lemur.constants import CERTIFICATE_KEY_TYPES
class AuthorityInputSchema(LemurInputSchema):
@@ -56,11 +57,12 @@ class AuthorityInputSchema(LemurInputSchema):
type = fields.String(validate=validate.OneOf(["root", "subca"]), missing="root")
parent = fields.Nested(AssociatedAuthoritySchema)
signing_algorithm = fields.String(
- validate=validate.OneOf(["sha256WithRSA", "sha1WithRSA"]),
+ validate=validate.OneOf(["sha256WithRSA", "sha1WithRSA",
+ "sha256WithECDSA", "SHA384withECDSA", "SHA512withECDSA"]),
missing="sha256WithRSA",
)
key_type = fields.String(
- validate=validate.OneOf(["RSA2048", "RSA4096"]), missing="RSA2048"
+ validate=validate.OneOf(CERTIFICATE_KEY_TYPES), missing="RSA2048"
)
key_name = fields.String()
sensitivity = fields.String(
diff --git a/lemur/common/validators.py b/lemur/common/validators.py
index 74095255..e1dfe3c1 100644
--- a/lemur/common/validators.py
+++ b/lemur/common/validators.py
@@ -152,18 +152,6 @@ def dates(data):
data["authority"].authority_certificate.not_after
)
)
- # Allow no more than PUBLIC_CA_MAX_VALIDITY_DAYS (Default: 397) days of validity
- # for certs issued by public CA
- # The list of public issuers can be managed through a config named PUBLIC_CA
- public_CA = current_app.config.get("PUBLIC_CA_AUTHORITY_NAMES", [])
- if data["authority"].name.lower() in [ca.lower() for ca in public_CA]:
- max_validity_days = current_app.config.get("PUBLIC_CA_MAX_VALIDITY_DAYS", 397)
- if (
- (data.get("validity_end").date() - data.get("validity_start").date()).days
- > max_validity_days
- ):
- raise ValidationError("Certificate cannot be valid for more than " +
- str(max_validity_days) + " days")
return data
diff --git a/lemur/static/app/angular/authorities/authority/options.tpl.html b/lemur/static/app/angular/authorities/authority/options.tpl.html
index dbc4f40a..bf1ad70c 100644
--- a/lemur/static/app/angular/authorities/authority/options.tpl.html
+++ b/lemur/static/app/angular/authorities/authority/options.tpl.html
@@ -4,7 +4,7 @@
Signing Algorithm
-
+
diff --git a/lemur/tests/test_authorities.py b/lemur/tests/test_authorities.py
index 9649e949..fade39e8 100644
--- a/lemur/tests/test_authorities.py
+++ b/lemur/tests/test_authorities.py
@@ -34,6 +34,29 @@ def test_authority_input_schema(client, role, issuer_plugin, logged_in_user):
assert not errors
+def test_authority_input_schema_ecc(client, role, issuer_plugin, logged_in_user):
+ from lemur.authorities.schemas import AuthorityInputSchema
+
+ input_data = {
+ "name": "Example Authority",
+ "owner": "jim@example.com",
+ "description": "An example authority.",
+ "commonName": "An Example Authority",
+ "plugin": {
+ "slug": "test-issuer",
+ "plugin_options": [{"name": "test", "value": "blah"}],
+ },
+ "type": "root",
+ "signingAlgorithm": "sha256WithECDSA",
+ "keyType": "ECCPRIME256V1",
+ "sensitivity": "medium",
+ }
+
+ data, errors = AuthorityInputSchema().load(input_data)
+
+ assert not errors
+
+
def test_user_authority(session, client, authority, role, user, issuer_plugin):
u = user["user"]
u.roles.append(role)
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 2299848e..166722e8 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -11,7 +11,7 @@ cffi==1.14.0 # via cryptography
cfgv==3.1.0 # via pre-commit
chardet==3.0.4 # via requests
colorama==0.4.3 # via twine
-cryptography==3.0 # via secretstorage
+cryptography==3.1 # via secretstorage
distlib==0.3.0 # via virtualenv
docutils==0.16 # via readme-renderer
filelock==3.0.12 # via virtualenv
@@ -22,9 +22,9 @@ invoke==1.4.1 # via -r requirements-dev.in
jeepney==0.4.3 # via keyring, secretstorage
keyring==21.2.0 # via twine
mccabe==0.6.1 # via flake8
-nodeenv==1.4.0 # via -r requirements-dev.in, pre-commit
+nodeenv==1.5.0 # via -r requirements-dev.in, pre-commit
pkginfo==1.5.0.1 # via twine
-pre-commit==2.6.0 # via -r requirements-dev.in
+pre-commit==2.7.1 # via -r requirements-dev.in
pycodestyle==2.3.1 # via flake8
pycparser==2.20 # via cffi
pyflakes==1.6.0 # via flake8
diff --git a/requirements-docs.txt b/requirements-docs.txt
index 7e187213..37d50804 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -4,35 +4,35 @@
#
# pip-compile --no-index --output-file=requirements-docs.txt requirements-docs.in
#
-acme==1.6.0 # via -r requirements.txt
+acme==1.7.0 # via -r requirements.txt
alabaster==0.7.12 # via sphinx
alembic-autogenerate-enums==0.0.2 # via -r requirements.txt
alembic==1.4.2 # via -r requirements.txt, flask-migrate
amqp==2.5.2 # via -r requirements.txt, kombu
aniso8601==8.0.0 # via -r requirements.txt, flask-restful
-arrow==0.15.8 # via -r requirements.txt
+arrow==0.16.0 # via -r requirements.txt
asyncpool==1.0 # via -r requirements.txt
babel==2.8.0 # via sphinx
bcrypt==3.1.7 # via -r requirements.txt, flask-bcrypt, paramiko
beautifulsoup4==4.9.1 # via -r requirements.txt, cloudflare
billiard==3.6.3.0 # via -r requirements.txt, celery
blinker==1.4 # via -r requirements.txt, flask-mail, flask-principal, raven
-boto3==1.14.33 # via -r requirements.txt
-botocore==1.17.33 # via -r requirements.txt, boto3, s3transfer
+boto3==1.14.56 # via -r requirements.txt
+botocore==1.17.56 # via -r requirements.txt, boto3, s3transfer
celery[redis]==4.4.2 # via -r requirements.txt
certifi==2020.6.20 # via -r requirements.txt, requests
certsrv==2.1.1 # via -r requirements.txt
cffi==1.14.0 # via -r requirements.txt, bcrypt, cryptography, pynacl
chardet==3.0.4 # via -r requirements.txt, requests
click==7.1.1 # via -r requirements.txt, flask
-cloudflare==2.8.9 # via -r requirements.txt
-cryptography==3.0 # via -r requirements.txt, acme, josepy, paramiko, pyopenssl, requests
+cloudflare==2.8.13 # via -r requirements.txt
+cryptography==3.1 # via -r requirements.txt, acme, josepy, paramiko, pyopenssl, requests
dnspython3==1.15.0 # via -r requirements.txt
dnspython==1.15.0 # via -r requirements.txt, dnspython3
docutils==0.15.2 # via -r requirements.txt, botocore, sphinx
dyn==1.8.1 # via -r requirements.txt
flask-bcrypt==0.7.1 # via -r requirements.txt
-flask-cors==3.0.8 # via -r requirements.txt
+flask-cors==3.0.9 # via -r requirements.txt
flask-mail==0.9.1 # via -r requirements.txt
flask-migrate==2.5.3 # via -r requirements.txt
flask-principal==0.4.0 # via -r requirements.txt
@@ -46,7 +46,7 @@ gunicorn==20.0.4 # via -r requirements.txt
hvac==0.10.5 # via -r requirements.txt
idna==2.9 # via -r requirements.txt, requests
imagesize==1.2.0 # via sphinx
-inflection==0.5.0 # via -r requirements.txt
+inflection==0.5.1 # via -r requirements.txt
itsdangerous==1.1.0 # via -r requirements.txt, flask
javaobj-py3==0.4.0.1 # via -r requirements.txt, pyjks
jinja2==2.11.2 # via -r requirements.txt, flask, sphinx
@@ -62,9 +62,9 @@ marshmallow-sqlalchemy==0.23.1 # via -r requirements.txt
marshmallow==2.20.4 # via -r requirements.txt, marshmallow-sqlalchemy
ndg-httpsclient==0.5.1 # via -r requirements.txt
packaging==20.3 # via sphinx
-paramiko==2.7.1 # via -r requirements.txt
+paramiko==2.7.2 # via -r requirements.txt
pem==20.1.0 # via -r requirements.txt
-psycopg2==2.8.5 # via -r requirements.txt
+psycopg2==2.8.6 # via -r requirements.txt
pyasn1-modules==0.2.8 # via -r requirements.txt, pyjks, python-ldap
pyasn1==0.4.8 # via -r requirements.txt, ndg-httpsclient, pyasn1-modules, pyjks, python-ldap
pycparser==2.20 # via -r requirements.txt, cffi
@@ -92,7 +92,7 @@ six==1.15.0 # via -r requirements.txt, acme, bcrypt, cryptography,
snowballstemmer==2.0.0 # via sphinx
soupsieve==2.0.1 # via -r requirements.txt, beautifulsoup4
sphinx-rtd-theme==0.5.0 # via -r requirements-docs.in
-sphinx==3.2.0 # via -r requirements-docs.in, sphinx-rtd-theme, sphinxcontrib-httpdomain
+sphinx==3.2.1 # via -r requirements-docs.in, sphinx-rtd-theme, sphinxcontrib-httpdomain
sphinxcontrib-applehelp==1.0.2 # via sphinx
sphinxcontrib-devhelp==1.0.2 # via sphinx
sphinxcontrib-htmlhelp==1.0.3 # via sphinx
diff --git a/requirements-tests.txt b/requirements-tests.txt
index 7fd13f76..e9106767 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -5,30 +5,30 @@
# pip-compile --no-index --output-file=requirements-tests.txt requirements-tests.in
#
appdirs==1.4.3 # via black
-attrs==19.3.0 # via black, jsonschema, pytest
+attrs==19.3.0 # via jsonschema, pytest
aws-sam-translator==1.22.0 # via cfn-lint
aws-xray-sdk==2.5.0 # via moto
bandit==1.6.2 # via -r requirements-tests.in
-black==19.10b0 # via -r requirements-tests.in
-boto3==1.14.33 # via aws-sam-translator, moto
+black==20.8b1 # via -r requirements-tests.in
+boto3==1.14.56 # via aws-sam-translator, moto
boto==2.49.0 # via moto
-botocore==1.17.33 # via aws-xray-sdk, boto3, moto, s3transfer
+botocore==1.17.56 # via aws-xray-sdk, boto3, moto, s3transfer
certifi==2020.6.20 # via requests
cffi==1.14.0 # via cryptography
cfn-lint==0.29.5 # via moto
chardet==3.0.4 # via requests
-click==7.1.1 # via black, flask
+click==7.1.2 # via black, flask
coverage==5.2.1 # via -r requirements-tests.in
-cryptography==3.0 # via moto, sshpubkeys
+cryptography==3.1 # via moto, sshpubkeys
decorator==4.4.2 # via networkx
docker==4.2.0 # via moto
docutils==0.15.2 # via botocore
ecdsa==0.15 # via python-jose, sshpubkeys
-factory-boy==2.12.0 # via -r requirements-tests.in
-faker==4.1.1 # via -r requirements-tests.in, factory-boy
-fakeredis==1.4.1 # via -r requirements-tests.in
+factory-boy==3.0.1 # via -r requirements-tests.in
+faker==4.1.2 # via -r requirements-tests.in, factory-boy
+fakeredis==1.4.3 # via -r requirements-tests.in
flask==1.1.2 # via pytest-flask
-freezegun==0.3.15 # via -r requirements-tests.in
+freezegun==1.0.0 # via -r requirements-tests.in
future==0.18.2 # via aws-xray-sdk
gitdb==4.0.4 # via gitpython
gitpython==3.1.1 # via bandit
@@ -47,6 +47,7 @@ markupsafe==1.1.1 # via jinja2
mock==4.0.2 # via moto
more-itertools==8.2.0 # via pytest
moto==1.3.14 # via -r requirements-tests.in
+mypy-extensions==0.4.3 # via black
networkx==2.4 # via cfn-lint
nose==1.3.7 # via -r requirements-tests.in
packaging==20.3 # via pytest
@@ -60,7 +61,7 @@ pyflakes==2.2.0 # via -r requirements-tests.in
pyparsing==2.4.7 # via packaging
pyrsistent==0.16.0 # via jsonschema
pytest-flask==1.0.0 # via -r requirements-tests.in
-pytest-mock==3.2.0 # via -r requirements-tests.in
+pytest-mock==3.3.1 # via -r requirements-tests.in
pytest==6.0.1 # via -r requirements-tests.in, pytest-flask, pytest-mock
python-dateutil==2.8.1 # via botocore, faker, freezegun, moto
python-jose==3.1.0 # via moto
@@ -73,14 +74,15 @@ requests==2.24.0 # via docker, moto, requests-mock, responses
responses==0.10.12 # via moto
rsa==4.0 # via python-jose
s3transfer==0.3.3 # via boto3
-six==1.15.0 # via aws-sam-translator, bandit, cfn-lint, cryptography, docker, ecdsa, fakeredis, freezegun, jsonschema, moto, packaging, pyrsistent, python-dateutil, python-jose, requests-mock, responses, stevedore, websocket-client
+six==1.15.0 # via aws-sam-translator, bandit, cfn-lint, cryptography, docker, ecdsa, fakeredis, jsonschema, moto, packaging, pyrsistent, python-dateutil, python-jose, requests-mock, responses, stevedore, websocket-client
smmap==3.0.2 # via gitdb
sortedcontainers==2.1.0 # via fakeredis
sshpubkeys==3.1.0 # via moto
stevedore==1.32.0 # via bandit
text-unidecode==1.3 # via faker
-toml==0.10.0 # via black, pytest
+toml==0.10.1 # via black, pytest
typed-ast==1.4.1 # via black
+typing-extensions==3.7.4.3 # via black
urllib3==1.25.8 # via botocore, requests
websocket-client==0.57.0 # via docker
werkzeug==1.0.1 # via flask, moto, pytest-flask
diff --git a/requirements.txt b/requirements.txt
index d9e86d97..64e41b3c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,33 +4,33 @@
#
# pip-compile --no-index --output-file=requirements.txt requirements.in
#
-acme==1.6.0 # via -r requirements.in
+acme==1.7.0 # via -r requirements.in
alembic-autogenerate-enums==0.0.2 # via -r requirements.in
alembic==1.4.2 # via flask-migrate
amqp==2.5.2 # via kombu
aniso8601==8.0.0 # via flask-restful
-arrow==0.15.8 # via -r requirements.in
+arrow==0.16.0 # via -r requirements.in
asyncpool==1.0 # via -r requirements.in
bcrypt==3.1.7 # via flask-bcrypt, paramiko
beautifulsoup4==4.9.1 # via cloudflare
billiard==3.6.3.0 # via celery
blinker==1.4 # via flask-mail, flask-principal, raven
-boto3==1.14.33 # via -r requirements.in
-botocore==1.17.33 # via -r requirements.in, boto3, s3transfer
+boto3==1.14.56 # via -r requirements.in
+botocore==1.17.56 # via -r requirements.in, boto3, s3transfer
celery[redis]==4.4.2 # via -r requirements.in
certifi==2020.6.20 # via -r requirements.in, requests
certsrv==2.1.1 # via -r requirements.in
cffi==1.14.0 # via bcrypt, cryptography, pynacl
chardet==3.0.4 # via requests
click==7.1.1 # via flask
-cloudflare==2.8.9 # via -r requirements.in
-cryptography==3.0 # via -r requirements.in, acme, josepy, paramiko, pyopenssl, requests
+cloudflare==2.8.13 # via -r requirements.in
+cryptography==3.1 # via -r requirements.in, acme, josepy, paramiko, pyopenssl, requests
dnspython3==1.15.0 # via -r requirements.in
dnspython==1.15.0 # via dnspython3
docutils==0.15.2 # via botocore
dyn==1.8.1 # via -r requirements.in
flask-bcrypt==0.7.1 # via -r requirements.in
-flask-cors==3.0.8 # via -r requirements.in
+flask-cors==3.0.9 # via -r requirements.in
flask-mail==0.9.1 # via -r requirements.in
flask-migrate==2.5.3 # via -r requirements.in
flask-principal==0.4.0 # via -r requirements.in
@@ -43,7 +43,7 @@ future==0.18.2 # via -r requirements.in
gunicorn==20.0.4 # via -r requirements.in
hvac==0.10.5 # via -r requirements.in
idna==2.9 # via requests
-inflection==0.5.0 # via -r requirements.in
+inflection==0.5.1 # via -r requirements.in
itsdangerous==1.1.0 # via flask
javaobj-py3==0.4.0.1 # via pyjks
jinja2==2.11.2 # via -r requirements.in, flask
@@ -58,9 +58,9 @@ markupsafe==1.1.1 # via jinja2, mako
marshmallow-sqlalchemy==0.23.1 # via -r requirements.in
marshmallow==2.20.4 # via -r requirements.in, marshmallow-sqlalchemy
ndg-httpsclient==0.5.1 # via -r requirements.in
-paramiko==2.7.1 # via -r requirements.in
+paramiko==2.7.2 # via -r requirements.in
pem==20.1.0 # via -r requirements.in
-psycopg2==2.8.5 # via -r requirements.in
+psycopg2==2.8.6 # via -r requirements.in
pyasn1-modules==0.2.8 # via pyjks, python-ldap
pyasn1==0.4.8 # via ndg-httpsclient, pyasn1-modules, pyjks, python-ldap
pycparser==2.20 # via cffi
diff --git a/setup.py b/setup.py
index 4ce03d70..a612cd18 100644
--- a/setup.py
+++ b/setup.py
@@ -9,30 +9,18 @@ Is a TLS management and orchestration tool.
"""
from __future__ import absolute_import
-import sys
-import json
-import os.path
import datetime
+import json
+import logging
+import os.path
+import sys
+from subprocess import check_output
-from distutils import log
-from distutils.core import Command
+from setuptools import Command
+from setuptools import setup, find_packages
from setuptools.command.develop import develop
from setuptools.command.install import install
from setuptools.command.sdist import sdist
-from setuptools import setup, find_packages
-from subprocess import check_output
-
-import pip
-if tuple(map(int, pip.__version__.split('.'))) >= (19, 3, 0):
- from pip._internal.network.session import PipSession
- from pip._internal.req import parse_requirements
-
-elif tuple(map(int, pip.__version__.split('.'))) >= (10, 0, 0):
- from pip._internal.download import PipSession
- from pip._internal.req import parse_requirements
-else:
- from pip.download import PipSession
- from pip.req import parse_requirements
ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__)))
@@ -44,21 +32,18 @@ about = {}
with open(os.path.join(ROOT, 'lemur', '__about__.py')) as f:
exec(f.read(), about) # nosec: about file is benign
-install_requires_g = parse_requirements("requirements.txt", session=PipSession())
-tests_require_g = parse_requirements("requirements-tests.txt", session=PipSession())
-docs_require_g = parse_requirements("requirements-docs.txt", session=PipSession())
-dev_requires_g = parse_requirements("requirements-dev.txt", session=PipSession())
+# Parse requirements files
+with open('requirements.txt') as f:
+ install_requirements = f.read().splitlines()
-if tuple(map(int, pip.__version__.split('.'))) >= (20, 1):
- install_requires = [str(ir.requirement) for ir in install_requires_g]
- tests_require = [str(ir.requirement) for ir in tests_require_g]
- docs_require = [str(ir.requirement) for ir in docs_require_g]
- dev_requires = [str(ir.requirement) for ir in dev_requires_g]
-else:
- install_requires = [str(ir.req) for ir in install_requires_g]
- tests_require = [str(ir.req) for ir in tests_require_g]
- docs_require = [str(ir.req) for ir in docs_require_g]
- dev_requires = [str(ir.req) for ir in dev_requires_g]
+with open('requirements-tests.txt') as f:
+ tests_requirements = f.read().splitlines()
+
+with open('requirements-docs.txt') as f:
+ docs_requirements = f.read().splitlines()
+
+with open('requirements-dev.txt') as f:
+ dev_requirements = f.read().splitlines()
class SmartInstall(install):
@@ -67,6 +52,7 @@ class SmartInstall(install):
If the package indicator is missing, this will also force a run of
`build_static` which is required for JavaScript assets and other things.
"""
+
def _needs_static(self):
return not os.path.exists(os.path.join(ROOT, 'lemur/static/dist'))
@@ -105,16 +91,16 @@ class BuildStatic(Command):
pass
def run(self):
- log.info("running [npm install --quiet] in {0}".format(ROOT))
+ logging.info("running [npm install --quiet] in {0}".format(ROOT))
try:
check_output(['npm', 'install', '--quiet'], cwd=ROOT)
- log.info("running [gulp build]")
+ logging.info("running [gulp build]")
check_output([os.path.join(ROOT, 'node_modules', '.bin', 'gulp'), 'build'], cwd=ROOT)
- log.info("running [gulp package]")
+ logging.info("running [gulp package]")
check_output([os.path.join(ROOT, 'node_modules', '.bin', 'gulp'), 'package'], cwd=ROOT)
except Exception as e:
- log.warn("Unable to build static content")
+ logging.warn("Unable to build static content")
setup(
@@ -128,11 +114,11 @@ setup(
packages=find_packages(),
include_package_data=True,
zip_safe=False,
- install_requires=install_requires,
+ install_requires=install_requirements,
extras_require={
- 'tests': tests_require,
- 'docs': docs_require,
- 'dev': dev_requires,
+ 'tests': tests_requirements,
+ 'docs': docs_requirements,
+ 'dev': dev_requirements,
},
cmdclass={
'build_static': BuildStatic,