Skip to content

Commit

Permalink
UI: Pki model attribute consolidation (#19281)
Browse files Browse the repository at this point in the history
  • Loading branch information
hellobontempo authored Feb 24, 2023
1 parent 431b424 commit 8657baf
Show file tree
Hide file tree
Showing 22 changed files with 248 additions and 145 deletions.
5 changes: 3 additions & 2 deletions ui/app/models/pki/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default class PkiActionModel extends Model {
label: 'Subject Alternative Names (SANs)',
editType: 'stringArray',
})
altNames; // comma sep strings
altNames;

@attr('string', {
label: 'IP Subject Alternative Names (IP SANs)',
Expand Down Expand Up @@ -129,7 +129,8 @@ export default class PkiActionModel extends Model {
@attr({ editType: 'stringArray' }) postalCode;

@attr('string', {
subText: "Specifies the requested Subject's named Serial Number value.",
subText:
"Specifies the requested Subject's named Serial Number value. This has no impact on the Certificate's serial number randomly generated by Vault.",
})
serialNumber;

Expand Down
74 changes: 51 additions & 23 deletions ui/app/models/pki/certificate/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { withFormFields } from 'vault/decorators/model-form-fields';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';

/**
* There are many ways to generate a cert, but we want to display them in a consistent way.
* This base certificate model will set the attributes we want to display, and other
* models under pki/certificate will extend this model and have their own required
* attributes and adapter methods.
* There are many actions that involve certificates in PKI world.
* The base certificate model contains shared attributes that make up a certificate's content.
* Other models under pki/certificate will extend this model and include additional attributes
* and associated adapter methods for performing various generation and signing actions.
* This model also displays leaf certs and their parsed attributes (parsed parameters only
* render if included in certDisplayFields below).
*/

const certDisplayFields = [
Expand All @@ -23,6 +25,7 @@ const certDisplayFields = [
@withFormFields(certDisplayFields)
export default class PkiCertificateBaseModel extends Model {
@service secretMountPath;

get useOpenAPI() {
return true;
}
Expand All @@ -33,7 +36,6 @@ export default class PkiCertificateBaseModel extends Model {
assert('You must provide a helpUrl for OpenAPI', true);
}

// Required input for all certificates
@attr('string') commonName;

@attr({
Expand All @@ -43,33 +45,59 @@ export default class PkiCertificateBaseModel extends Model {
'The time after which this certificate will no longer be valid. This can be a TTL (a range of time from now) or a specific date.',
editType: 'yield',
})
customTtl; // combines ttl and notAfter into one input <PkiNotValidAfterForm>
customTtl; // sets ttl and notAfter via one input <PkiNotValidAfterForm>

@attr('boolean', {
label: 'Exclude common name from SANs',
subText:
'If checked, the common name will not be included in DNS or Email Subject Alternate Names. This is useful if the CN is a human-readable identifier, not a hostname or email address.',
defaultValue: false,
})
excludeCnFromSans;

@attr('string', {
label: 'Subject Alternative Names (SANs)',
subText:
'The requested Subject Alternative Names; if email protection is enabled for the role, this may contain email addresses. Add one per row.',
editType: 'stringArray',
})
altNames;

// SANs below are editType: stringArray from openApi
@attr('string', {
label: 'IP Subject Alternative Names (IP SANs)',
subText: 'Only valid if the role allows IP SANs (which is the default). Add one per row.',
})
ipSans;

@attr('string', {
label: 'URI Subject Alternative Names (URI SANs)',
subText:
'If any requested URIs do not match role policy, the entire request will be denied. Add one per row.',
})
uriSans;

@attr('string', {
subText:
'Requested other SANs with the format <oid>;UTF8:<utf8 string value> for each entry. Add one per row.',
})
otherSans;

// Attrs that come back from API POST request
@attr({ masked: true, label: 'CA Chain' }) caChain;
@attr({ label: 'CA Chain', masked: true }) caChain;
@attr('string', { masked: true }) certificate;
@attr('number') expiration;
@attr('number', { formatDate: true }) revocationTime;
@attr('string', { label: 'Issuing CA', masked: true }) issuingCa;
@attr('string') privateKey;
@attr('string') privateKeyType;
@attr('string') privateKey; // only returned for type=exported
@attr('string') privateKeyType; // only returned for type=exported
@attr('number', { formatDate: true }) revocationTime;
@attr('string') serialNumber;

// Parsed from cert in serializer
@attr('number', { formatDate: true }) notValidAfter;
@attr('number', { formatDate: true }) notValidBefore;
@attr('string', { label: 'URI Subject Alternative Names (URI SANs)' }) uriSans;
@attr('string', { label: 'IP Subject Alternative Names (IP SANs)' }) ipSans;
@attr('string', { label: 'Subject Alternative Names (SANs)' }) altNames;
// read only attrs parsed from certificate contents in serializer on GET requests (see parse-pki-cert.js)
@attr('number', { formatDate: true }) notValidAfter; // set by ttl or notAfter (customTtL above)
@attr('number', { formatDate: true }) notValidBefore; // date certificate was issued
@attr('string') signatureBits;

// For importing
@attr('string') pemBundle;
// readonly attrs returned after importing
@attr importedIssuers;
@attr importedKeys;
@attr mapping;

@lazyCapabilities(apiPath`${'backend'}/revoke`, 'backend') revokePath;
get canRevoke() {
return this.revokePath.get('isLoading') || this.revokePath.get('canCreate') !== false;
Expand Down
4 changes: 2 additions & 2 deletions ui/app/models/pki/certificate/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ const generateFromRole = [
},
{
'Subject Alternative Name (SAN) Options': [
'excludeCnFromSans',
'altNames',
'ipSans',
'uriSans',
'otherSans',
'excludeCnFromSans',
],
},
{
Expand All @@ -24,5 +24,5 @@ export default class PkiCertificateGenerateModel extends PkiCertificateBaseModel
getHelpUrl(backend) {
return `/v1/${backend}/issue/example?help=1`;
}
@attr('string') role;
@attr('string') role; // role name to issue certificate against for request URL
}
13 changes: 2 additions & 11 deletions ui/app/models/pki/certificate/sign.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,16 @@ export default class PkiCertificateSignModel extends PkiCertificateBaseModel {
getHelpUrl(backend) {
return `/v1/${backend}/sign/example?help=1`;
}
@attr('string') role;
@attr('string') role; // role name to create certificate against for request URL

@attr('string', {
label: 'CSR',
editType: 'textarea',
})
csr;

@attr({
label: 'Not valid after',
detailsLabel: 'Issued certificates expire after',
subText:
'The time after which this certificate will no longer be valid. This can be a TTL (a range of time from now) or a specific date.',
editType: 'yield',
})
customTtl;

@attr('boolean', {
subText: 'When checked, the CA chain will not include self-signed CA certificates',
subText: 'When checked, the CA chain will not include self-signed CA certificates.',
})
removeRootsFromChain;
}
116 changes: 80 additions & 36 deletions ui/app/models/pki/issuer.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,69 @@
import PkiCertificateBaseModel from './certificate/base';
import { attr } from '@ember-data/model';
import Model, { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { service } from '@ember/service';

const issuerUrls = ['issuingCertificates', 'crlDistributionPoints', 'ocspServers'];
@withFormFields(
['issuerName', 'leafNotAfterBehavior', 'usage', 'manualChain', ...issuerUrls],
[
{
default: [
'certificate',
'caChain',
'commonName',
'issuerName',
'issuerId',
'serialNumber',
'keyId',
'uriSans',
'ipSans',
'notValidBefore',
'notValidAfter',
],
},
{ 'Issuer URLs': issuerUrls },
]
)
export default class PkiIssuerModel extends PkiCertificateBaseModel {
// there are too many differences between what openAPI returns and the designs for the update form
// manually defining the attrs instead with the correct meta data
const inputFields = [
'issuerName',
'leafNotAfterBehavior',
'usage',
'manualChain',
'revocationSignatureAlgorithm',
...issuerUrls,
];
const displayFields = [
{
default: [
'certificate',
'caChain',
'commonName',
'issuerName',
'issuerId',
'serialNumber',
'keyId',
'altNames',
'uriSans',
'ipSans',
'otherSans',
'notValidBefore',
'notValidAfter',
],
},
{ 'Issuer URLs': issuerUrls },
];
@withFormFields(inputFields, displayFields)
export default class PkiIssuerModel extends Model {
@service secretMountPath;
// TODO use openAPI after removing route extension (see pki/roles route for example)
get useOpenAPI() {
return false;
}

get backend() {
return this.secretMountPath.currentPath;
}
get issuerRef() {
return this.issuerName || this.issuerId;
}

@attr isDefault; // readonly
@attr('string') issuerId;
// READ ONLY
@attr isDefault;
@attr('string', { label: 'Issuer ID' }) issuerId;
@attr('string', { label: 'Default key ID' }) keyId;
@attr({ label: 'CA Chain', masked: true }) caChain;
@attr({ masked: true }) certificate;

@attr('string', {
label: 'Default key ID',
})
keyId;
// parsed from certificate contents in serializer (see parse-pki-cert.js)
@attr commonName;
@attr('number', { formatDate: true }) notValidAfter;
@attr('number', { formatDate: true }) notValidBefore;
@attr serialNumber; // this is not the UUID serial number field randomly generated by Vault for leaf certificates
@attr({ label: 'Subject Alternative Names (SANs)' }) altNames;
@attr({ label: 'IP SANs' }) ipSans;
@attr({ label: 'URI SANs' }) uriSans;
@attr({ label: 'Other SANs' }) otherSans;

// UPDATING
@attr('string') issuerName;

@attr({
Expand All @@ -57,7 +77,6 @@ export default class PkiIssuerModel extends PkiCertificateBaseModel {
leafNotAfterBehavior;

@attr({
label: 'Usage',
subText: 'Allowed usages for this issuer. It can always be read.',
editType: 'yield',
valueOptions: [
Expand All @@ -69,14 +88,32 @@ export default class PkiIssuerModel extends PkiCertificateBaseModel {
usage;

@attr('string', {
label: 'Manual chain',
subText:
"An advanced field useful when automatic chain building isn't desired. The first element must be the present issuer's reference.",
})
manualChain;

@attr({
subText:
'The signature algorithm to use when building CRLs. The default value (empty string) is for Go to select the signature algorithm automatically, which may not always work.',
noDefault: true,
possibleValues: [
'sha256withrsa',
'ecdsawithsha384',
'sha256withrsapss',
'ed25519',
'sha384withrsapss',
'sha512withrsapss',
'pureed25519',
'sha384withrsa',
'sha512withrsa',
'ecdsawithsha256',
'ecdsawithsha512',
],
})
revocationSignatureAlgorithm;

@attr('string', {
label: 'Issuing certificates',
subText:
'The URL values for the Issuing Certificate field. These are different URLs for the same resource, and should be added individually, not in a comma-separated list.',
editType: 'stringArray',
Expand All @@ -97,6 +134,13 @@ export default class PkiIssuerModel extends PkiCertificateBaseModel {
})
ocspServers;

// IMPORTING
@attr('string') pemBundle;
// readonly attrs returned after importing
@attr importedIssuers;
@attr importedKeys;
@attr mapping;

@lazyCapabilities(apiPath`${'backend'}/issuer/${'issuerId'}`) issuerPath;
@lazyCapabilities(apiPath`${'backend'}/root/rotate/exported`) rotateExported;
@lazyCapabilities(apiPath`${'backend'}/root/rotate/internal`) rotateInternal;
Expand Down
20 changes: 8 additions & 12 deletions ui/app/models/pki/sign-intermediate.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const validations = {
'csr',
'useCsrValues',
'commonName',
'excludeCnFromSans',
'customTtl',
'notBeforeDuration',
'format',
Expand Down Expand Up @@ -39,15 +40,6 @@ export default class PkiSignIntermediateModel extends PkiCertificateBaseModel {
})
useCsrValues;

@attr({
label: 'Not valid after',
detailsLabel: 'Issued certificates expire after',
subText:
'The time after which this certificate will no longer be valid. This can be a TTL (a range of time from now) or a specific date.',
editType: 'yield',
})
customTtl;

@attr({
label: 'Backdate validity',
detailsLabel: 'Issued certificate backdating',
Expand All @@ -59,9 +51,6 @@ export default class PkiSignIntermediateModel extends PkiCertificateBaseModel {
})
notBeforeDuration;

@attr('string')
commonName;

@attr({
label: 'Permitted DNS domains',
subText:
Expand Down Expand Up @@ -94,4 +83,11 @@ export default class PkiSignIntermediateModel extends PkiCertificateBaseModel {
possibleValues: ['0', '256', '384', '512'],
})
signatureBits;

/* Additional subject overrides */
@attr('string', {
subText:
"Specifies the requested Subject's named Serial Number value. This has no impact on the Certificate's serial number randomly generated by Vault.",
})
serialNumber;
}
Loading

0 comments on commit 8657baf

Please sign in to comment.