mirror of
https://github.com/bitwarden/server.git
synced 2025-01-10 20:07:56 +01:00
Added X.509 cert validation copy value buttons (#923)
This commit is contained in:
parent
1c3ba46246
commit
b429f6908d
@ -6,6 +6,10 @@ using Bit.Core;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Sso;
|
||||
using U2F.Core.Utils;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Bit.Portal.Models
|
||||
{
|
||||
@ -144,6 +148,35 @@ namespace Bit.Portal.Models
|
||||
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleSignOnServiceUrlValidationError"),
|
||||
new[] { nameof(model.IdpSingleSignOnServiceUrl) });
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(model.IdpX509PublicCert))
|
||||
{
|
||||
// Validate the certificate is in a valid format
|
||||
ValidationResult failedResult = null;
|
||||
try
|
||||
{
|
||||
var certData = StripPemCertificateElements(model.IdpX509PublicCert).Base64StringToByteArray();
|
||||
new X509Certificate2(certData);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertInvalidFormatValidationError"),
|
||||
new[] { nameof(model.IdpX509PublicCert) });
|
||||
}
|
||||
catch (CryptographicException cryptoEx)
|
||||
{
|
||||
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertCryptographicExceptionValidationError", cryptoEx.Message),
|
||||
new[] { nameof(model.IdpX509PublicCert) });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertValidationError", ex.Message),
|
||||
new[] { nameof(model.IdpX509PublicCert) });
|
||||
}
|
||||
if (failedResult != null)
|
||||
{
|
||||
yield return failedResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,7 +195,7 @@ namespace Bit.Portal.Models
|
||||
IdpSingleSignOnServiceUrl = IdpSingleSignOnServiceUrl,
|
||||
IdpSingleLogoutServiceUrl = IdpSingleLogoutServiceUrl,
|
||||
IdpArtifactResolutionServiceUrl = IdpArtifactResolutionServiceUrl,
|
||||
IdpX509PublicCert = IdpX509PublicCert,
|
||||
IdpX509PublicCert = StripPemCertificateElements(IdpX509PublicCert),
|
||||
IdpOutboundSigningAlgorithm = IdpOutboundSigningAlgorithm,
|
||||
IdpAllowUnsolicitedAuthnResponse = IdpAllowUnsolicitedAuthnResponse,
|
||||
IdpDisableOutboundLogoutRequests = IdpDisableOutboundLogoutRequests,
|
||||
@ -174,5 +207,13 @@ namespace Bit.Portal.Models
|
||||
SpValidateCertificates = SpValidateCertificates,
|
||||
};
|
||||
}
|
||||
|
||||
private string StripPemCertificateElements(string certificateText)
|
||||
{
|
||||
return Regex.Replace(certificateText,
|
||||
@"(((BEGIN|END) CERTIFICATE)|([\-\n\r\t\s\f]))",
|
||||
string.Empty,
|
||||
RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,3 +224,8 @@ input, select, textarea {
|
||||
.alert.validation-summary-errors > ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.input-validation-error {
|
||||
border: solid 1px $danger;
|
||||
border-color: $danger;
|
||||
}
|
@ -25,6 +25,16 @@
|
||||
$('#Data_ConfigType').change(function () {
|
||||
toggleVisibility();
|
||||
});
|
||||
|
||||
$('.copy-button').on('click', function () {
|
||||
const $control = $(this).closest('.form-group').find('input[type="text"], textarea');
|
||||
if ($control.length > 0) {
|
||||
const elem = $control[0];
|
||||
elem.select();
|
||||
elem.setSelectionRange(0, $control.val().length);
|
||||
document.execCommand('copy');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
@ -42,7 +52,7 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.ConfigType"></label>
|
||||
<select asp-for="Data.ConfigType" asp-items="Model.ConfigTypes" class="form-control"></select>
|
||||
</div>
|
||||
@ -53,47 +63,64 @@
|
||||
<div class="config-section">
|
||||
<h2>@i18nService.T("OpenIdConnectConfig")</h2>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.CallbackPath">@i18nService.T("CallbackPath")</label>
|
||||
<input asp-for="Data.CallbackPath" class="form-control" readonly>
|
||||
<div class="input-group">
|
||||
<input asp-for="Data.CallbackPath" class="form-control" readonly>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary copy-button"
|
||||
aria-label="@i18nService.T("CopyCallbackPath")" title="@i18nService.T("CopyCallbackPath")"
|
||||
tabindex="-1">
|
||||
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.SignedOutCallbackPath">@i18nService.T("SignedOutCallbackPath")</label>
|
||||
<input asp-for="Data.SignedOutCallbackPath" class="form-control" readonly>
|
||||
<div class="input-group">
|
||||
<input asp-for="Data.SignedOutCallbackPath" class="form-control" readonly>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary copy-button"
|
||||
aria-label="@i18nService.T("CopySignedOutCallbackPath")" title="@i18nService.T("CopySignedOutCallbackPath")"
|
||||
tabindex="-1">
|
||||
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.Authority">@i18nService.T("Authority")</label>
|
||||
<input asp-for="Data.Authority" class="form-control">
|
||||
<span asp-validation-for="Data.Authority" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.ClientId">@i18nService.T("ClientId")</label>
|
||||
<input asp-for="Data.ClientId" class="form-control">
|
||||
<span asp-validation-for="Data.ClientId" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.ClientSecret">@i18nService.T("ClientSecret")</label>
|
||||
<input asp-for="Data.ClientSecret" class="form-control">
|
||||
<span asp-validation-for="Data.ClientSecret" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.MetadataAddress">@i18nService.T("MetadataAddress")</label>
|
||||
<input asp-for="Data.MetadataAddress" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<div class="form-check">
|
||||
<input asp-for="Data.GetClaimsFromUserInfoEndpoint" type="checkbox" class="form-check-input">
|
||||
<label asp-for="Data.GetClaimsFromUserInfoEndpoint" class="form-check-label"></label>
|
||||
@ -108,33 +135,53 @@
|
||||
<div class="config-section">
|
||||
<h2>@i18nService.T("SamlSpConfig")</h2>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.SpEntityId">@i18nService.T("SpEntityId")</label>
|
||||
<input asp-for="Data.SpEntityId" class="form-control" readonly>
|
||||
<div class="input-group">
|
||||
<input asp-for="Data.SpEntityId" class="form-control" readonly>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary copy-button"
|
||||
aria-label="@i18nService.T("CopySpEntityId")" title="@i18nService.T("CopySpEntityId")"
|
||||
tabindex="-1">
|
||||
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.SpAcsUrl">@i18nService.T("SpAcsUrl")</label>
|
||||
<input asp-for="Data.SpAcsUrl" class="form-control" readonly>
|
||||
<div class="input-group">
|
||||
<input asp-for="Data.SpAcsUrl" class="form-control" readonly>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary copy-button"
|
||||
aria-label="@i18nService.T("CopySpAcsUrl")" title="@i18nService.T("CopySpAcsUrl")"
|
||||
tabindex="-1">
|
||||
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.SpNameIdFormat">@i18nService.T("NameIdFormat")</label>
|
||||
<select asp-for="Data.SpNameIdFormat" asp-items="Model.SpNameIdFormats"
|
||||
class="form-control"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.SpOutboundSigningAlgorithm">@i18nService.T("OutboundSigningAlgorithm")</label>
|
||||
<select asp-for="Data.SpOutboundSigningAlgorithm" asp-items="Model.SigningAlgorithms"
|
||||
class="form-control"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.SpSigningBehavior">@i18nService.T("SigningBehavior")</label>
|
||||
<select asp-for="Data.SpSigningBehavior" asp-items="Model.SigningBehaviors"
|
||||
class="form-control"></select>
|
||||
@ -159,46 +206,47 @@
|
||||
<h2>@i18nService.T("SamlIdpConfig")</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpEntityId">@i18nService.T("EntityId")</label>
|
||||
<input asp-for="Data.IdpEntityId" class="form-control">
|
||||
<span asp-validation-for="Data.IdpEntityId" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpBindingType"></label>
|
||||
<select asp-for="Data.IdpBindingType" asp-items="Model.BindingTypes" class="form-control"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpSingleSignOnServiceUrl">@i18nService.T("SingleSignOnServiceUrl")</label>
|
||||
<input asp-for="Data.IdpSingleSignOnServiceUrl" class="form-control">
|
||||
<span asp-validation-for="Data.IdpSingleSignOnServiceUrl" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpSingleLogoutServiceUrl">@i18nService.T("SingleLogoutServiceUrl")</label>
|
||||
<input asp-for="Data.IdpSingleLogoutServiceUrl" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpArtifactResolutionServiceUrl"></label>
|
||||
<input asp-for="Data.IdpArtifactResolutionServiceUrl" class="form-control">
|
||||
<span asp-validation-for="Data.IdpArtifactResolutionServiceUrl" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpX509PublicCert">@i18nService.T("X509PublicCert")</label>
|
||||
<textarea asp-for="Data.IdpX509PublicCert" class="form-control"></textarea>
|
||||
<textarea asp-for="Data.IdpX509PublicCert" class="form-control form-control-sm text-monospace" rows="6"></textarea>
|
||||
<span asp-validation-for="Data.IdpX509PublicCert" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6 form-group">
|
||||
<div class="col-7 form-group">
|
||||
<label asp-for="Data.IdpOutboundSigningAlgorithm"></label>
|
||||
<select asp-for="Data.IdpOutboundSigningAlgorithm" asp-items="Model.SigningAlgorithms"
|
||||
class="form-control"></select>
|
||||
|
@ -276,15 +276,19 @@
|
||||
</data>
|
||||
<data name="NotConfigured" xml:space="preserve">
|
||||
<value>Not Configured</value>
|
||||
<comment>A SAML Name ID format</comment>
|
||||
</data>
|
||||
<data name="Unspecified" xml:space="preserve">
|
||||
<value>Unspecified</value>
|
||||
<comment>A SAML Name ID format</comment>
|
||||
</data>
|
||||
<data name="EmailAddress" xml:space="preserve">
|
||||
<value>Email Address</value>
|
||||
<comment>A SAML Name ID format</comment>
|
||||
</data>
|
||||
<data name="X509SubjectName" xml:space="preserve">
|
||||
<value>X.509 Subject Name</value>
|
||||
<comment>A SAML Name ID format</comment>
|
||||
</data>
|
||||
<data name="WindowsDomainQualifiedName" xml:space="preserve">
|
||||
<value>Windows Domain Qualified Name</value>
|
||||
@ -297,9 +301,11 @@
|
||||
</data>
|
||||
<data name="Persistent" xml:space="preserve">
|
||||
<value>Persistent</value>
|
||||
<comment>A SAML Name ID format</comment>
|
||||
</data>
|
||||
<data name="Transient" xml:space="preserve">
|
||||
<value>Transient</value>
|
||||
<comment>A SAML Name ID format</comment>
|
||||
</data>
|
||||
<data name="PrivateKey" xml:space="preserve">
|
||||
<value>Private Key</value>
|
||||
@ -448,4 +454,37 @@
|
||||
<data name="WelcomeToBusinessPortal">
|
||||
<value>Welcome to the Bitwarden Business Portal</value>
|
||||
</data>
|
||||
<data name="IdpX509PublicCertValidationError" xml:space="preserve">
|
||||
<value>The IdP public certificate provided is invalid: {0}</value>
|
||||
</data>
|
||||
<data name="IdpX509PublicCertInvalidFormatValidationError" xml:space="preserve">
|
||||
<value>The IdP public certificate provided is not a valid Base64 encoded string, contains illegal characters or whitespace, or is incomplete.</value>
|
||||
</data>
|
||||
<data name="IdpX509PublicCertCryptographicExceptionValidationError" xml:space="preserve">
|
||||
<value>The IdP public certificate provided does not appear to be a valid certificate, please ensure this is a valid, Base64 encoded PEM or CER format public certificate valid for signing: {0}</value>
|
||||
</data>
|
||||
<data name="CopyCallbackPath">
|
||||
<value>Copy the OIDC callback path to your clipboard</value>
|
||||
</data>
|
||||
<data name="CopySignedOutCallbackPath">
|
||||
<value>Copy the OIDC signed out callback path to your clipboard</value>
|
||||
</data>
|
||||
<data name="CopySpEntityId">
|
||||
<value>Copy the SP Entity Id to your clipboard</value>
|
||||
</data>
|
||||
<data name="CopySpAcsUrl">
|
||||
<value>Copy the Assertion Consumer Service (ACS) URL to your clipboard</value>
|
||||
</data>
|
||||
<data name="HttpRedirect">
|
||||
<value>Redirect</value>
|
||||
<comment>A SAML binding type, Redirect</comment>
|
||||
</data>
|
||||
<data name="HttpPost">
|
||||
<value>HTTP POST</value>
|
||||
<comment>A SAML binding type, HTTP POST</comment>
|
||||
</data>
|
||||
<data name="Artifact">
|
||||
<value>Artifact</value>
|
||||
<comment>A SAML binding type, Artifact</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
Loading…
Reference in New Issue
Block a user