Merge branch 'master' into entrust-plugin
This commit is contained in:
commit
8adca442e1
|
@ -172,15 +172,16 @@ Specifying the `SQLALCHEMY_MAX_OVERFLOW` to 0 will enforce limit to not create c
|
||||||
PUBLIC_CA_MAX_VALIDITY_DAYS = 365
|
PUBLIC_CA_MAX_VALIDITY_DAYS = 365
|
||||||
|
|
||||||
|
|
||||||
.. data:: DEFAULT_MAX_VALIDITY_DAYS
|
.. data:: DEFAULT_VALIDITY_DAYS
|
||||||
:noindex:
|
:noindex:
|
||||||
Use this config to override the default limit of 1095 days (3 years) of validity. Any CA which is not listed in
|
Use this config to override the default validity of 365 days for certificates offered through Lemur UI. Any CA which
|
||||||
PUBLIC_CA_AUTHORITY_NAMES will be using this validity to display date range on UI. Below example overrides the
|
is not listed in PUBLIC_CA_AUTHORITY_NAMES will be using this value as default validity to be displayed on UI. Please
|
||||||
default validity of 1095 days and sets it to 365 days.
|
note that this config is used for cert issuance only through Lemur UI. Below example overrides the default validity
|
||||||
|
of 365 days and sets it to 1095 days (3 years).
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
DEFAULT_MAX_VALIDITY_DAYS = 365
|
DEFAULT_VALIDITY_DAYS = 1095
|
||||||
|
|
||||||
|
|
||||||
.. data:: DEBUG_DUMP
|
.. data:: DEBUG_DUMP
|
||||||
|
|
|
@ -112,6 +112,7 @@ class RootAuthorityCertificateOutputSchema(LemurOutputSchema):
|
||||||
not_after = fields.DateTime()
|
not_after = fields.DateTime()
|
||||||
not_before = fields.DateTime()
|
not_before = fields.DateTime()
|
||||||
max_issuance_days = fields.Integer()
|
max_issuance_days = fields.Integer()
|
||||||
|
default_validity_days = fields.Integer()
|
||||||
owner = fields.Email()
|
owner = fields.Email()
|
||||||
status = fields.Boolean()
|
status = fields.Boolean()
|
||||||
user = fields.Nested(UserNestedOutputSchema)
|
user = fields.Nested(UserNestedOutputSchema)
|
||||||
|
@ -137,7 +138,7 @@ class AuthorityNestedOutputSchema(LemurOutputSchema):
|
||||||
owner = fields.Email()
|
owner = fields.Email()
|
||||||
plugin = fields.Nested(PluginOutputSchema)
|
plugin = fields.Nested(PluginOutputSchema)
|
||||||
active = fields.Boolean()
|
active = fields.Boolean()
|
||||||
authority_certificate = fields.Nested(RootAuthorityCertificateOutputSchema, only=["max_issuance_days"])
|
authority_certificate = fields.Nested(RootAuthorityCertificateOutputSchema, only=["max_issuance_days", "default_validity_days"])
|
||||||
|
|
||||||
|
|
||||||
authority_update_schema = AuthorityUpdateSchema()
|
authority_update_schema = AuthorityUpdateSchema()
|
||||||
|
|
|
@ -9,9 +9,10 @@ from datetime import timedelta
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
from cryptography.hazmat.primitives.asymmetric import rsa, ec
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from idna.core import InvalidCodepoint
|
from idna.core import InvalidCodepoint
|
||||||
|
from lemur.common.utils import get_key_type_from_ec_curve
|
||||||
from sqlalchemy import (
|
from sqlalchemy import (
|
||||||
event,
|
event,
|
||||||
Integer,
|
Integer,
|
||||||
|
@ -302,6 +303,8 @@ class Certificate(db.Model):
|
||||||
return "RSA{key_size}".format(
|
return "RSA{key_size}".format(
|
||||||
key_size=self.parsed_cert.public_key().key_size
|
key_size=self.parsed_cert.public_key().key_size
|
||||||
)
|
)
|
||||||
|
elif isinstance(self.parsed_cert.public_key(), ec.EllipticCurvePublicKey):
|
||||||
|
return get_key_type_from_ec_curve(self.parsed_cert.public_key().curve.name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def validity_remaining(self):
|
def validity_remaining(self):
|
||||||
|
@ -317,7 +320,13 @@ class Certificate(db.Model):
|
||||||
if self.name.lower() in [ca.lower() for ca in public_CA]:
|
if self.name.lower() in [ca.lower() for ca in public_CA]:
|
||||||
return current_app.config.get("PUBLIC_CA_MAX_VALIDITY_DAYS", 397)
|
return current_app.config.get("PUBLIC_CA_MAX_VALIDITY_DAYS", 397)
|
||||||
|
|
||||||
return current_app.config.get("DEFAULT_MAX_VALIDITY_DAYS", 1095) # 3 years default
|
@property
|
||||||
|
def default_validity_days(self):
|
||||||
|
public_CA = current_app.config.get("PUBLIC_CA_AUTHORITY_NAMES", [])
|
||||||
|
if self.name.lower() in [ca.lower() for ca in public_CA]:
|
||||||
|
return current_app.config.get("PUBLIC_CA_MAX_VALIDITY_DAYS", 397)
|
||||||
|
|
||||||
|
return current_app.config.get("DEFAULT_VALIDITY_DAYS", 365) # 1 year default
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def subject(self):
|
def subject(self):
|
||||||
|
|
|
@ -148,6 +148,13 @@ class CertificateInputSchema(CertificateCreationSchema):
|
||||||
data["extensions"]["subAltNames"]["names"] = []
|
data["extensions"]["subAltNames"]["names"] = []
|
||||||
|
|
||||||
data["extensions"]["subAltNames"]["names"] = csr_sans
|
data["extensions"]["subAltNames"]["names"] = csr_sans
|
||||||
|
|
||||||
|
common_name = cert_utils.get_cn_from_csr(data["csr"])
|
||||||
|
if common_name:
|
||||||
|
data["common_name"] = common_name
|
||||||
|
key_type = cert_utils.get_key_type_from_csr(data["csr"])
|
||||||
|
if key_type:
|
||||||
|
data["key_type"] = key_type
|
||||||
return missing.convert_validity_years(data)
|
return missing.convert_validity_years(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ Utils to parse certificate data.
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from marshmallow.exceptions import ValidationError
|
from marshmallow.exceptions import ValidationError
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa, ec
|
||||||
|
from lemur.common.utils import get_key_type_from_ec_curve
|
||||||
|
|
||||||
|
|
||||||
def get_sans_from_csr(data):
|
def get_sans_from_csr(data):
|
||||||
|
@ -39,3 +41,45 @@ def get_sans_from_csr(data):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return sub_alt_names
|
return sub_alt_names
|
||||||
|
|
||||||
|
|
||||||
|
def get_cn_from_csr(data):
|
||||||
|
"""
|
||||||
|
Fetches common name (CN) from CSR.
|
||||||
|
Works with any kind of SubjectAlternativeName
|
||||||
|
:param data: PEM-encoded string with CSR
|
||||||
|
:return: the common name
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
request = x509.load_pem_x509_csr(data.encode("utf-8"), default_backend())
|
||||||
|
except Exception:
|
||||||
|
raise ValidationError("CSR presented is not valid.")
|
||||||
|
|
||||||
|
common_name = request.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
|
||||||
|
return common_name[0].value
|
||||||
|
|
||||||
|
|
||||||
|
def get_key_type_from_csr(data):
|
||||||
|
"""
|
||||||
|
Fetches key_type from CSR.
|
||||||
|
Works with any kind of SubjectAlternativeName
|
||||||
|
:param data: PEM-encoded string with CSR
|
||||||
|
:return: key_type
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
request = x509.load_pem_x509_csr(data.encode("utf-8"), default_backend())
|
||||||
|
except Exception:
|
||||||
|
raise ValidationError("CSR presented is not valid.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if isinstance(request.public_key(), rsa.RSAPublicKey):
|
||||||
|
return "RSA{key_size}".format(
|
||||||
|
key_size=request.public_key().key_size
|
||||||
|
)
|
||||||
|
elif isinstance(request.public_key(), ec.EllipticCurvePublicKey):
|
||||||
|
return get_key_type_from_ec_curve(request.public_key().curve.name)
|
||||||
|
else:
|
||||||
|
raise Exception("Unsupported key type")
|
||||||
|
|
||||||
|
except NotImplemented:
|
||||||
|
raise NotImplemented()
|
||||||
|
|
|
@ -114,6 +114,39 @@ def get_authority_key(body):
|
||||||
return authority_key.hex()
|
return authority_key.hex()
|
||||||
|
|
||||||
|
|
||||||
|
def get_key_type_from_ec_curve(curve_name):
|
||||||
|
"""
|
||||||
|
Give an EC curve name, return the matching key_type.
|
||||||
|
|
||||||
|
:param: curve_name
|
||||||
|
:return: key_type
|
||||||
|
"""
|
||||||
|
|
||||||
|
_CURVE_TYPES = {
|
||||||
|
ec.SECP192R1().name: "ECCPRIME192V1",
|
||||||
|
ec.SECP256R1().name: "ECCPRIME256V1",
|
||||||
|
ec.SECP224R1().name: "ECCSECP224R1",
|
||||||
|
ec.SECP384R1().name: "ECCSECP384R1",
|
||||||
|
ec.SECP521R1().name: "ECCSECP521R1",
|
||||||
|
ec.SECP256K1().name: "ECCSECP256K1",
|
||||||
|
ec.SECT163K1().name: "ECCSECT163K1",
|
||||||
|
ec.SECT233K1().name: "ECCSECT233K1",
|
||||||
|
ec.SECT283K1().name: "ECCSECT283K1",
|
||||||
|
ec.SECT409K1().name: "ECCSECT409K1",
|
||||||
|
ec.SECT571K1().name: "ECCSECT571K1",
|
||||||
|
ec.SECT163R2().name: "ECCSECT163R2",
|
||||||
|
ec.SECT233R1().name: "ECCSECT233R1",
|
||||||
|
ec.SECT283R1().name: "ECCSECT283R1",
|
||||||
|
ec.SECT409R1().name: "ECCSECT409R1",
|
||||||
|
ec.SECT571R1().name: "ECCSECT571R2",
|
||||||
|
}
|
||||||
|
|
||||||
|
if curve_name in _CURVE_TYPES.keys():
|
||||||
|
return _CURVE_TYPES[curve_name]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def generate_private_key(key_type):
|
def generate_private_key(key_type):
|
||||||
"""
|
"""
|
||||||
Generates a new private key based on key_type.
|
Generates a new private key based on key_type.
|
||||||
|
@ -128,11 +161,11 @@ def generate_private_key(key_type):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_CURVE_TYPES = {
|
_CURVE_TYPES = {
|
||||||
"ECCPRIME192V1": ec.SECP192R1(),
|
"ECCPRIME192V1": ec.SECP192R1(), # duplicate
|
||||||
"ECCPRIME256V1": ec.SECP256R1(),
|
"ECCPRIME256V1": ec.SECP256R1(), # duplicate
|
||||||
"ECCSECP192R1": ec.SECP192R1(),
|
"ECCSECP192R1": ec.SECP192R1(), # duplicate
|
||||||
"ECCSECP224R1": ec.SECP224R1(),
|
"ECCSECP224R1": ec.SECP224R1(),
|
||||||
"ECCSECP256R1": ec.SECP256R1(),
|
"ECCSECP256R1": ec.SECP256R1(), # duplicate
|
||||||
"ECCSECP384R1": ec.SECP384R1(),
|
"ECCSECP384R1": ec.SECP384R1(),
|
||||||
"ECCSECP521R1": ec.SECP521R1(),
|
"ECCSECP521R1": ec.SECP521R1(),
|
||||||
"ECCSECP256K1": ec.SECP256K1(),
|
"ECCSECP256K1": ec.SECP256K1(),
|
||||||
|
|
|
@ -18,8 +18,9 @@ import json
|
||||||
import arrow
|
import arrow
|
||||||
import pem
|
import pem
|
||||||
import requests
|
import requests
|
||||||
|
import sys
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from flask import current_app
|
from flask import current_app, g
|
||||||
from lemur.common.utils import validate_conf
|
from lemur.common.utils import validate_conf
|
||||||
from lemur.extensions import metrics
|
from lemur.extensions import metrics
|
||||||
from lemur.plugins import lemur_digicert as digicert
|
from lemur.plugins import lemur_digicert as digicert
|
||||||
|
@ -129,6 +130,9 @@ def map_fields(options, csr):
|
||||||
data["validity_years"] = determine_validity_years(options.get("validity_years"))
|
data["validity_years"] = determine_validity_years(options.get("validity_years"))
|
||||||
elif options.get("validity_end"):
|
elif options.get("validity_end"):
|
||||||
data["custom_expiration_date"] = determine_end_date(options.get("validity_end")).format("YYYY-MM-DD")
|
data["custom_expiration_date"] = determine_end_date(options.get("validity_end")).format("YYYY-MM-DD")
|
||||||
|
# check if validity got truncated. If resultant validity is not equal to requested validity, it just got truncated
|
||||||
|
if data["custom_expiration_date"] != options.get("validity_end").format("YYYY-MM-DD"):
|
||||||
|
log_validity_truncation(options, f"{__name__}.{sys._getframe().f_code.co_name}")
|
||||||
else:
|
else:
|
||||||
data["validity_years"] = determine_validity_years(0)
|
data["validity_years"] = determine_validity_years(0)
|
||||||
|
|
||||||
|
@ -154,6 +158,9 @@ def map_cis_fields(options, csr):
|
||||||
validity_end = determine_end_date(arrow.utcnow().shift(years=options["validity_years"]))
|
validity_end = determine_end_date(arrow.utcnow().shift(years=options["validity_years"]))
|
||||||
elif options.get("validity_end"):
|
elif options.get("validity_end"):
|
||||||
validity_end = determine_end_date(options.get("validity_end"))
|
validity_end = determine_end_date(options.get("validity_end"))
|
||||||
|
# check if validity got truncated. If resultant validity is not equal to requested validity, it just got truncated
|
||||||
|
if validity_end != options.get("validity_end"):
|
||||||
|
log_validity_truncation(options, f"{__name__}.{sys._getframe().f_code.co_name}")
|
||||||
else:
|
else:
|
||||||
validity_end = determine_end_date(False)
|
validity_end = determine_end_date(False)
|
||||||
|
|
||||||
|
@ -179,6 +186,18 @@ def map_cis_fields(options, csr):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def log_validity_truncation(options, function):
|
||||||
|
log_data = {
|
||||||
|
"cn": options["common_name"],
|
||||||
|
"creator": g.user.username
|
||||||
|
}
|
||||||
|
metrics.send("digicert_validity_truncated", "counter", 1, metric_tags=log_data)
|
||||||
|
|
||||||
|
log_data["function"] = function
|
||||||
|
log_data["message"] = "Digicert Plugin truncated the validity of certificate"
|
||||||
|
current_app.logger.info(log_data)
|
||||||
|
|
||||||
|
|
||||||
def handle_response(response):
|
def handle_response(response):
|
||||||
"""
|
"""
|
||||||
Handle the DigiCert API response and any errors it might have experienced.
|
Handle the DigiCert API response and any errors it might have experienced.
|
||||||
|
|
|
@ -107,7 +107,6 @@ angular.module('lemur')
|
||||||
startingDay: 1
|
startingDay: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
$scope.open1 = function() {
|
$scope.open1 = function() {
|
||||||
$scope.popup1.opened = true;
|
$scope.popup1.opened = true;
|
||||||
};
|
};
|
||||||
|
@ -140,6 +139,14 @@ angular.module('lemur')
|
||||||
);
|
);
|
||||||
|
|
||||||
$scope.create = function (certificate) {
|
$scope.create = function (certificate) {
|
||||||
|
if(certificate.validityType === 'customDates' &&
|
||||||
|
(!certificate.validityStart || !certificate.validityEnd)) { // these are not mandatory fields in schema, thus handling validation in js
|
||||||
|
return showMissingDateError();
|
||||||
|
}
|
||||||
|
if(certificate.validityType === 'defaultDays') {
|
||||||
|
populateValidityDateAsPerDefault(certificate);
|
||||||
|
}
|
||||||
|
|
||||||
WizardHandler.wizard().context.loading = true;
|
WizardHandler.wizard().context.loading = true;
|
||||||
CertificateService.create(certificate).then(
|
CertificateService.create(certificate).then(
|
||||||
function () {
|
function () {
|
||||||
|
@ -164,6 +171,30 @@ angular.module('lemur')
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function showMissingDateError() {
|
||||||
|
let error = {};
|
||||||
|
error.message = '';
|
||||||
|
error.reasons = {};
|
||||||
|
error.reasons.validityRange = 'Valid start and end dates are needed, else select Default option';
|
||||||
|
|
||||||
|
toaster.pop({
|
||||||
|
type: 'error',
|
||||||
|
title: 'Validation Error',
|
||||||
|
body: 'lemur-bad-request',
|
||||||
|
bodyOutputType: 'directive',
|
||||||
|
directiveData: error,
|
||||||
|
timeout: 100000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateValidityDateAsPerDefault(certificate) {
|
||||||
|
// calculate start and end date as per default validity
|
||||||
|
let startDate = new Date(), endDate = new Date();
|
||||||
|
endDate.setDate(startDate.getDate() + certificate.authority.authorityCertificate.defaultValidityDays);
|
||||||
|
certificate.validityStart = startDate;
|
||||||
|
certificate.validityEnd = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
$scope.templates = [
|
$scope.templates = [
|
||||||
{
|
{
|
||||||
'name': 'Client Certificate',
|
'name': 'Client Certificate',
|
||||||
|
@ -277,6 +308,14 @@ angular.module('lemur')
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.create = function (certificate) {
|
$scope.create = function (certificate) {
|
||||||
|
if(certificate.validityType === 'customDates' &&
|
||||||
|
(!certificate.validityStart || !certificate.validityEnd)) { // these are not mandatory fields in schema, thus handling validation in js
|
||||||
|
return showMissingDateError();
|
||||||
|
}
|
||||||
|
if(certificate.validityType === 'defaultDays') {
|
||||||
|
populateValidityDateAsPerDefault(certificate);
|
||||||
|
}
|
||||||
|
|
||||||
WizardHandler.wizard().context.loading = true;
|
WizardHandler.wizard().context.loading = true;
|
||||||
CertificateService.create(certificate).then(
|
CertificateService.create(certificate).then(
|
||||||
function () {
|
function () {
|
||||||
|
@ -301,6 +340,30 @@ angular.module('lemur')
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function showMissingDateError() {
|
||||||
|
let error = {};
|
||||||
|
error.message = '';
|
||||||
|
error.reasons = {};
|
||||||
|
error.reasons.validityRange = 'Valid start and end dates are needed, else select Default option';
|
||||||
|
|
||||||
|
toaster.pop({
|
||||||
|
type: 'error',
|
||||||
|
title: 'Validation Error',
|
||||||
|
body: 'lemur-bad-request',
|
||||||
|
bodyOutputType: 'directive',
|
||||||
|
directiveData: error,
|
||||||
|
timeout: 100000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateValidityDateAsPerDefault(certificate) {
|
||||||
|
// calculate start and end date as per default validity
|
||||||
|
let startDate = new Date(), endDate = new Date();
|
||||||
|
endDate.setDate(startDate.getDate() + certificate.authority.authorityCertificate.defaultValidityDays);
|
||||||
|
certificate.validityStart = startDate;
|
||||||
|
certificate.validityEnd = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
$scope.templates = [
|
$scope.templates = [
|
||||||
{
|
{
|
||||||
'name': 'Client Certificate',
|
'name': 'Client Certificate',
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
name="certificate signing request"
|
name="certificate signing request"
|
||||||
ng-model="certificate.csr"
|
ng-model="certificate.csr"
|
||||||
placeholder="PEM encoded string..." class="form-control"
|
placeholder="PEM encoded string..." class="form-control"
|
||||||
ng-pattern="/^-----BEGIN CERTIFICATE REQUEST-----/"></textarea>
|
ng-pattern="/(^-----BEGIN CERTIFICATE REQUEST-----[\S\s]*-----END CERTIFICATE REQUEST-----)|(^-----BEGIN NEW CERTIFICATE REQUEST-----[\S\s]*-----END NEW CERTIFICATE REQUEST-----)/"></textarea>
|
||||||
|
|
||||||
<p ng-show="trackingForm.csr.$invalid && !trackingForm.csr.$pristine"
|
<p ng-show="trackingForm.csr.$invalid && !trackingForm.csr.$pristine"
|
||||||
class="help-block">Enter a valid certificate signing request.</p>
|
class="help-block">Enter a valid certificate signing request.</p>
|
||||||
|
|
|
@ -96,7 +96,7 @@
|
||||||
Certificate Authority
|
Certificate Authority
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<ui-select class="input-md" ng-model="certificate.authority" theme="bootstrap" title="choose an authority">
|
<ui-select class="input-md" ng-model="certificate.authority" theme="bootstrap" title="choose an authority" ng-change="clearDates()">
|
||||||
<ui-select-match placeholder="select an authority...">{{$select.selected.name}}</ui-select-match>
|
<ui-select-match placeholder="select an authority...">{{$select.selected.name}}</ui-select-match>
|
||||||
<ui-select-choices class="form-control" repeat="authority in authorities"
|
<ui-select-choices class="form-control" repeat="authority in authorities"
|
||||||
refresh="getAuthoritiesByName($select.search)"
|
refresh="getAuthoritiesByName($select.search)"
|
||||||
|
@ -133,22 +133,20 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" ng-hide="certificate.authority.plugin.slug == 'acme-issuer'">
|
<div class="form-group" ng-hide="certificate.authority.plugin.slug == 'acme-issuer'">
|
||||||
<label class="control-label col-sm-2"
|
<label class="control-label col-sm-2"
|
||||||
uib-tooltip="If no date is selected Lemur attempts to issue a 1 year certificate">
|
uib-tooltip="You can select custom date range; however, we recommend continuing with default validity.">
|
||||||
Validity Range <span class="glyphicon glyphicon-question-sign"></span>
|
Validity Range <span class="glyphicon glyphicon-question-sign"></span>
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-4">
|
||||||
<select ng-model="certificate.validityYears" class="form-control">
|
<div class="btn-group btn-group-toggle" data-toggle="buttons">
|
||||||
<option value="">-</option>
|
<label class="btn btn-info" ng-model="certificate.validityType" uib-btn-radio="'defaultDays'" ng-click="clearDates()">
|
||||||
<option value="1">1 year</option>
|
Default ({{certificate.authority.authorityCertificate.defaultValidityDays}} days)</label>
|
||||||
</select>
|
<label class="btn btn-info" ng-model="certificate.validityType" uib-btn-radio="'customDates'" ng-change="clearDates()">Custom</label>
|
||||||
</div>
|
</div>
|
||||||
<span style="padding-top: 15px" class="text-center col-sm-1">
|
</div>
|
||||||
<strong>or</strong>
|
<div class="col-sm-3" ng-if="certificate.validityType==='customDates'">
|
||||||
</span>
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control"
|
<input type="text" class="form-control"
|
||||||
uib-tooltip="yyyy/MM/dd"
|
uib-tooltip="Start Date (yyyy/MM/dd)"
|
||||||
uib-datepicker-popup="yyyy/MM/dd"
|
uib-datepicker-popup="yyyy/MM/dd"
|
||||||
ng-model="certificate.validityStart"
|
ng-model="certificate.validityStart"
|
||||||
ng-change="certificate.setValidityEndDateRange(certificate.validityStart)"
|
ng-change="certificate.setValidityEndDateRange(certificate.validityStart)"
|
||||||
|
@ -159,6 +157,7 @@
|
||||||
min-date="certificate.authority.authorityCertificate.notBefore"
|
min-date="certificate.authority.authorityCertificate.notBefore"
|
||||||
alt-input-formats="altInputFormats"
|
alt-input-formats="altInputFormats"
|
||||||
placeholder="Start Date"
|
placeholder="Start Date"
|
||||||
|
readonly="true"
|
||||||
/>
|
/>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="button" class="btn btn-default" ng-click="open1()"><i
|
<button type="button" class="btn btn-default" ng-click="open1()"><i
|
||||||
|
@ -166,10 +165,10 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3" ng-if="certificate.validityType==='customDates'">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control"
|
<input type="text" class="form-control"
|
||||||
uib-tooltip="yyyy/MM/dd"
|
uib-tooltip="End Date (yyyy/MM/dd)"
|
||||||
uib-datepicker-popup="yyyy/MM/dd"
|
uib-datepicker-popup="yyyy/MM/dd"
|
||||||
ng-model="certificate.validityEnd"
|
ng-model="certificate.validityEnd"
|
||||||
is-open="popup2.opened"
|
is-open="popup2.opened"
|
||||||
|
@ -179,6 +178,7 @@
|
||||||
min-date="certificate.authority.authorityCertificate.minValidityEnd"
|
min-date="certificate.authority.authorityCertificate.minValidityEnd"
|
||||||
alt-input-formats="altInputFormats"
|
alt-input-formats="altInputFormats"
|
||||||
placeholder="End Date"
|
placeholder="End Date"
|
||||||
|
readonly="true"
|
||||||
/>
|
/>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="button" class="btn btn-default" ng-click="open2()"><i
|
<button type="button" class="btn btn-default" ng-click="open2()"><i
|
||||||
|
@ -186,10 +186,6 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-1">
|
|
||||||
<button uib-tooltip="Clear Validity" ng-click="clearDates()" class="btn btn-default"><i
|
|
||||||
class="glyphicon glyphicon-remove"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" ng-show="certificate.authority.plugin.slug == 'acme-issuer'">
|
<div class="form-group" ng-show="certificate.authority.plugin.slug == 'acme-issuer'">
|
||||||
<label class="control-label col-sm-2">
|
<label class="control-label col-sm-2">
|
||||||
|
|
|
@ -167,18 +167,20 @@ angular.module('lemur')
|
||||||
},
|
},
|
||||||
setValidityEndDateRange: function (value) {
|
setValidityEndDateRange: function (value) {
|
||||||
// clear selected validity end date as we are about to calculate new range
|
// clear selected validity end date as we are about to calculate new range
|
||||||
if(this.validityEnd) {
|
|
||||||
this.validityEnd = '';
|
this.validityEnd = '';
|
||||||
}
|
|
||||||
|
|
||||||
// Minimum end date will be same as selected start date
|
// Minimum end date will be same as selected start date
|
||||||
this.authority.authorityCertificate.minValidityEnd = value;
|
this.authority.authorityCertificate.minValidityEnd = value;
|
||||||
|
|
||||||
|
if(!this.authority.authorityCertificate || !this.authority.authorityCertificate.maxIssuanceDays) {
|
||||||
|
this.authority.authorityCertificate.maxValidityEnd = this.authority.authorityCertificate.notAfter;
|
||||||
|
} else {
|
||||||
// Move max end date by maxIssuanceDays
|
// Move max end date by maxIssuanceDays
|
||||||
let endDate = new Date(value);
|
let endDate = new Date(value);
|
||||||
endDate.setDate(endDate.getDate() + this.authority.authorityCertificate.maxIssuanceDays);
|
endDate.setDate(endDate.getDate() + this.authority.authorityCertificate.maxIssuanceDays);
|
||||||
this.authority.authorityCertificate.maxValidityEnd = endDate;
|
this.authority.authorityCertificate.maxValidityEnd = endDate;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return LemurRestangular.all('certificates');
|
return LemurRestangular.all('certificates');
|
||||||
|
@ -195,7 +197,7 @@ angular.module('lemur')
|
||||||
CertificateService.create = function (certificate) {
|
CertificateService.create = function (certificate) {
|
||||||
certificate.attachSubAltName();
|
certificate.attachSubAltName();
|
||||||
certificate.attachCustom();
|
certificate.attachCustom();
|
||||||
if (certificate.validityYears === '') { // if a user de-selects validity years we ignore it
|
if (certificate.validityYears === '') { // if a user de-selects validity years we ignore it - might not be needed anymore
|
||||||
delete certificate.validityYears;
|
delete certificate.validityYears;
|
||||||
}
|
}
|
||||||
return CertificateApi.post(certificate);
|
return CertificateApi.post(certificate);
|
||||||
|
@ -281,6 +283,9 @@ angular.module('lemur')
|
||||||
certificate.authority.authorityCertificate.minValidityEnd = defaults.authority.authorityCertificate.notBefore;
|
certificate.authority.authorityCertificate.minValidityEnd = defaults.authority.authorityCertificate.notBefore;
|
||||||
certificate.authority.authorityCertificate.maxValidityEnd = defaults.authority.authorityCertificate.notAfter;
|
certificate.authority.authorityCertificate.maxValidityEnd = defaults.authority.authorityCertificate.notAfter;
|
||||||
|
|
||||||
|
// pre-select validity type radio button to default days
|
||||||
|
certificate.validityType = 'defaultDays';
|
||||||
|
|
||||||
if (certificate.dnsProviderId) {
|
if (certificate.dnsProviderId) {
|
||||||
certificate.dnsProvider = {id: certificate.dnsProviderId};
|
certificate.dnsProvider = {id: certificate.dnsProviderId};
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,18 +147,20 @@ angular.module('lemur')
|
||||||
},
|
},
|
||||||
setValidityEndDateRange: function (value) {
|
setValidityEndDateRange: function (value) {
|
||||||
// clear selected validity end date as we are about to calculate new range
|
// clear selected validity end date as we are about to calculate new range
|
||||||
if(this.validityEnd) {
|
|
||||||
this.validityEnd = '';
|
this.validityEnd = '';
|
||||||
}
|
|
||||||
|
|
||||||
// Minimum end date will be same as selected start date
|
// Minimum end date will be same as selected start date
|
||||||
this.authority.authorityCertificate.minValidityEnd = value;
|
this.authority.authorityCertificate.minValidityEnd = value;
|
||||||
|
|
||||||
|
if(!this.authority.authorityCertificate || !this.authority.authorityCertificate.maxIssuanceDays) {
|
||||||
|
this.authority.authorityCertificate.maxValidityEnd = this.authority.authorityCertificate.notAfter;
|
||||||
|
} else {
|
||||||
// Move max end date by maxIssuanceDays
|
// Move max end date by maxIssuanceDays
|
||||||
let endDate = new Date(value);
|
let endDate = new Date(value);
|
||||||
endDate.setDate(endDate.getDate() + this.authority.authorityCertificate.maxIssuanceDays);
|
endDate.setDate(endDate.getDate() + this.authority.authorityCertificate.maxIssuanceDays);
|
||||||
this.authority.authorityCertificate.maxValidityEnd = endDate;
|
this.authority.authorityCertificate.maxValidityEnd = endDate;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return LemurRestangular.all('pending_certificates');
|
return LemurRestangular.all('pending_certificates');
|
||||||
|
|
|
@ -11,6 +11,12 @@ from lemur.tests.vectors import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_key_type_from_ec_curve():
|
||||||
|
from lemur.common.utils import get_key_type_from_ec_curve
|
||||||
|
|
||||||
|
assert get_key_type_from_ec_curve("secp256r1") == "ECCPRIME256V1"
|
||||||
|
|
||||||
|
|
||||||
def test_generate_private_key():
|
def test_generate_private_key():
|
||||||
from lemur.common.utils import generate_private_key
|
from lemur.common.utils import generate_private_key
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue