fixing merge conflict

This commit is contained in:
kevgliss 2015-09-11 08:38:48 -07:00
commit 25f652c1eb
30 changed files with 268 additions and 191 deletions

View File

@ -1 +1,2 @@
- Kevin Glisson (kglisson@netflix.com)
- Jeremy Heffner <jheffner@netflix.com>

4
MANIFEST.in Normal file
View File

@ -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 *~

View File

@ -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]"

View File

@ -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

View File

@ -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'))

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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')

63
lemur/defaults/views.py Normal file
View File

@ -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')

View File

@ -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'))

View File

@ -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):

View File

@ -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>

View File

@ -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']

View File

@ -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');

View File

@ -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;

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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,

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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"

View File

@ -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;

View File

@ -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({

View File

@ -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>

View File

@ -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"})

View File

@ -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': [