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) - 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 npm install
pip install "setuptools>=0.9.8" pip install "setuptools>=0.9.8"
# order matters here, base package must install first # 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 -e .
pip install "file://`pwd`#egg=lemur[dev]" pip install "file://`pwd`#egg=lemur[dev]"
pip install "file://`pwd`#egg=lemur[tests]" 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.destinations.views import mod as destinations_bp
from lemur.authorities.views import mod as authorities_bp from lemur.authorities.views import mod as authorities_bp
from lemur.certificates.views import mod as certificates_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.plugins.views import mod as plugins_bp
from lemur.notifications.views import mod as notifications_bp from lemur.notifications.views import mod as notifications_bp
from lemur.sources.views import mod as sources_bp from lemur.sources.views import mod as sources_bp
@ -31,7 +31,7 @@ LEMUR_BLUEPRINTS = (
destinations_bp, destinations_bp,
authorities_bp, authorities_bp,
certificates_bp, certificates_bp,
status_bp, defaults_bp,
plugins_bp, plugins_bp,
notifications_bp, notifications_bp,
sources_bp sources_bp

View File

@ -37,7 +37,7 @@ ViewRoleCredentialsNeed = partial(RoleUser, 'roleView')
class ViewRoleCredentialsPermission(Permission): class ViewRoleCredentialsPermission(Permission):
def __init__(self, role_id): def __init__(self, role_id):
need = ViewRoleCredentialsNeed(str(role_id)) need = ViewRoleCredentialsNeed(role_id)
super(ViewRoleCredentialsPermission, self).__init__(need, RoleNeed('admin')) 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 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. Update a an authority with new values.
@ -37,6 +37,9 @@ def update(authority_id, active=None, roles=None):
if active: if active:
authority.active = active authority.active = active
authority.description = description
authority.owner = owner
return database.update(authority) return database.update(authority)

View File

@ -20,6 +20,7 @@ from lemur.common.utils import paginated_parser, marshal_items
FIELDS = { FIELDS = {
'name': fields.String, 'name': fields.String,
'owner': fields.String,
'description': fields.String, 'description': fields.String,
'options': fields.Raw, 'options': fields.Raw,
'pluginName': fields.String, 'pluginName': fields.String,
@ -264,7 +265,9 @@ class Authorities(AuthenticatedResource):
{ {
"roles": [], "roles": [],
"active": false "active": false,
"owner": "bob@example.com",
"description": "this is authority1"
} }
**Example response**: **Example response**:
@ -279,12 +282,12 @@ class Authorities(AuthenticatedResource):
"id": 1, "id": 1,
"name": "authority1", "name": "authority1",
"description": "this is authority1", "description": "this is authority1",
"pluginname": null, "pluginName": null,
"chain": "-----begin ...", "chain": "-----begin ...",
"body": "-----begin ...", "body": "-----begin ...",
"active": false, "active": false,
"notbefore": "2015-06-05t17:09:39", "notBefore": "2015-06-05t17:09:39",
"notafter": "2015-06-10t17:09:39" "notAfter": "2015-06-10t17:09:39"
"options": null "options": null
} }
@ -292,8 +295,10 @@ class Authorities(AuthenticatedResource):
:statuscode 200: no error :statuscode 200: no error
:statuscode 403: unauthenticated :statuscode 403: unauthenticated
""" """
self.reqparse.add_argument('roles', type=list, location='json') self.reqparse.add_argument('roles', type=list, default=[], location='json')
self.reqparse.add_argument('active', type=str, 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() args = self.reqparse.parse_args()
authority = service.get(authority_id) 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 return dict(message="You are not allowed to associate a role which you are not a member of"), 400
if permission.can(): 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 return dict(message="You are not authorized to update this authority"), 403

View File

@ -6,14 +6,28 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com> .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
""" """
import os import os
import re
import hashlib
import requests import requests
import subprocess import subprocess
from OpenSSL import crypto from OpenSSL import crypto
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from flask import current_app 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): 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 :return: True if certificate is valid, False otherwise
:raise Exception: If certificate does not have CRL :raise Exception: If certificate does not have CRL
""" """
s = "(http(s)?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}/\S*?$)" with open(cert_path, 'rt') as c:
regex = re.compile(s, re.MULTILINE) cert = x509.load_pem_x509_certificate(c.read(), default_backend())
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, open(cert_path, 'rt').read()) distribution_points = cert.extensions.get_extension_for_oid(x509.OID_CRL_DISTRIBUTION_POINTS).value
for x in range(x509.get_extension_count()): for p in distribution_points:
ext = x509.get_extension(x) point = p.full_name[0].value
if ext.get_short_name() == 'crlDistributionPoints': response = requests.get(point)
r = regex.search(ext.get_data()) crl = crypto.load_crl(crypto.FILETYPE_ASN1, response.content) # TODO this should be switched to cryptography when support exists
points = r.groups() revoked = crl.get_revoked()
break for r in revoked:
else: if cert.serial == r.get_serial():
raise Exception("Certificate does not have a CRL distribution point") return
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
return True return True
@ -99,22 +104,6 @@ def verify(cert_path, issuer_chain_path):
raise Exception("Failed to verify") 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): def verify_string(cert_string, issuer_string):
""" """
Verify a certificate given only it's string value Verify a certificate given only it's string value
@ -123,13 +112,11 @@ def verify_string(cert_string, issuer_string):
:param issuer_string: :param issuer_string:
:return: True if valid, False otherwise :return: True if valid, False otherwise
""" """
cert_path = make_tmp_file(cert_string) with mktempfile() as cert_tmp:
issuer_path = make_tmp_file(issuer_string) with open(cert_tmp, 'w') as f:
status = verify(cert_path, issuer_path) f.write(cert_string)
remove_tmp_file(cert_path) with mktempfile() as issuer_tmp:
remove_tmp_file(issuer_path) with open(issuer_tmp, 'w') as f:
f.write(issuer_string)
status = verify(cert_tmp, issuer_tmp)
return status return status
def remove_tmp_file(file_path):
os.remove(file_path)

