commit
3ebbbd21e7
19
.travis.yml
19
.travis.yml
|
@ -1,23 +1,36 @@
|
|||
sudo: false
|
||||
|
||||
language: python
|
||||
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- python: "2.7"
|
||||
env: TOXENV=py27
|
||||
- python: "3.3"
|
||||
env: TOXENV=py33
|
||||
- python: "3.4"
|
||||
env: TOXENV=py34
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- .pip_download_cache
|
||||
- "$HOME/virtualenv/python2.7.9"
|
||||
|
||||
env:
|
||||
global:
|
||||
- PIP_DOWNLOAD_CACHE=".pip_download_cache"
|
||||
|
||||
install:
|
||||
- make dev-postgres
|
||||
|
||||
before_script:
|
||||
- psql -c "create database lemur;" -U postgres
|
||||
- psql -c "create user lemur with password 'lemur;'" -U postgres
|
||||
- npm install -g bower
|
||||
|
||||
script:
|
||||
- make test
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
.. module: permissions
|
||||
.. module: lemur.auth.permissions
|
||||
:platform: Unix
|
||||
:synopsis: This module defines all the permission used within Lemur
|
||||
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
|
||||
|
@ -24,15 +24,15 @@ CertificateOwnerNeed = partial(CertificateOwner, 'certificateView')
|
|||
|
||||
class ViewKeyPermission(Permission):
|
||||
def __init__(self, role_id, certificate_id):
|
||||
c_need = CertificateCreatorNeed(unicode(certificate_id))
|
||||
o_need = CertificateOwnerNeed(unicode(role_id))
|
||||
c_need = CertificateCreatorNeed(str(certificate_id))
|
||||
o_need = CertificateOwnerNeed(str(role_id))
|
||||
super(ViewKeyPermission, self).__init__(o_need, c_need, RoleNeed('admin'))
|
||||
|
||||
|
||||
class UpdateCertificatePermission(Permission):
|
||||
def __init__(self, role_id, certificate_id):
|
||||
c_need = CertificateCreatorNeed(unicode(certificate_id))
|
||||
o_need = CertificateOwnerNeed(unicode(role_id))
|
||||
c_need = CertificateCreatorNeed(str(certificate_id))
|
||||
o_need = CertificateOwnerNeed(str(role_id))
|
||||
super(UpdateCertificatePermission, self).__init__(o_need, c_need, RoleNeed('admin'))
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ ViewRoleCredentialsNeed = partial(RoleUser, 'roleView')
|
|||
|
||||
class ViewRoleCredentialsPermission(Permission):
|
||||
def __init__(self, role_id):
|
||||
need = ViewRoleCredentialsNeed(unicode(role_id))
|
||||
need = ViewRoleCredentialsNeed(str(role_id))
|
||||
super(ViewRoleCredentialsPermission, self).__init__(need, RoleNeed('admin'))
|
||||
|
||||
|
||||
|
@ -55,8 +55,8 @@ AuthorityOwnerNeed = partial(AuthorityOwner, 'role')
|
|||
|
||||
class AuthorityPermission(Permission):
|
||||
def __init__(self, authority_id, roles):
|
||||
needs = [RoleNeed('admin'), AuthorityCreatorNeed(unicode(authority_id))]
|
||||
needs = [RoleNeed('admin'), AuthorityCreatorNeed(str(authority_id))]
|
||||
for r in roles:
|
||||
needs.append(AuthorityOwnerNeed(unicode(r)))
|
||||
needs.append(AuthorityOwnerNeed(str(r)))
|
||||
|
||||
super(AuthorityPermission, self).__init__(*needs)
|
||||
|
|
|
@ -12,6 +12,8 @@ import jwt
|
|||
import json
|
||||
import base64
|
||||
import binascii
|
||||
from builtins import str
|
||||
|
||||
from functools import wraps
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
@ -32,7 +34,7 @@ from lemur.auth.permissions import CertificateOwnerNeed, CertificateCreatorNeed,
|
|||
|
||||
|
||||
def base64url_decode(data):
|
||||
if isinstance(data, unicode):
|
||||
if isinstance(data, str):
|
||||
data = str(data)
|
||||
|
||||
rem = len(data) % 4
|
||||
|
@ -139,7 +141,9 @@ def fetch_token_header(token):
|
|||
|
||||
try:
|
||||
return json.loads(base64url_decode(header_segment))
|
||||
except TypeError, binascii.Error:
|
||||
except TypeError:
|
||||
raise jwt.DecodeError('Invalid header padding')
|
||||
except binascii.Error:
|
||||
raise jwt.DecodeError('Invalid header padding')
|
||||
|
||||
|
||||
|
@ -161,19 +165,19 @@ def on_identity_loaded(sender, identity):
|
|||
# identity with the roles that the user provides
|
||||
if hasattr(user, 'roles'):
|
||||
for role in user.roles:
|
||||
identity.provides.add(CertificateOwnerNeed(unicode(role.id)))
|
||||
identity.provides.add(ViewRoleCredentialsNeed(unicode(role.id)))
|
||||
identity.provides.add(CertificateOwnerNeed(role.id))
|
||||
identity.provides.add(ViewRoleCredentialsNeed(role.id))
|
||||
identity.provides.add(RoleNeed(role.name))
|
||||
|
||||
# apply ownership for authorities
|
||||
if hasattr(user, 'authorities'):
|
||||
for authority in user.authorities:
|
||||
identity.provides.add(AuthorityCreatorNeed(unicode(authority.id)))
|
||||
identity.provides.add(AuthorityCreatorNeed(authority.id))
|
||||
|
||||
# apply ownership of certificates
|
||||
if hasattr(user, 'certificates'):
|
||||
for certificate in user.certificates:
|
||||
identity.provides.add(CertificateCreatorNeed(unicode(certificate.id)))
|
||||
identity.provides.add(CertificateCreatorNeed(certificate.id))
|
||||
|
||||
g.user = user
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"""
|
||||
import os
|
||||
import datetime
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
|
@ -56,7 +57,10 @@ def create_name(issuer, not_before, not_after, subject, san):
|
|||
disallowed_chars = disallowed_chars.replace("-", "")
|
||||
disallowed_chars = disallowed_chars.replace(".", "")
|
||||
temp = temp.replace('*', "WILDCARD")
|
||||
temp = temp.translate(None, disallowed_chars)
|
||||
|
||||
for c in disallowed_chars:
|
||||
temp = temp.replace(c, "")
|
||||
|
||||
# white space is silly too
|
||||
return temp.replace(" ", "-")
|
||||
|
||||
|
@ -151,7 +155,9 @@ def cert_get_issuer(cert):
|
|||
delchars = ''.join(c for c in map(chr, range(256)) if not c.isalnum())
|
||||
try:
|
||||
issuer = str(cert.issuer.get_attributes_for_oid(x509.OID_ORGANIZATION_NAME)[0].value)
|
||||
return issuer.translate(None, delchars)
|
||||
for c in delchars:
|
||||
issuer = issuer.replace(c, "")
|
||||
return issuer
|
||||
except Exception as e:
|
||||
current_app.logger.error("Unable to get issuer! {0}".format(e))
|
||||
|
||||
|
|
|
@ -304,15 +304,15 @@ def create_csr(csr_config):
|
|||
backend=default_backend()
|
||||
)
|
||||
|
||||
# TODO When we figure out a better way to validate these options they should be parsed as unicode
|
||||
# TODO When we figure out a better way to validate these options they should be parsed as str
|
||||
builder = x509.CertificateSigningRequestBuilder()
|
||||
builder = builder.subject_name(x509.Name([
|
||||
x509.NameAttribute(x509.OID_COMMON_NAME, unicode(csr_config['commonName'])),
|
||||
x509.NameAttribute(x509.OID_ORGANIZATION_NAME, unicode(csr_config['organization'])),
|
||||
x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, unicode(csr_config['organizationalUnit'])),
|
||||
x509.NameAttribute(x509.OID_COUNTRY_NAME, unicode(csr_config['country'])),
|
||||
x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, unicode(csr_config['state'])),
|
||||
x509.NameAttribute(x509.OID_LOCALITY_NAME, unicode(csr_config['location'])),
|
||||
x509.NameAttribute(x509.OID_COMMON_NAME, csr_config['commonName']),
|
||||
x509.NameAttribute(x509.OID_ORGANIZATION_NAME, csr_config['organization']),
|
||||
x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, csr_config['organizationalUnit']),
|
||||
x509.NameAttribute(x509.OID_COUNTRY_NAME, csr_config['country']),
|
||||
x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, csr_config['state']),
|
||||
x509.NameAttribute(x509.OID_LOCALITY_NAME, csr_config['location']),
|
||||
]))
|
||||
|
||||
builder = builder.add_extension(
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
:license: Apache, see LICENSE for more details.
|
||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||
"""
|
||||
from builtins import str
|
||||
|
||||
from flask import Blueprint, make_response, jsonify
|
||||
from flask.ext.restful import reqparse, Api, fields
|
||||
|
||||
|
@ -75,7 +77,7 @@ def pem_str(value, name):
|
|||
:return: :raise ValueError:
|
||||
"""
|
||||
try:
|
||||
x509.load_pem_x509_certificate(str(value), default_backend())
|
||||
x509.load_pem_x509_certificate(bytes(value), default_backend())
|
||||
except Exception:
|
||||
raise ValueError("The parameter '{0}' needs to be a valid PEM string".format(name))
|
||||
return value
|
||||
|
@ -90,7 +92,7 @@ def private_key_str(value, name):
|
|||
:return: :raise ValueError:
|
||||
"""
|
||||
try:
|
||||
serialization.load_pem_private_key(str(value), None, backend=default_backend())
|
||||
serialization.load_pem_private_key(bytes(value), None, backend=default_backend())
|
||||
except Exception:
|
||||
raise ValueError("The parameter '{0}' needs to be a valid RSA private key".format(name))
|
||||
return value
|
||||
|
|
|
@ -65,7 +65,7 @@ class marshal_items(object):
|
|||
else:
|
||||
return {'message': 'unknown'}, 400
|
||||
else:
|
||||
return {'message': e.message}, 400
|
||||
return {'message': str(e)}, 400
|
||||
return wrapper
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
|
||||
:license: Apache, see LICENSE for more details.
|
||||
"""
|
||||
from builtins import str
|
||||
|
||||
from datetime import timedelta
|
||||
from flask import make_response, request, current_app
|
||||
|
||||
|
@ -16,10 +18,10 @@ def crossdomain(origin=None, methods=None, headers=None,
|
|||
if methods is not None:
|
||||
methods = ', '.join(sorted(x.upper() for x in methods))
|
||||
|
||||
if headers is not None and not isinstance(headers, basestring):
|
||||
if headers is not None and not isinstance(headers, str):
|
||||
headers = ', '.join(x.upper() for x in headers)
|
||||
|
||||
if not isinstance(origin, basestring):
|
||||
if not isinstance(origin, str):
|
||||
origin = ', '.join(origin)
|
||||
|
||||
if isinstance(max_age, timedelta):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
try:
|
||||
VERSION = __import__('pkg_resources') \
|
||||
.get_distribution(__name__).version
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
VERSION = 'unknown'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
try:
|
||||
VERSION = __import__('pkg_resources') \
|
||||
.get_distribution(__name__).version
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
VERSION = 'unknown'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
try:
|
||||
VERSION = __import__('pkg_resources') \
|
||||
.get_distribution(__name__).version
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
VERSION = 'unknown'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
try:
|
||||
VERSION = __import__('pkg_resources') \
|
||||
.get_distribution(__name__).version
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
VERSION = 'unknown'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
INTERNAL_VALID_LONG_STR = """
|
||||
INTERNAL_VALID_LONG_STR = b"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID1zCCAr+gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCVVMx
|
||||
CzAJBgNVBAgMAkNBMRAwDgYDVQQHDAdBIHBsYWNlMRcwFQYDVQQDDA5sb25nLmxp
|
||||
|
@ -29,7 +29,7 @@ h0S8LN4iv/+vNFPNiM1z9X/SZgfbwZXrLsSi
|
|||
INTERNAL_VALID_LONG_CERT = x509.load_pem_x509_certificate(INTERNAL_VALID_LONG_STR, default_backend())
|
||||
|
||||
|
||||
INTERNAL_INVALID_STR = """
|
||||
INTERNAL_INVALID_STR = b"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEFTCCAv2gAwIBAgICA+gwDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
|
||||
MQswCQYDVQQIDAJDQTEQMA4GA1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5s
|
||||
|
@ -58,7 +58,7 @@ kP+oGWtHvhteUAe8Gloo5NchZJ0/BqlYRCD5aAHcmbXRsDid9mO4ADU=
|
|||
INTERNAL_INVALID_CERT = x509.load_pem_x509_certificate(INTERNAL_INVALID_STR, default_backend())
|
||||
|
||||
|
||||
INTERNAL_VALID_SAN_STR = """
|
||||
INTERNAL_VALID_SAN_STR = b"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIESjCCAzKgAwIBAgICA+kwDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
|
||||
MQswCQYDVQQIDAJDQTEQMA4GA1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5s
|
||||
|
@ -88,7 +88,7 @@ YBrY/duF15YpoMKAlFhDBh6R9/nb5kI2n3pY6I5h6LEYfLStazXbIu61M8zu9TM/
|
|||
INTERNAL_VALID_SAN_CERT = x509.load_pem_x509_certificate(INTERNAL_VALID_SAN_STR, default_backend())
|
||||
|
||||
|
||||
INTERNAL_VALID_WILDCARD_STR = """
|
||||
INTERNAL_VALID_WILDCARD_STR = b"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEHDCCAwSgAwIBAgICA+owDQYJKoZIhvcNAQELBQAwgYwxCzAJBgNVBAYTAlVT
|
||||
MQswCQYDVQQIDAJDQTEQMA4GA1UEBwwHQSBwbGFjZTEXMBUGA1UEAwwObG9uZy5s
|
||||
|
@ -117,7 +117,7 @@ S0Xb3ZauZJQI7OdHeUPDRVq+8hcG77sopN9pEYrIH08oxvLX2US3GqrowjOxthRa
|
|||
INTERNAL_VALID_WILDCARD_CERT = x509.load_pem_x509_certificate(INTERNAL_VALID_WILDCARD_STR, default_backend())
|
||||
|
||||
|
||||
EXTERNAL_VALID_STR = """
|
||||
EXTERNAL_VALID_STR = b"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFHzCCBAegAwIBAgIQGFWCciDWzbOej/TbAJN0WzANBgkqhkiG9w0BAQsFADCB
|
||||
pDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
|
||||
|
@ -152,7 +152,7 @@ Bs63gULVCqWygt5KEbv990m/XGuRMaXuHzHCHB4v5LRM30FiFmqCzyD8d+btzW9B
|
|||
EXTERNAL_CERT = x509.load_pem_x509_certificate(EXTERNAL_VALID_STR, default_backend())
|
||||
|
||||
|
||||
PRIVATE_KEY_STR = """
|
||||
PRIVATE_KEY_STR = b"""
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAnEjM0cQevlDjT6mDMtTo8N1ovAyKbfVEp0ketCPC4hLkStms
|
||||
q9ETIyyerARIMv4SEhKqS4E7HIg6ccGkwv1ja5E/b2jHMH4ht1dEXnfM2yh0Mwvk
|
||||
|
@ -181,41 +181,3 @@ t5Gpocpt77LJnNiszXSerj/KjX2MflY5xUXeekWowLVTBOK5+CZ8+XBIgBt1hIG3
|
|||
XKxcRgm/Va4QMEAnec0qXfdTVJaJiAW0bdKwKRRrrbwcTdNRGibdng==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
"""
|
||||
|
||||
CSR_CONFIG = """
|
||||
# Configuration for standard CSR generation for Netflix
|
||||
# Used for procuring VeriSign certificates
|
||||
# Author: jbob
|
||||
# Contact: security@example.com
|
||||
|
||||
[ req ]
|
||||
# Use a 2048 bit private key
|
||||
default_bits = 2048
|
||||
default_keyfile = key.pem
|
||||
prompt = no
|
||||
encrypt_key = no
|
||||
|
||||
# base request
|
||||
distinguished_name = req_distinguished_name
|
||||
|
||||
# extensions
|
||||
# Uncomment the following line if you are requesting a SAN cert
|
||||
#req_extensions = req_ext
|
||||
|
||||
# distinguished_name
|
||||
[ req_distinguished_name ]
|
||||
countryName = "US" # C=
|
||||
stateOrProvinceName = "CALIFORNIA" # ST=
|
||||
localityName = "A place" # L=
|
||||
organizationName = "Example, Inc." # O=
|
||||
organizationalUnitName = "Operations" # OU=
|
||||
# This is the hostname/subject name on the certificate
|
||||
commonName = "example.net" # CN=
|
||||
|
||||
[ req_ext ]
|
||||
# Uncomment the following line if you are requesting a SAN cert
|
||||
#subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
# Put your SANs here
|
||||
"""
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import unicode_literals # at top of module
|
||||
|
||||
import pytest
|
||||
from lemur.certificates.views import * # noqa
|
||||
|
||||
|
@ -21,13 +23,13 @@ def test_private_key_str():
|
|||
def test_create_basic_csr():
|
||||
from lemur.certificates.service import create_csr
|
||||
csr_config = dict(
|
||||
commonName=u'example.com',
|
||||
organization=u'Example, Inc.',
|
||||
organizationalUnit=u'Operations',
|
||||
country=u'US',
|
||||
state=u'CA',
|
||||
location=u'A place',
|
||||
extensions=dict(names=dict(subAltNames=[u'test.example.com', u'test2.example.com']))
|
||||
commonName='example.com',
|
||||
organization='Example, Inc.',
|
||||
organizationalUnit='Operations',
|
||||
country='US',
|
||||
state='CA',
|
||||
location='A place',
|
||||
extensions=dict(names=dict(subAltNames=['test.example.com', 'test2.example.com']))
|
||||
)
|
||||
csr, pem = create_csr(csr_config)
|
||||
|
||||
|
|
3
setup.py
3
setup.py
|
@ -43,7 +43,8 @@ install_requires = [
|
|||
'pyopenssl==0.15.1',
|
||||
'pyjwt==1.0.1',
|
||||
'xmltodict==0.9.2',
|
||||
'lockfile==0.10.2'
|
||||
'lockfile==0.10.2',
|
||||
'future==0.15.0',
|
||||
]
|
||||
|
||||
tests_require = [
|
||||
|
|
Loading…
Reference in New Issue