249 lines
7.4 KiB
JavaScript
249 lines
7.4 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
import Model, { attr } from '@ember-data/model';
|
|
import { inject as service } from '@ember/service';
|
|
import { tracked } from '@glimmer/tracking';
|
|
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
|
import { withFormFields } from 'vault/decorators/model-form-fields';
|
|
import { withModelValidations } from 'vault/decorators/model-validations';
|
|
|
|
const validations = {
|
|
type: [{ type: 'presence', message: 'Type is required.' }],
|
|
commonName: [{ type: 'presence', message: 'Common name is required.' }],
|
|
issuerName: [
|
|
{
|
|
validator(model) {
|
|
if (
|
|
(model.actionType === 'generate-root' || model.actionType === 'rotate-root') &&
|
|
model.issuerName === 'default'
|
|
)
|
|
return false;
|
|
return true;
|
|
},
|
|
message: `Issuer name must be unique across all issuers and not be the reserved value 'default'.`,
|
|
},
|
|
],
|
|
keyName: [
|
|
{
|
|
validator(model) {
|
|
if (model.keyName === 'default') return false;
|
|
return true;
|
|
},
|
|
message: `Key name cannot be the reserved value 'default'`,
|
|
},
|
|
],
|
|
};
|
|
|
|
/**
|
|
* This model maps to multiple PKI endpoints, specifically the ones that make up the
|
|
* configuration/create workflow. These endpoints also share a nontypical behavior in that
|
|
* a POST request to the endpoints don't necessarily result in a single entity created --
|
|
* depending on the inputs, some number of issuers, keys, and certificates can be created
|
|
* from the API.
|
|
*/
|
|
@withModelValidations(validations)
|
|
@withFormFields()
|
|
export default class PkiActionModel extends Model {
|
|
@service secretMountPath;
|
|
|
|
@tracked actionType; // used to toggle between different form fields when creating configuration
|
|
|
|
/* actionType import */
|
|
@attr('string') pemBundle;
|
|
|
|
// parsed attrs from parse-pki-cert util if certificate on response
|
|
@attr parsedCertificate;
|
|
|
|
// readonly attrs returned after importing
|
|
@attr importedIssuers;
|
|
@attr importedKeys;
|
|
@attr mapping;
|
|
@attr('string', { readOnly: true, masked: true }) certificate;
|
|
|
|
/* actionType generate-root */
|
|
|
|
// readonly attrs returned right after root generation
|
|
@attr serialNumber;
|
|
@attr('string', { label: 'Issuing CA', readOnly: true, masked: true }) issuingCa;
|
|
// end of readonly
|
|
|
|
@attr('string', {
|
|
possibleValues: ['exported', 'internal', 'existing', 'kms'],
|
|
noDefault: true,
|
|
})
|
|
type;
|
|
|
|
@attr('string') issuerName;
|
|
|
|
@attr('string') keyName;
|
|
|
|
@attr('string', {
|
|
defaultValue: 'default',
|
|
label: 'Key reference',
|
|
})
|
|
keyRef; // type=existing only
|
|
|
|
@attr('string') commonName; // REQUIRED
|
|
|
|
@attr('string', {
|
|
label: 'Subject Alternative Names (SANs)',
|
|
editType: 'stringArray',
|
|
})
|
|
altNames;
|
|
|
|
@attr('string', {
|
|
label: 'IP Subject Alternative Names (IP SANs)',
|
|
editType: 'stringArray',
|
|
})
|
|
ipSans;
|
|
|
|
@attr('string', {
|
|
label: 'URI Subject Alternative Names (URI SANs)',
|
|
editType: 'stringArray',
|
|
})
|
|
uriSans;
|
|
|
|
@attr('string', {
|
|
label: 'Other SANs',
|
|
editType: 'stringArray',
|
|
})
|
|
otherSans;
|
|
|
|
@attr('string', {
|
|
defaultValue: 'pem',
|
|
possibleValues: ['pem', 'der', 'pem_bundle'],
|
|
})
|
|
format;
|
|
|
|
@attr('string', {
|
|
defaultValue: 'der',
|
|
possibleValues: ['der', 'pkcs8'],
|
|
})
|
|
privateKeyFormat;
|
|
|
|
@attr('string', {
|
|
defaultValue: 'rsa',
|
|
possibleValues: ['rsa', 'ed25519', 'ec'],
|
|
})
|
|
keyType;
|
|
|
|
@attr('string', {
|
|
defaultValue: '0',
|
|
// options management happens in pki-key-parameters
|
|
})
|
|
keyBits;
|
|
|
|
@attr('number', {
|
|
defaultValue: -1,
|
|
})
|
|
maxPathLength;
|
|
|
|
@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: 'Permitted DNS domains',
|
|
})
|
|
permittedDnsDomains;
|
|
|
|
@attr('string', {
|
|
label: 'Organizational Units (OU)',
|
|
subText:
|
|
'A list of allowed serial numbers to be requested during certificate issuance. Shell-style globbing is supported. If empty, custom-specified serial numbers will be forbidden.',
|
|
editType: 'stringArray',
|
|
})
|
|
ou;
|
|
@attr({ editType: 'stringArray' }) organization;
|
|
@attr({ editType: 'stringArray' }) country;
|
|
@attr({ editType: 'stringArray' }) locality;
|
|
@attr({ editType: 'stringArray' }) province;
|
|
@attr({ editType: 'stringArray' }) streetAddress;
|
|
@attr({ editType: 'stringArray' }) postalCode;
|
|
|
|
@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.",
|
|
})
|
|
subjectSerialNumber;
|
|
// this is different from the number (16:5e:a0...) randomly generated by Vault
|
|
// https://developer.hashicorp.com/vault/api-docs/secret/pki#serial_number
|
|
|
|
@attr('boolean', {
|
|
subText: 'Whether to add a Basic Constraints extension with CA: true.',
|
|
})
|
|
addBasicConstraints;
|
|
|
|
@attr({
|
|
label: 'Backdate validity',
|
|
detailsLabel: 'Issued certificate backdating',
|
|
helperTextDisabled: 'Vault will use the default value, 30s',
|
|
helperTextEnabled:
|
|
'Also called the not_before_duration property. Allows certificates to be valid for a certain time period before now. This is useful to correct clock misalignment on various systems when setting up your CA.',
|
|
editType: 'ttl',
|
|
defaultValue: '30s',
|
|
})
|
|
notBeforeDuration;
|
|
|
|
@attr('string') managedKeyName;
|
|
@attr('string', {
|
|
label: 'Managed key UUID',
|
|
})
|
|
managedKeyId;
|
|
|
|
@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('string') ttl;
|
|
@attr('date') notAfter;
|
|
|
|
@attr('string', { label: 'Issuer ID', readOnly: true, detailLinkTo: 'issuers.issuer.details' }) issuerId; // returned from generate-root action
|
|
|
|
// For generating and signing a CSR
|
|
@attr('string', { label: 'CSR', masked: true }) csr;
|
|
@attr caChain;
|
|
@attr('string', { label: 'Key ID', detailLinkTo: 'keys.key.details' }) keyId;
|
|
@attr('string', { masked: true }) privateKey;
|
|
@attr('string') privateKeyType;
|
|
|
|
get backend() {
|
|
return this.secretMountPath.currentPath;
|
|
}
|
|
|
|
// To determine which endpoint the config adapter should use,
|
|
// we want to check capabilities on the newer endpoints (those
|
|
// prefixed with "issuers") and use the old path as fallback
|
|
// if user does not have permissions.
|
|
@lazyCapabilities(apiPath`${'backend'}/issuers/import/bundle`, 'backend') importBundlePath;
|
|
@lazyCapabilities(apiPath`${'backend'}/issuers/generate/root/${'type'}`, 'backend', 'type')
|
|
generateIssuerRootPath;
|
|
@lazyCapabilities(apiPath`${'backend'}/issuers/generate/intermediate/${'type'}`, 'backend', 'type')
|
|
generateIssuerCsrPath;
|
|
@lazyCapabilities(apiPath`${'backend'}/issuers/cross-sign`, 'backend') crossSignPath;
|
|
|
|
get canImportBundle() {
|
|
return this.importBundlePath.get('canCreate') === true;
|
|
}
|
|
get canGenerateIssuerRoot() {
|
|
return this.generateIssuerRootPath.get('canCreate') === true;
|
|
}
|
|
get canGenerateIssuerIntermediate() {
|
|
return this.generateIssuerCsrPath.get('canCreate') === true;
|
|
}
|
|
get canCrossSign() {
|
|
return this.crossSignPath.get('canCreate') === true;
|
|
}
|
|
}
|