View File

@ -7,7 +7,7 @@
""" """
from builtins import str 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 flask.ext.restful import reqparse, Api, fields
from cryptography import x509 from cryptography import x509
@ -668,58 +668,9 @@ class NotificationCertificatesList(AuthenticatedResource):
return service.render(args) 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(CertificatesList, '/certificates', endpoint='certificates')
api.add_resource(Certificates, '/certificates/<int:certificate_id>', endpoint='certificate') api.add_resource(Certificates, '/certificates/<int:certificate_id>', endpoint='certificate')
api.add_resource(CertificatesStats, '/certificates/stats', endpoint='certificateStats') api.add_resource(CertificatesStats, '/certificates/stats', endpoint='certificateStats')
api.add_resource(CertificatesUpload, '/certificates/upload', endpoint='certificateUpload') api.add_resource(CertificatesUpload, '/certificates/upload', endpoint='certificateUpload')
api.add_resource(CertificatePrivateKey, '/certificates/<int:certificate_id>/key', endpoint='privateKeyCertificates') 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(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 sys
import base64 import base64
import time import time
import requests
import json
from gunicorn.config import make_settings from gunicorn.config import make_settings
from cryptography.fernet import Fernet from cryptography.fernet import Fernet
@ -146,12 +148,15 @@ def check_revoked():
as `unknown`. as `unknown`.
""" """
for cert in cert_service.get_all_certs(): for cert in cert_service.get_all_certs():
if cert.chain: try:
status = verify_string(cert.body, cert.chain) if cert.chain:
else: status = verify_string(cert.body, cert.chain)
status = verify_string(cert.body, "") 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) database.update(cert)
@ -181,7 +186,7 @@ def generate_settings():
return output return output
@manager.option('-s', '--sources', dest='labels', default='', required=False) @manager.option('-s', '--sources', dest='labels')
def sync_sources(labels): def sync_sources(labels):
""" """
Attempts to run several methods Certificate discovery. This is Attempts to run several methods Certificate discovery. This is
@ -207,13 +212,14 @@ def sync_sources(labels):
try: try:
sync_lock.acquire(timeout=10) # wait up to 10 seconds sync_lock.acquire(timeout=10) # wait up to 10 seconds
if labels: sys.stdout.write("[+] Staring to sync sources: {labels}!\n".format(labels=labels))
sys.stdout.write("[+] Staring to sync sources: {labels}!\n".format(labels=labels)) labels = labels.split(",")
labels = labels.split(",")
else: if labels[0] == 'all':
sys.stdout.write("[+] Starting to sync ALL sources!\n") sync()
else:
sync(labels=labels)
sync(labels=labels)
sys.stdout.write( sys.stdout.write(
"[+] Finished syncing sources. Run Time: {time}\n".format( "[+] Finished syncing sources. Run Time: {time}\n".format(
time=(time.time() - start_time) time=(time.time() - start_time)
@ -563,11 +569,11 @@ class ProvisionELB(Command):
'authority': authority, 'authority': authority,
'owner': owner, 'owner': owner,
# defaults: # defaults:
'organization': u'Netflix, Inc.', 'organization': current_app.config.get('LEMUR_DEFAULT_ORGANIZATION'),
'organizationalUnit': u'Operations', 'organizationalUnit': current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT'),
'country': u'US', 'country': current_app.config.get('LEMUR_DEFAULT_COUNTRY'),
'state': u'California', 'state': current_app.config.get('LEMUR_DEFAULT_STATE'),
'location': u'Los Gatos' 'location': current_app.config.get('LEMUR_DEFAULT_LOCATION')
} }
return options return options
@ -680,6 +686,38 @@ class ProvisionELB(Command):
done = True 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(): def main():
manager.add_command("start", LemurServer()) manager.add_command("start", LemurServer())
manager.add_command("runserver", Server(host='127.0.0.1')) manager.add_command("runserver", Server(host='127.0.0.1'))

View File

@ -9,7 +9,6 @@
""" """
import ssl import ssl
import socket
import arrow import arrow
@ -114,8 +113,9 @@ def _get_domain_certificate(name):
try: try:
pub_key = ssl.get_server_certificate((name, 443)) pub_key = ssl.get_server_certificate((name, 443))
return cert_service.find_duplicates(pub_key.strip()) return cert_service.find_duplicates(pub_key.strip())
except socket.gaierror as e: except Exception as e:
current_app.logger.info(str(e)) current_app.logger.info(str(e))
return []
def _find_superseded(cert): def _find_superseded(cert):

View File

@ -53,7 +53,7 @@
<hr /> <hr />
</div> </div>
<p> <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. you should create new certificates to replace the certificates that are expiring.
</p> </p>
<p> <p>

View File

@ -146,7 +146,7 @@ class VerisignIssuerPlugin(IssuerPlugin):
:param issuer_options: :param issuer_options:
:return: :raise Exception: :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 = process_options(issuer_options)
data['csr'] = csr data['csr'] = csr
@ -176,7 +176,7 @@ class VerisignIssuerPlugin(IssuerPlugin):
:return: :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'}) response = self.session.post(url, headers={'content-type': 'application/x-www-form-urlencoded'})
return handle_response(response.content)['Response']['Order'] 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) { lemur.factory('LemurRestangular', function (Restangular, $location, $auth) {
return Restangular.withConfig(function (RestangularConfigurer) { return Restangular.withConfig(function (RestangularConfigurer) {
RestangularConfigurer.setBaseUrl('http://localhost:5000/api/1'); 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) { .controller('AuthorityCreateController', function ($scope, $modalInstance, AuthorityService, LemurRestangular, RoleService, PluginService, WizardHandler) {
$scope.authority = LemurRestangular.restangularizeElement(null, {}, 'authorities'); $scope.authority = LemurRestangular.restangularizeElement(null, {}, 'authorities');
// set the defaults
AuthorityService.getDefaults($scope.authority);
$scope.loading = false; $scope.loading = false;
$scope.create = function (authority) { $scope.create = function (authority) {
WizardHandler.wizard().context.loading = true; WizardHandler.wizard().context.loading = true;

View File

@ -1,9 +1,32 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title"> <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>
<div class="modal-body"> <div class="modal-body">
<form name="createForm" class="form-horizontal" role="form" novalidate> <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"> <div class="form-group">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Roles Roles

View File

@ -16,7 +16,7 @@
Owner Owner
</label> </label>
<div class="col-sm-10"> <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> <p ng-show="trackingForm.ownerEmail.$invalid && !trackingForm.ownerEmail.$pristine" class="help-block">You must enter an Certificate Authority owner</p>
</div> </div>
</div> </div>

View File

@ -56,7 +56,7 @@ angular.module('lemur')
}); });
return LemurRestangular.all('authorities'); return LemurRestangular.all('authorities');
}) })
.service('AuthorityService', function ($location, AuthorityApi, toaster) { .service('AuthorityService', function ($location, AuthorityApi, DefaultService, toaster) {
var AuthorityService = this; var AuthorityService = this;
AuthorityService.findAuthorityByName = function (filterValue) { AuthorityService.findAuthorityByName = function (filterValue) {
return AuthorityApi.getList({'filter[name]': 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) { AuthorityService.getRoles = function (authority) {
return authority.getList('roles').then(function (roles) { return authority.getList('roles').then(function (roles) {
authority.roles = roles; authority.roles = roles;

View File

@ -46,7 +46,7 @@ angular.module('lemur')
$scope.edit = function (authorityId) { $scope.edit = function (authorityId) {
var modalInstance = $modal.open({ var modalInstance = $modal.open({
animation: true, animation: true,
templateUrl: '/angular/authorities/authority/authorityEdit.tpl.html', templateUrl: '/angular/authorities/authority/edit.tpl.html',
controller: 'AuthorityEditController', controller: 'AuthorityEditController',
size: 'lg', size: 'lg',
resolve: { 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 () { $scope.create = function () {
var modalInstance = $modal.open({ var modalInstance = $modal.open({
animation: true, animation: true,

View File

@ -29,7 +29,7 @@
</td> </td>
<td data-title="'Roles'"> <!--filter="{ 'select': 'role' }" filter-data="roleService.getRoleDropDown()">--> <td data-title="'Roles'"> <!--filter="{ 'select': 'role' }" filter-data="roleService.getRoleDropDown()">-->
<div class="btn-group"> <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 }} {{ role.name }}
</a> </a>
</div> </div>

View File

@ -4,7 +4,7 @@
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group"> <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" 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" 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" tooltip="Lemur can upload certificates to any pre-defined destination"

View File

@ -6,7 +6,7 @@
Owner Owner
</label> </label>
<div class="col-sm-10"> <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> <p ng-show="trackingForm.ownerEmail.$invalid && !trackingForm.ownerEmail.$pristine" class="help-block">You must enter an Certificate owner</p>
</div> </div>
</div> </div>

View File

@ -11,7 +11,7 @@
</label> </label>
<div class="col-sm-10"> <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/> class="form-control" required/>
<p ng-show="uploadForm.owner.$invalid && !uploadForm.owner.$pristine" class="help-block">Enter a valid <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> Custom Name <span class="glyphicon glyphicon-question-sign"></span>
</label> </label>
<div class="col-sm-10"> <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> </div>
<div class="form-group" <div class="form-group"

View File

@ -89,7 +89,7 @@ angular.module('lemur')
}); });
return LemurRestangular.all('certificates'); return LemurRestangular.all('certificates');
}) })
.service('CertificateService', function ($location, CertificateApi, LemurRestangular, toaster) { .service('CertificateService', function ($location, CertificateApi, LemurRestangular, DefaultService, toaster) {
var CertificateService = this; var CertificateService = this;
CertificateService.findCertificatesByName = function (filterValue) { CertificateService.findCertificatesByName = function (filterValue) {
return CertificateApi.getList({'filter[name]': filterValue}) return CertificateApi.getList({'filter[name]': filterValue})
@ -207,7 +207,7 @@ angular.module('lemur')
}; };
CertificateService.getDefaults = function (certificate) { CertificateService.getDefaults = function (certificate) {
return certificate.customGET('defaults').then(function (defaults) { return DefaultService.get().then(function (defaults) {
certificate.country = defaults.country; certificate.country = defaults.country;
certificate.state = defaults.state; certificate.state = defaults.state;
certificate.location = defaults.location; certificate.location = defaults.location;

View File

@ -55,7 +55,6 @@ angular.module('lemur')
title: role.name, title: role.name,
body: 'Has been successfully created!' body: 'Has been successfully created!'
}); });
$location.path('roles');
}, },
function (response) { function (response) {
toaster.pop({ toaster.pop({
@ -74,7 +73,6 @@ angular.module('lemur')
title: role.name, title: role.name,
body: 'Successfully updated!' body: 'Successfully updated!'
}); });
$location.path('roles');
}, },
function (response) { function (response) {
toaster.pop({ toaster.pop({

View File

@ -8,12 +8,5 @@
<div class="row featurette"> <div class="row featurette">
<div class="col-md-10"> <div class="col-md-10">
<h2 class="featurette-heading">SSL In The Cloud <span class="text-muted">Encrypt it all </span></h2> <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>
</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.develop import develop
from setuptools.command.install import install from setuptools.command.install import install
from setuptools.command.sdist import sdist from setuptools.command.sdist import sdist
from setuptools import setup from setuptools import setup, find_packages
from subprocess import check_output from subprocess import check_output
ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__))) ROOT = os.path.realpath(os.path.join(os.path.dirname(__file__)))
@ -39,7 +39,7 @@ install_requires = [
'six==1.9.0', 'six==1.9.0',
'gunicorn==19.3.0', 'gunicorn==19.3.0',
'pycrypto==2.6.1', 'pycrypto==2.6.1',
'cryptography>=1.0dev', 'cryptography==1.0.1',
'pyopenssl==0.15.1', 'pyopenssl==0.15.1',
'pyjwt==1.0.1', 'pyjwt==1.0.1',
'xmltodict==0.9.2', 'xmltodict==0.9.2',
@ -110,11 +110,11 @@ class BuildStatic(Command):
setup( setup(
name='lemur', name='lemur',
version='0.1', version='0.1.3',
author='Kevin Glisson', author='Kevin Glisson',
author_email='kglisson@netflix.com', author_email='kglisson@netflix.com',
long_description=open(os.path.join(ROOT, 'README.rst')).read(), long_description=open(os.path.join(ROOT, 'README.rst')).read(),
packages=['lemur'], packages=find_packages(),
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
install_requires=install_requires, install_requires=install_requires,
@ -127,7 +127,6 @@ setup(
'build_static': BuildStatic, 'build_static': BuildStatic,
'sdist': SdistWithBuildStatic, 'sdist': SdistWithBuildStatic,
'install': SmartInstall 'install': SmartInstall
}, },
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [