fixing merge conflict
This commit is contained in:
commit
25f652c1eb
1
AUTHORS
1
AUTHORS
|
@ -1 +1,2 @@
|
|||
- Kevin Glisson (kglisson@netflix.com)
|
||||
- Jeremy Heffner <jheffner@netflix.com>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
include setup.py package.json bower.json gulpfile.js README.rst MANIFEST.in LICENSE AUTHORS
|
||||
recursive-include lemur/plugins/lemur_email/templates *
|
||||
recursive-include lemur/static *
|
||||
global-exclude *~
|
2
Makefile
2
Makefile
|
@ -6,8 +6,6 @@ develop: update-submodules setup-git
|
|||
npm install
|
||||
pip install "setuptools>=0.9.8"
|
||||
# order matters here, base package must install first
|
||||
# this is temporary until the version we need is released
|
||||
pip install -e 'git+https://git@github.com/pyca/cryptography.git#egg=cryptography-1.0.dev1'
|
||||
pip install -e .
|
||||
pip install "file://`pwd`#egg=lemur[dev]"
|
||||
pip install "file://`pwd`#egg=lemur[tests]"
|
||||
|
|
|
@ -17,7 +17,7 @@ from lemur.domains.views import mod as domains_bp
|
|||
from lemur.destinations.views import mod as destinations_bp
|
||||
from lemur.authorities.views import mod as authorities_bp
|
||||
from lemur.certificates.views import mod as certificates_bp
|
||||
from lemur.status.views import mod as status_bp
|
||||
from lemur.defaults.views import mod as defaults_bp
|
||||
from lemur.plugins.views import mod as plugins_bp
|
||||
from lemur.notifications.views import mod as notifications_bp
|
||||
from lemur.sources.views import mod as sources_bp
|
||||
|
@ -31,7 +31,7 @@ LEMUR_BLUEPRINTS = (
|
|||
destinations_bp,
|
||||
authorities_bp,
|
||||
certificates_bp,
|
||||
status_bp,
|
||||
defaults_bp,
|
||||
plugins_bp,
|
||||
notifications_bp,
|
||||
sources_bp
|
||||
|
|
|
@ -37,7 +37,7 @@ ViewRoleCredentialsNeed = partial(RoleUser, 'roleView')
|
|||
|
||||
class ViewRoleCredentialsPermission(Permission):
|
||||
def __init__(self, role_id):
|
||||
need = ViewRoleCredentialsNeed(str(role_id))
|
||||
need = ViewRoleCredentialsNeed(role_id)
|
||||
super(ViewRoleCredentialsPermission, self).__init__(need, RoleNeed('admin'))
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ from lemur.certificates.models import Certificate
|
|||
from lemur.plugins.base import plugins
|
||||
|
||||
|
||||
def update(authority_id, active=None, roles=None):
|
||||
def update(authority_id, description=None, owner=None, active=None, roles=None):
|
||||
"""
|
||||
Update a an authority with new values.
|
||||
|
||||
|
@ -37,6 +37,9 @@ def update(authority_id, active=None, roles=None):
|
|||
|
||||
if active:
|
||||
authority.active = active
|
||||
|
||||
authority.description = description
|
||||
authority.owner = owner
|
||||
return database.update(authority)
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ from lemur.common.utils import paginated_parser, marshal_items
|
|||
|
||||
FIELDS = {
|
||||
'name': fields.String,
|
||||
'owner': fields.String,
|
||||
'description': fields.String,
|
||||
'options': fields.Raw,
|
||||
'pluginName': fields.String,
|
||||
|
@ -264,7 +265,9 @@ class Authorities(AuthenticatedResource):
|
|||
|
||||
{
|
||||
"roles": [],
|
||||
"active": false
|
||||
"active": false,
|
||||
"owner": "bob@example.com",
|
||||
"description": "this is authority1"
|
||||
}
|
||||
|
||||
**Example response**:
|
||||
|
@ -279,12 +282,12 @@ class Authorities(AuthenticatedResource):
|
|||
"id": 1,
|
||||
"name": "authority1",
|
||||
"description": "this is authority1",
|
||||
"pluginname": null,
|
||||
"pluginName": null,
|
||||
"chain": "-----begin ...",
|
||||
"body": "-----begin ...",
|
||||
"active": false,
|
||||
"notbefore": "2015-06-05t17:09:39",
|
||||
"notafter": "2015-06-10t17:09:39"
|
||||
"notBefore": "2015-06-05t17:09:39",
|
||||
"notAfter": "2015-06-10t17:09:39"
|
||||
"options": null
|
||||
}
|
||||
|
||||
|
@ -292,8 +295,10 @@ class Authorities(AuthenticatedResource):
|
|||
:statuscode 200: no error
|
||||
:statuscode 403: unauthenticated
|
||||
"""
|
||||
self.reqparse.add_argument('roles', type=list, location='json')
|
||||
self.reqparse.add_argument('active', type=str, location='json')
|
||||
self.reqparse.add_argument('roles', type=list, default=[], location='json')
|
||||
self.reqparse.add_argument('active', type=str, location='json', required=True)
|
||||
self.reqparse.add_argument('owner', type=str, location='json', required=True)
|
||||
self.reqparse.add_argument('description', type=str, location='json', required=True)
|
||||
args = self.reqparse.parse_args()
|
||||
|
||||
authority = service.get(authority_id)
|
||||
|
@ -315,7 +320,13 @@ class Authorities(AuthenticatedResource):
|
|||
return dict(message="You are not allowed to associate a role which you are not a member of"), 400
|
||||
|
||||
if permission.can():
|
||||
return service.update(authority_id, active=args['active'], roles=args['roles'])
|
||||
return service.update(
|
||||
authority_id,
|
||||
owner=args['owner'],
|
||||
description=args['description'],
|
||||
active=args['active'],
|
||||
roles=args['roles']
|
||||
)
|
||||
|
||||
return dict(message="You are not authorized to update this authority"), 403
|
||||
|
||||
|
|
|
@ -6,14 +6,28 @@
|
|||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import hashlib
|
||||
import requests
|
||||
import subprocess
|
||||
from OpenSSL import crypto
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from contextlib import contextmanager
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mktempfile():
|
||||
with NamedTemporaryFile(delete=False) as f:
|
||||
name = f.name
|
||||
|
||||
try:
|
||||
yield name
|
||||
finally:
|
||||
os.unlink(name)
|
||||
|
||||
|
||||
def ocsp_verify(cert_path, issuer_chain_path):
|
||||
"""
|
||||
|
@ -53,27 +67,18 @@ def crl_verify(cert_path):
|
|||
:return: True if certificate is valid, False otherwise
|
||||
:raise Exception: If certificate does not have CRL
|
||||
"""
|
||||
s = "(http(s)?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}/\S*?$)"
|
||||
regex = re.compile(s, re.MULTILINE)
|
||||
with open(cert_path, 'rt') as c:
|
||||
cert = x509.load_pem_x509_certificate(c.read(), default_backend())
|
||||
|
||||
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, open(cert_path, 'rt').read())
|
||||
for x in range(x509.get_extension_count()):
|
||||
ext = x509.get_extension(x)
|
||||
if ext.get_short_name() == 'crlDistributionPoints':
|
||||
r = regex.search(ext.get_data())
|
||||
points = r.groups()
|
||||
break
|
||||
else:
|
||||
raise Exception("Certificate does not have a CRL distribution point")
|
||||
|
||||
for point in points:
|
||||
if point:
|
||||
response = requests.get(point)
|
||||
crl = crypto.load_crl(crypto.FILETYPE_ASN1, response.content)
|
||||
revoked = crl.get_revoked()
|
||||
for r in revoked:
|
||||
if x509.get_serial_number() == r.get_serial():
|
||||
return
|
||||
distribution_points = cert.extensions.get_extension_for_oid(x509.OID_CRL_DISTRIBUTION_POINTS).value
|
||||
for p in distribution_points:
|
||||
point = p.full_name[0].value
|
||||
response = requests.get(point)
|
||||
crl = crypto.load_crl(crypto.FILETYPE_ASN1, response.content) # TODO this should be switched to cryptography when support exists
|
||||
revoked = crl.get_revoked()
|
||||
for r in revoked:
|
||||
if cert.serial == r.get_serial():
|
||||
return
|
||||
return True
|
||||
|
||||
|
||||
|
@ -99,22 +104,6 @@ def verify(cert_path, issuer_chain_path):
|
|||
raise Exception("Failed to verify")
|
||||
|
||||
|
||||
def make_tmp_file(string):
|
||||
"""
|
||||
Creates a temporary file for a given string
|
||||
|
||||
:param string:
|
||||
:return: Full file path to created file
|
||||
"""
|
||||
m = hashlib.md5()
|
||||
m.update(string)
|
||||
hexdigest = m.hexdigest()
|
||||
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), hexdigest)
|
||||
with open(path, 'w') as f:
|
||||
f.write(string)
|
||||
return path
|
||||
|
||||
|
||||
def verify_string(cert_string, issuer_string):
|
||||
"""
|
||||
Verify a certificate given only it's string value
|
||||
|
@ -123,13 +112,11 @@ def verify_string(cert_string, issuer_string):
|
|||
:param issuer_string:
|
||||
:return: True if valid, False otherwise
|
||||
"""
|
||||
cert_path = make_tmp_file(cert_string)
|
||||
issuer_path = make_tmp_file(issuer_string)
|
||||
status = verify(cert_path, issuer_path)
|
||||
remove_tmp_file(cert_path)
|
||||
remove_tmp_file(issuer_path)
|
||||
with mktempfile() as cert_tmp:
|
||||
with open(cert_tmp, 'w') as f:
|
||||
f.write(cert_string)
|
||||
with mktempfile() as issuer_tmp:
|
||||
with open(issuer_tmp, 'w') as f:
|
||||
f.write(issuer_string)
|
||||
status = verify(cert_tmp, issuer_tmp)
|
||||
return status
|
||||
|
||||
|
||||
def remove_tmp_file(file_path):
|
||||
os.remove(file_path)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"""
|
||||
from builtins import str
|
||||
|
||||
from flask import Blueprint, current_app, make_response, jsonify
|
||||
from flask import Blueprint, make_response, jsonify
|
||||
from flask.ext.restful import reqparse, Api, fields
|
||||
|
||||
from cryptography import x509
|
||||
|
@ -668,58 +668,9 @@ class NotificationCertificatesList(AuthenticatedResource):
|
|||
return service.render(args)
|
||||
|
||||
|
||||
class CertificatesDefaults(AuthenticatedResource):
|
||||
""" Defineds the 'certificates' defaults endpoint """
|
||||
def __init__(self):
|
||||
super(CertificatesDefaults)
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
.. http:get:: /certificates/defaults
|
||||
|
||||
Returns defaults needed to generate CSRs
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /certificates/defaults HTTP/1.1
|
||||
Host: example.com
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"country": "US",
|
||||
"state": "CA",
|
||||
"location": "Los Gatos",
|
||||
"organization": "Netflix",
|
||||
"organizationalUnit": "Operations"
|
||||
}
|
||||
|
||||
:reqheader Authorization: OAuth token to authenticate
|
||||
:statuscode 200: no error
|
||||
:statuscode 403: unauthenticated
|
||||
"""
|
||||
return dict(
|
||||
country=current_app.config.get('LEMUR_DEFAULT_COUNTRY'),
|
||||
state=current_app.config.get('LEMUR_DEFAULT_STATE'),
|
||||
location=current_app.config.get('LEMUR_DEFAULT_LOCATION'),
|
||||
organization=current_app.config.get('LEMUR_DEFAULT_ORGANIZATION'),
|
||||
organizationalUnit=current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT')
|
||||
)
|
||||
|
||||
|
||||
api.add_resource(CertificatesList, '/certificates', endpoint='certificates')
|
||||
api.add_resource(Certificates, '/certificates/<int:certificate_id>', endpoint='certificate')
|
||||
api.add_resource(CertificatesStats, '/certificates/stats', endpoint='certificateStats')
|
||||
api.add_resource(CertificatesUpload, '/certificates/upload', endpoint='certificateUpload')
|
||||
api.add_resource(CertificatePrivateKey, '/certificates/<int:certificate_id>/key', endpoint='privateKeyCertificates')
|
||||
api.add_resource(NotificationCertificatesList, '/notifications/<int:notification_id>/certificates', endpoint='notificationCertificates')
|
||||
api.add_resource(CertificatesDefaults, '/certificates/defaults', endpoint='certificatesDefault')
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
"""
|
||||
.. module: lemur.status.views
|
||||
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
|
||||
:license: Apache, see LICENSE for more details.
|
||||
"""
|
||||
from flask import current_app, Blueprint
|
||||
from flask.ext.restful import Api
|
||||
|
||||
from lemur.auth.service import AuthenticatedResource
|
||||
|
||||
|
||||
mod = Blueprint('default', __name__)
|
||||
api = Api(mod)
|
||||
|
||||
|
||||
class LemurDefaults(AuthenticatedResource):
|
||||
""" Defines the 'defaults' endpoint """
|
||||
def __init__(self):
|
||||
super(LemurDefaults)
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
.. http:get:: /defaults
|
||||
|
||||
Returns defaults needed to generate CSRs
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /defaults HTTP/1.1
|
||||
Host: example.com
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: text/javascript
|
||||
|
||||
{
|
||||
"country": "US",
|
||||
"state": "CA",
|
||||
"location": "Los Gatos",
|
||||
"organization": "Netflix",
|
||||
"organizationalUnit": "Operations"
|
||||
}
|
||||
|
||||
:reqheader Authorization: OAuth token to authenticate
|
||||
:statuscode 200: no error
|
||||
:statuscode 403: unauthenticated
|
||||
"""
|
||||
return dict(
|
||||
country=current_app.config.get('LEMUR_DEFAULT_COUNTRY'),
|
||||
state=current_app.config.get('LEMUR_DEFAULT_STATE'),
|
||||
location=current_app.config.get('LEMUR_DEFAULT_LOCATION'),
|
||||
organization=current_app.config.get('LEMUR_DEFAULT_ORGANIZATION'),
|
||||
organizationalUnit=current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT')
|
||||
)
|
||||
|
||||
api.add_resource(LemurDefaults, '/defaults', endpoint='default')
|
|
@ -4,6 +4,8 @@ import os
|
|||
import sys
|
||||
import base64
|
||||
import time
|
||||
import requests
|
||||
import json
|
||||
from gunicorn.config import make_settings
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
|
@ -146,12 +148,15 @@ def check_revoked():
|
|||
as `unknown`.
|
||||
"""
|
||||
for cert in cert_service.get_all_certs():
|
||||
if cert.chain:
|
||||
status = verify_string(cert.body, cert.chain)
|
||||
else:
|
||||
status = verify_string(cert.body, "")
|
||||
try:
|
||||
if cert.chain:
|
||||
status = verify_string(cert.body, cert.chain)
|
||||
else:
|
||||
status = verify_string(cert.body, "")
|
||||
|
||||
cert.status = 'valid' if status else "invalid"
|
||||
cert.status = 'valid' if status else 'invalid'
|
||||
except Exception as e:
|
||||
cert.status = 'unknown'
|
||||
database.update(cert)
|
||||
|
||||
|
||||
|
@ -181,7 +186,7 @@ def generate_settings():
|
|||
return output
|
||||
|
||||
|
||||
@manager.option('-s', '--sources', dest='labels', default='', required=False)
|
||||
@manager.option('-s', '--sources', dest='labels')
|
||||
def sync_sources(labels):
|
||||
"""
|
||||
Attempts to run several methods Certificate discovery. This is
|
||||
|
@ -207,13 +212,14 @@ def sync_sources(labels):
|
|||
try:
|
||||
sync_lock.acquire(timeout=10) # wait up to 10 seconds
|
||||
|
||||
if labels:
|
||||
sys.stdout.write("[+] Staring to sync sources: {labels}!\n".format(labels=labels))
|
||||
labels = labels.split(",")
|
||||
else:
|
||||
sys.stdout.write("[+] Starting to sync ALL sources!\n")
|
||||
sys.stdout.write("[+] Staring to sync sources: {labels}!\n".format(labels=labels))
|
||||
labels = labels.split(",")
|
||||
|
||||
if labels[0] == 'all':
|
||||
sync()
|
||||
else:
|
||||
sync(labels=labels)
|
||||
|
||||
sync(labels=labels)
|
||||
sys.stdout.write(
|
||||
"[+] Finished syncing sources. Run Time: {time}\n".format(
|
||||
time=(time.time() - start_time)
|
||||
|
@ -563,11 +569,11 @@ class ProvisionELB(Command):
|
|||
'authority': authority,
|
||||
'owner': owner,
|
||||
# defaults:
|
||||
'organization': u'Netflix, Inc.',
|
||||
'organizationalUnit': u'Operations',
|
||||
'country': u'US',
|
||||
'state': u'California',
|
||||
'location': u'Los Gatos'
|
||||
'organization': current_app.config.get('LEMUR_DEFAULT_ORGANIZATION'),
|
||||
'organizationalUnit': current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT'),
|
||||
'country': current_app.config.get('LEMUR_DEFAULT_COUNTRY'),
|
||||
'state': current_app.config.get('LEMUR_DEFAULT_STATE'),
|
||||
'location': current_app.config.get('LEMUR_DEFAULT_LOCATION')
|
||||
}
|
||||
|
||||
return options
|
||||
|
@ -680,6 +686,38 @@ class ProvisionELB(Command):
|
|||
done = True
|
||||
|
||||
|
||||
@manager.command
|
||||
def publish_verisign_units():
|
||||
"""
|
||||
Simple function that queries verisign for API units and posts the mertics to
|
||||
Atlas API for other teams to consume.
|
||||
:return:
|
||||
"""
|
||||
from lemur.plugins import plugins
|
||||
v = plugins.get('verisign-issuer')
|
||||
units = v.get_available_units()
|
||||
|
||||
metrics = {}
|
||||
for item in units:
|
||||
if item['@type'] in metrics.keys():
|
||||
metrics[item['@type']] += int(item['@remaining'])
|
||||
else:
|
||||
metrics.update({item['@type']: int(item['@remaining'])})
|
||||
|
||||
for name, value in metrics.items():
|
||||
metric = [
|
||||
{
|
||||
"timestamp": 1321351651,
|
||||
"type": "GAUGE",
|
||||
"name": "Symantec {0} Unit Count".format(name),
|
||||
"tags": {},
|
||||
"value": value
|
||||
}
|
||||
]
|
||||
|
||||
requests.post('http://localhost:8078/metrics', data=json.dumps(metric))
|
||||
|
||||
|
||||
def main():
|
||||
manager.add_command("start", LemurServer())
|
||||
manager.add_command("runserver", Server(host='127.0.0.1'))
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
"""
|
||||
import ssl
|
||||
import socket
|
||||
|
||||
import arrow
|
||||
|
||||
|
@ -114,8 +113,9 @@ def _get_domain_certificate(name):
|
|||
try:
|
||||
pub_key = ssl.get_server_certificate((name, 443))
|
||||
return cert_service.find_duplicates(pub_key.strip())
|
||||
except socket.gaierror as e:
|
||||
except Exception as e:
|
||||
current_app.logger.info(str(e))
|
||||
return []
|
||||
|
||||
|
||||
def _find_superseded(cert):
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
<hr />
|
||||
</div>
|
||||
<p>
|
||||
Lemur, Netflix's SSL management portal has noticed that the following certificates are expiring soon, if you rely on these certificates
|
||||
Lemur, has noticed that the following certificates are expiring soon, if you rely on these certificates
|
||||
you should create new certificates to replace the certificates that are expiring.
|
||||
</p>
|
||||
<p>
|
||||
|
|
|
@ -146,7 +146,7 @@ class VerisignIssuerPlugin(IssuerPlugin):
|
|||
:param issuer_options:
|
||||
:return: :raise Exception:
|
||||
"""
|
||||
url = current_app.config.get('VERISIGN_URL') + 'rest/services/enroll'
|
||||
url = current_app.config.get("VERISIGN_URL") + '/rest/services/enroll'
|
||||
|
||||
data = process_options(issuer_options)
|
||||
data['csr'] = csr
|
||||
|
@ -176,7 +176,7 @@ class VerisignIssuerPlugin(IssuerPlugin):
|
|||
|
||||
:return:
|
||||
"""
|
||||
url = current_app.config.get("VERISIGN_URL") + 'rest/services/getTokens'
|
||||
url = current_app.config.get("VERISIGN_URL") + '/rest/services/getTokens'
|
||||
response = self.session.post(url, headers={'content-type': 'application/x-www-form-urlencoded'})
|
||||
return handle_response(response.content)['Response']['Order']
|
||||
|
||||
|
|
|
@ -60,6 +60,15 @@ lemur.controller('datePickerController', function ($scope, $timeout){
|
|||
};
|
||||
});
|
||||
|
||||
lemur.service('DefaultService', function (LemurRestangular) {
|
||||
var DefaultService = this;
|
||||
DefaultService.get = function () {
|
||||
return LemurRestangular.all('defaults').customGET().then(function (defaults) {
|
||||
return defaults;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
lemur.factory('LemurRestangular', function (Restangular, $location, $auth) {
|
||||
return Restangular.withConfig(function (RestangularConfigurer) {
|
||||
RestangularConfigurer.setBaseUrl('http://localhost:5000/api/1');
|
||||
|
|
|
@ -30,6 +30,9 @@ angular.module('lemur')
|
|||
.controller('AuthorityCreateController', function ($scope, $modalInstance, AuthorityService, LemurRestangular, RoleService, PluginService, WizardHandler) {
|
||||
$scope.authority = LemurRestangular.restangularizeElement(null, {}, 'authorities');
|
||||
|
||||
// set the defaults
|
||||
AuthorityService.getDefaults($scope.authority);
|
||||
|
||||
$scope.loading = false;
|
||||
$scope.create = function (authority) {
|
||||
WizardHandler.wizard().context.loading = true;
|
||||
|
|
|
@ -1,9 +1,32 @@
|
|||
<div class="modal-header">
|
||||
<div class="modal-title">
|
||||
<div class="modal-header">Edit Authority <span class="text-muted"><small>chain of command!</small></span></div>
|
||||
<h3 class="modal-header">Edit <span class="text-muted"><small>{{ authority.name }}</small></span></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="createForm" class="form-horizontal" role="form" novalidate>
|
||||
<div class="form-group"
|
||||
ng-class="{'has-error': editForm.owner.$invalid, 'has-success': !editForm.owner.$invalid&&editForm.owner.$dirty}">
|
||||
<label class="control-label col-sm-2">
|
||||
Owner
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="email" name="owner" ng-model="authority.owner" placeholder="owner@example.com"
|
||||
class="form-control" required/>
|
||||
|
||||
<p ng-show="editForm.owner.$invalid && !editForm.owner.$pristine" class="help-block">Enter a valid
|
||||
email.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"
|
||||
ng-class="{'has-error': editForm.description.$invalid, 'has-success': !editForm.$invalid&&editForm.description.$dirty}">
|
||||
<label class="control-label col-sm-2">
|
||||
Description
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea name="description" ng-model="authority.description" placeholder="Something elegant" class="form-control" required></textarea>
|
||||
<p ng-show="editForm.description.$invalid && !editForm.description.$pristine" class="help-block">You must give a short description about this authority will be used for, this description should only include alphanumeric characters</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2">
|
||||
Roles
|
|
@ -16,7 +16,7 @@
|
|||
Owner
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="email" name="ownerEmail" ng-model="authority.ownerEmail" placeholder="TeamDL@netflix.com" tooltip="This is the authorities team distribution list or the main point of contact for this authority" class="form-control" required/>
|
||||
<input type="email" name="ownerEmail" ng-model="authority.ownerEmail" placeholder="TeamDL@example.com" tooltip="This is the authorities team distribution list or the main point of contact for this authority" class="form-control" required/>
|
||||
<p ng-show="trackingForm.ownerEmail.$invalid && !trackingForm.ownerEmail.$pristine" class="help-block">You must enter an Certificate Authority owner</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -56,7 +56,7 @@ angular.module('lemur')
|
|||
});
|
||||
return LemurRestangular.all('authorities');
|
||||
})
|
||||
.service('AuthorityService', function ($location, AuthorityApi, toaster) {
|
||||
.service('AuthorityService', function ($location, AuthorityApi, DefaultService, toaster) {
|
||||
var AuthorityService = this;
|
||||
AuthorityService.findAuthorityByName = function (filterValue) {
|
||||
return AuthorityApi.getList({'filter[name]': filterValue})
|
||||
|
@ -117,6 +117,16 @@ angular.module('lemur')
|
|||
});
|
||||
};
|
||||
|
||||
AuthorityService.getDefaults = function (authority) {
|
||||
return DefaultService.get().then(function (defaults) {
|
||||
authority.caDN.country = defaults.country;
|
||||
authority.caDN.state = defaults.state;
|
||||
authority.caDN.location = defaults.location;
|
||||
authority.caDN.organization = defaults.organization;
|
||||
authority.caDN.organizationalUnit = defaults.organizationalUnit;
|
||||
});
|
||||
};
|
||||
|
||||
AuthorityService.getRoles = function (authority) {
|
||||
return authority.getList('roles').then(function (roles) {
|
||||
authority.roles = roles;
|
||||
|
|
|
@ -46,7 +46,7 @@ angular.module('lemur')
|
|||
$scope.edit = function (authorityId) {
|
||||
var modalInstance = $modal.open({
|
||||
animation: true,
|
||||
templateUrl: '/angular/authorities/authority/authorityEdit.tpl.html',
|
||||
templateUrl: '/angular/authorities/authority/edit.tpl.html',
|
||||
controller: 'AuthorityEditController',
|
||||
size: 'lg',
|
||||
resolve: {
|
||||
|
@ -62,6 +62,25 @@ angular.module('lemur')
|
|||
|
||||
};
|
||||
|
||||
$scope.editRole = function (roleId) {
|
||||
var modalInstance = $modal.open({
|
||||
animation: true,
|
||||
templateUrl: '/angular/roles/role/role.tpl.html',
|
||||
controller: 'RolesEditController',
|
||||
size: 'lg',
|
||||
resolve: {
|
||||
editId: function () {
|
||||
return roleId;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
modalInstance.result.then(function () {
|
||||
$scope.authoritiesTable.reload();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.create = function () {
|
||||
var modalInstance = $modal.open({
|
||||
animation: true,
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</td>
|
||||
<td data-title="'Roles'"> <!--filter="{ 'select': 'role' }" filter-data="roleService.getRoleDropDown()">-->
|
||||
<div class="btn-group">
|
||||
<a href="#/roles/{{ role.id }}/edit" ng-repeat="role in authority.roles" class="btn btn-sm btn-danger">
|
||||
<a ng-click="editRole(role.id)" ng-repeat="role in authority.roles" class="btn btn-sm btn-danger">
|
||||
{{ role.name }}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group">
|
||||
<input type="text" ng-model="certificate.selectedDestination" placeholder="AWS, TheSecret..."
|
||||
<input type="text" ng-model="certificate.selectedDestination" placeholder="AWS..."
|
||||
typeahead="destination.label for destination in destinationService.findDestinationsByName($viewValue)" typeahead-loading="loadingDestinations"
|
||||
class="form-control input-md" typeahead-on-select="certificate.attachDestination($item)" typeahead-min-wait="50"
|
||||
tooltip="Lemur can upload certificates to any pre-defined destination"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
Owner
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="email" name="ownerEmail" ng-model="certificate.owner" placeholder="TeamDL@netflix.com" tooltip="This is the certificates team distribution list or main point of contact" class="form-control" required/>
|
||||
<input type="email" name="ownerEmail" ng-model="certificate.owner" placeholder="TeamDL@example.com" tooltip="This is the certificates team distribution list or main point of contact" class="form-control" required/>
|
||||
<p ng-show="trackingForm.ownerEmail.$invalid && !trackingForm.ownerEmail.$pristine" class="help-block">You must enter an Certificate owner</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</label>
|
||||
|
||||
<div class="col-sm-10">
|
||||
<input type="email" name="owner" ng-model="certificate.owner" placeholder="owner@netflix.com"
|
||||
<input type="email" name="owner" ng-model="certificate.owner" placeholder="owner@example.com"
|
||||
class="form-control" required/>
|
||||
|
||||
<p ng-show="uploadForm.owner.$invalid && !uploadForm.owner.$pristine" class="help-block">Enter a valid
|
||||
|
@ -24,7 +24,7 @@
|
|||
Custom Name <span class="glyphicon glyphicon-question-sign"></span>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="name" ng-model="certificate.name" placeholder="example.netflix.net-SymantecCorporation-20150828-20160830" class="form-control"/>
|
||||
<input name="name" ng-model="certificate.name" placeholder="the.example.net-SymantecCorporation-20150828-20160830" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"
|
||||
|
|
|
@ -89,7 +89,7 @@ angular.module('lemur')
|
|||
});
|
||||
return LemurRestangular.all('certificates');
|
||||
})
|
||||
.service('CertificateService', function ($location, CertificateApi, LemurRestangular, toaster) {
|
||||
.service('CertificateService', function ($location, CertificateApi, LemurRestangular, DefaultService, toaster) {
|
||||
var CertificateService = this;
|
||||
CertificateService.findCertificatesByName = function (filterValue) {
|
||||
return CertificateApi.getList({'filter[name]': filterValue})
|
||||
|
@ -207,7 +207,7 @@ angular.module('lemur')
|
|||
};
|
||||
|
||||
CertificateService.getDefaults = function (certificate) {
|
||||
return certificate.customGET('defaults').then(function (defaults) {
|
||||
return DefaultService.get().then(function (defaults) {
|
||||
certificate.country = defaults.country;
|
||||
certificate.state = defaults.state;
|
||||
certificate.location = defaults.location;
|
||||
|
|
|
@ -55,7 +55,6 @@ angular.module('lemur')
|
|||
title: role.name,
|
||||
body: 'Has been successfully created!'
|
||||
});
|
||||
$location.path('roles');
|
||||
},
|
||||
function (response) {
|
||||
toaster.pop({
|
||||
|
@ -74,7 +73,6 @@ angular.module('lemur')
|
|||
title: role.name,
|
||||
body: 'Successfully updated!'
|
||||
});
|
||||
$location.path('roles');
|
||||
},
|
||||
function (response) {
|
||||
toaster.pop({
|
||||
|
|
|
@ -8,12 +8,5 @@
|
|||
<div class="row featurette">
|
||||
<div class="col-md-10">
|
||||
<h2 class="featurette-heading">SSL In The Cloud <span class="text-muted">Encrypt it all </span></h2>
|
||||
|
||||
<p class="lead">The Security Operations team manages all of the SSL certificate generation at Netflix. This
|
||||
portal was created to serve as both a self service application so that application owners can provision
|
||||
their own certificates and to help enforce some key naming and security conventions, in order provide
|
||||
Netflix with scalable and manageable SSL security.</p>
|
||||
|
||||
<p>See <a href="http://go/ssl">go/ssl</a> for more info.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
"""
|
||||
.. module: lemur.status.views
|
||||
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
|
||||
:license: Apache, see LICENSE for more details.
|
||||
"""
|
||||
import os
|
||||
|
||||
from flask import app, Blueprint, jsonify
|
||||
from flask.ext.restful import Api
|
||||
|
||||
from lemur.auth.service import AuthenticatedResource
|
||||
|
||||
|
||||
mod = Blueprint('status', __name__)
|
||||
api = Api(mod)
|
||||
|
||||
|
||||
class Status(AuthenticatedResource):
|
||||
""" Defines the 'accounts' endpoint """
|
||||
def __init__(self):
|
||||
super(Status, self).__init__()
|
||||
|
||||
def get(self):
|
||||
if not os.path.isdir(os.path.join(app.config.get("KEY_PATH"), "decrypted")):
|
||||
return jsonify({
|
||||
'environment': app.config.get('ENVIRONMENT'),
|
||||
'status': 'degraded',
|
||||
'message': "This Lemur instance is in a degraded state and is unable to issue certificates, please alert secops@netflix.com"})
|
||||
else:
|
||||
return jsonify({
|
||||
'environment': app.config.get('ENVIRONMENT'),
|
||||
'status': 'healthy',
|
||||
'message': "This Lemur instance is healthy"})
|
9
setup.py
9
setup.py
|
@ -16,7 +16,7 @@ from distutils.core import Command
|
|||
from setuptools.command.develop import develop
|
||||
from setuptools.command.install import install
|
||||
from setuptools.command.sdist import sdist
|
||||
from setuptools import setup
|
||||
from setuptools import setup, find_packages
|
||||
from subprocess import check_output
|
||||
|
||||
ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__)))
|
||||
|
@ -39,7 +39,7 @@ install_requires = [
|
|||
'six==1.9.0',
|
||||
'gunicorn==19.3.0',
|
||||
'pycrypto==2.6.1',
|
||||
'cryptography>=1.0dev',
|
||||
'cryptography==1.0.1',
|
||||
'pyopenssl==0.15.1',
|
||||
'pyjwt==1.0.1',
|
||||
'xmltodict==0.9.2',
|
||||
|
@ -110,11 +110,11 @@ class BuildStatic(Command):
|
|||
|
||||
setup(
|
||||
name='lemur',
|
||||
version='0.1',
|
||||
version='0.1.3',
|
||||
author='Kevin Glisson',
|
||||
author_email='kglisson@netflix.com',
|
||||
long_description=open(os.path.join(ROOT, 'README.rst')).read(),
|
||||
packages=['lemur'],
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=install_requires,
|
||||
|
@ -127,7 +127,6 @@ setup(
|
|||
'build_static': BuildStatic,
|
||||
'sdist': SdistWithBuildStatic,
|
||||
'install': SmartInstall
|
||||
|
||||
},
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
|
|
Loading…
Reference in New Issue