1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00
Files
browser/bitwarden_license/bit-web/src/app/auth/sso/sso.component.html

557 lines
18 KiB
HTML

<app-header></app-header>
<bit-container>
<ng-container *ngIf="loading">
<i
class="bwi bwi-spinner bwi-spin tw-text-muted"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
</ng-container>
<form [formGroup]="ssoConfigForm" [bitSubmit]="submit" *ngIf="!loading">
<p>
{{ "ssoPolicyHelpStart" | i18n }}
<a bitLink routerLink="../policies">{{ "ssoPolicyHelpAnchor" | i18n }}</a>
{{ "ssoPolicyHelpEnd" | i18n }}
<br />
</p>
<!-- Root form -->
<ng-container>
<bit-form-control>
<bit-label>{{ "allowSso" | i18n }}</bit-label>
<input bitCheckbox type="checkbox" formControlName="enabled" id="enabled" />
<bit-hint>{{ "allowSsoDesc" | i18n }}</bit-hint>
</bit-form-control>
<bit-form-field>
<bit-label>{{ "ssoIdentifier" | i18n }}</bit-label>
<input bitInput type="text" formControlName="ssoIdentifier" />
<bit-hint>
{{ "ssoIdentifierHintPartOne" | i18n }}
<a bitLink routerLink="../domain-verification">{{ "claimedDomains" | i18n }}</a>
</bit-hint>
</bit-form-field>
<bit-radio-group formControlName="memberDecryptionType">
<bit-label>{{ "memberDecryptionOption" | i18n }}</bit-label>
<bit-radio-button
class="tw-block"
id="memberDecryptionPass"
[value]="memberDecryptionType.MasterPassword"
>
<bit-label>{{ "masterPass" | i18n }}</bit-label>
</bit-radio-button>
<bit-radio-button
class="tw-block"
id="memberDecryptionKey"
[value]="memberDecryptionType.KeyConnector"
[disabled]="!organization.useKeyConnector || null"
*ngIf="showKeyConnectorOptions"
>
<bit-label>
{{ "keyConnector" | i18n }}
<a
target="_blank"
rel="noreferrer"
appA11yTitle="{{ 'learnMore' | i18n }}"
href="https://bitwarden.com/help/about-key-connector/"
slot="end"
bitLink
>
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
</a>
</bit-label>
<bit-hint>
{{ "memberDecryptionKeyConnectorDescStart" | i18n }}
<a bitLink routerLink="../policies">{{
"memberDecryptionKeyConnectorDescLink" | i18n
}}</a>
{{ "memberDecryptionKeyConnectorDescEnd" | i18n }}
</bit-hint>
</bit-radio-button>
<bit-radio-button
class="tw-block"
id="memberDecryptionTde"
[value]="memberDecryptionType.TrustedDeviceEncryption"
>
<bit-label>
{{ "trustedDevices" | i18n }}
</bit-label>
<bit-hint>
{{ "memberDecryptionOptionTdeDescPart1" | i18n }}
<a bitLink routerLink="../policies">
{{ "memberDecryptionOptionTdeDescLink1" | i18n }}
</a>
{{ "memberDecryptionOptionTdeDescPart2" | i18n }}
<a bitLink routerLink="../policies">
{{ "memberDecryptionOptionTdeDescLink2" | i18n }}
</a>
{{ "memberDecryptionOptionTdeDescPart3" | i18n }}
<a bitLink routerLink="../policies">
{{ "memberDecryptionOptionTdeDescLink3" | i18n }}
</a>
{{ "memberDecryptionOptionTdeDescPart4" | i18n }}
</bit-hint>
</bit-radio-button>
</bit-radio-group>
<!-- Key Connector -->
<ng-container
*ngIf="
ssoConfigForm.value.memberDecryptionType === memberDecryptionType.KeyConnector &&
showKeyConnectorOptions
"
>
<bit-callout type="warning" [useAlertRole]="true">
{{ "keyConnectorWarning" | i18n }}
</bit-callout>
<bit-form-field>
<bit-label>{{ "keyConnectorUrl" | i18n }}</bit-label>
<input
bitInput
type="text"
required
formControlName="keyConnectorUrl"
appInputStripSpaces
(input)="haveTestedKeyConnector = false"
/>
<button
bitSuffix
bitLink
[disabled]="!enableTestKeyConnector"
type="button"
(click)="validateKeyConnectorUrl()"
>
<i
class="bwi bwi-spinner bwi-spin"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
*ngIf="keyConnectorUrl.pending"
></i>
<span *ngIf="!keyConnectorUrl.pending">
{{ "keyConnectorTest" | i18n }}
</span>
</button>
<bit-hint
aria-live="polite"
*ngIf="haveTestedKeyConnector && !keyConnectorUrl.hasError('invalidUrl')"
>
<small class="tw-text-success-600">
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
{{ "keyConnectorTestSuccess" | i18n }}
</small>
</bit-hint>
</bit-form-field>
</ng-container>
<hr class="tw-mb-4" />
<bit-form-field>
<bit-label>{{ "type" | i18n }}</bit-label>
<select bitInput formControlName="configType">
<option *ngFor="let o of ssoTypeOptions" [ngValue]="o.value" disabled="{{ o.disabled }}">
{{ o.name }}
</option>
</select>
</bit-form-field>
</ng-container>
<!-- OIDC -->
<div
*ngIf="ssoConfigForm.get('configType').value === ssoType.OpenIdConnect"
[formGroup]="openIdForm"
>
<div>
<h2 bitTypography="h2">
{{ "openIdConnectConfig" | i18n }}
</h2>
<bit-form-field>
<bit-label>{{ "callbackPath" | i18n }}</bit-label>
<input bitInput disabled [value]="callbackPath" />
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="callbackPath"
[appA11yTitle]="'copyValue' | i18n"
></button>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "signedOutCallbackPath" | i18n }}</bit-label>
<input bitInput disabled [value]="signedOutCallbackPath" />
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="signedOutCallbackPath"
[appA11yTitle]="'copyValue' | i18n"
></button>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "authority" | i18n }}</bit-label>
<input bitInput type="text" formControlName="authority" appInputStripSpaces />
</bit-form-field>
<bit-form-field>
<bit-label>{{ "clientId" | i18n }}</bit-label>
<input bitInput type="text" formControlName="clientId" appInputStripSpaces />
</bit-form-field>
<bit-form-field>
<bit-label>{{ "clientSecret" | i18n }}</bit-label>
<input bitInput type="text" formControlName="clientSecret" appInputStripSpaces />
</bit-form-field>
<bit-form-field>
<bit-label>{{ "metadataAddress" | i18n }}</bit-label>
<input bitInput type="text" formControlName="metadataAddress" appInputStripSpaces />
<bit-hint>{{ "openIdAuthorityRequired" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "oidcRedirectBehavior" | i18n }}</bit-label>
<select bitInput formControlName="redirectBehavior">
<option
*ngFor="let o of connectRedirectOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<bit-form-control>
<bit-label>{{ "getClaimsFromUserInfoEndpoint" | i18n }}</bit-label>
<input
bitCheckbox
type="checkbox"
formControlName="getClaimsFromUserInfoEndpoint"
id="getClaimsFromUserInfoEndpoint"
/>
</bit-form-control>
<!-- Optional customizations -->
<div
class="tw-flex tw-flex-row tw-items-center tw-my-3 tw-text-main hover:tw-cursor-pointer"
(click)="toggleOpenIdCustomizations()"
>
<h3 class="tw-mb-0 tw-mr-2 tw-font-normal tw-uppercase" id="customizations-header">
{{ "openIdOptionalCustomizations" | i18n }}
</h3>
<button
bitLink
linkType="primary"
type="button"
appStopClick
role="button"
aria-controls="customizations"
[attr.aria-expanded]="showOpenIdCustomizations"
aria-labelledby="customizations-header"
>
<i
class="bwi"
aria-hidden="true"
[ngClass]="{
'bwi-angle-right': !showOpenIdCustomizations,
'bwi-angle-down': showOpenIdCustomizations,
}"
></i>
</button>
</div>
<div id="customizations" [hidden]="!showOpenIdCustomizations">
<bit-form-field>
<bit-label>{{ "additionalScopes" | i18n }}</bit-label>
<input bitInput type="text" formControlName="additionalScopes" />
<bit-hint>{{ "separateMultipleWithComma" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "additionalUserIdClaimTypes" | i18n }}</bit-label>
<input bitInput type="text" formControlName="additionalUserIdClaimTypes" />
<bit-hint>{{ "separateMultipleWithComma" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "additionalEmailClaimTypes" | i18n }}</bit-label>
<input bitInput type="text" formControlName="additionalEmailClaimTypes" />
<bit-hint>{{ "separateMultipleWithComma" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "additionalNameClaimTypes" | i18n }}</bit-label>
<input bitInput type="text" formControlName="additionalNameClaimTypes" />
<bit-hint>{{ "separateMultipleWithComma" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "acrValues" | i18n }}</bit-label>
<input bitInput type="text" formControlName="acrValues" />
<bit-hint>acr_values</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "expectedReturnAcrValue" | i18n }}</bit-label>
<input bitInput type="text" formControlName="expectedReturnAcrValue" />
<bit-hint>acr_validaton</bit-hint>
</bit-form-field>
</div>
</div>
</div>
<!-- SAML2 SP -->
<div *ngIf="ssoConfigForm.get('configType').value === ssoType.Saml2" [formGroup]="samlForm">
<!-- SAML2 SP -->
<div>
<h2 bitTypography="h2">
{{ "samlSpConfig" | i18n }}
</h2>
<bit-form-control>
<bit-label>{{ "spUniqueEntityId" | i18n }}</bit-label>
<input
bitCheckbox
type="checkbox"
formControlName="spUniqueEntityId"
id="spUniqueEntityId"
/>
<bit-hint>{{ "spUniqueEntityIdDesc" | i18n }}</bit-hint>
</bit-form-control>
<bit-form-field *ngIf="ssoConfigForm.value.saml.spUniqueEntityId">
<bit-label>{{ "spEntityId" | i18n }}</bit-label>
<input bitInput disabled [value]="spEntityId" />
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="spEntityId"
[appA11yTitle]="'copyValue' | i18n"
></button>
</bit-form-field>
<bit-form-field *ngIf="!ssoConfigForm.value.saml.spUniqueEntityId">
<bit-label>{{ "spEntityId" | i18n }}</bit-label>
<input bitInput disabled [value]="spEntityIdStatic" />
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="spEntityIdStatic"
[appA11yTitle]="'copyValue' | i18n"
></button>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "spMetadataUrl" | i18n }}</bit-label>
<input bitInput disabled [value]="spMetadataUrl" />
<button
bitIconButton="bwi-external-link"
bitSuffix
type="button"
[appLaunchClick]="spMetadataUrl"
[appA11yTitle]="'launch' | i18n"
></button>
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="spMetadataUrl"
[appA11yTitle]="'copyValue' | i18n"
></button>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "spAcsUrl" | i18n }}</bit-label>
<input bitInput disabled [value]="spAcsUrl" />
<button
bitIconButton="bwi-clone"
bitSuffix
type="button"
[appCopyClick]="spAcsUrl"
[appA11yTitle]="'copyValue' | i18n"
></button>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "spNameIdFormat" | i18n }}</bit-label>
<select bitInput formControlName="spNameIdFormat">
<option
*ngFor="let o of saml2NameIdFormatOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "spOutboundSigningAlgorithm" | i18n }}</bit-label>
<select bitInput formControlName="spOutboundSigningAlgorithm">
<option
*ngFor="let o of samlSigningAlgorithmOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "spSigningBehavior" | i18n }}</bit-label>
<select bitInput formControlName="spSigningBehavior">
<option
*ngFor="let o of saml2SigningBehaviourOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "spMinIncomingSigningAlgorithm" | i18n }}</bit-label>
<select bitInput formControlName="spMinIncomingSigningAlgorithm">
<option
*ngFor="let o of samlSigningAlgorithmOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<bit-form-control>
<bit-label>{{ "spWantAssertionsSigned" | i18n }}</bit-label>
<input
bitCheckbox
type="checkbox"
formControlName="spWantAssertionsSigned"
id="spWantAssertionsSigned"
/>
</bit-form-control>
<bit-form-control>
<bit-label>{{ "spValidateCertificates" | i18n }}</bit-label>
<input
bitCheckbox
type="checkbox"
formControlName="spValidateCertificates"
id="spValidateCertificates"
/>
</bit-form-control>
</div>
<!-- SAML2 IDP -->
<div>
<h2 bitTypography="h2">
{{ "samlIdpConfig" | i18n }}
</h2>
<bit-form-field>
<bit-label>{{ "idpEntityId" | i18n }}</bit-label>
<input bitInput type="text" formControlName="idpEntityId" />
</bit-form-field>
<bit-form-field>
<bit-label>{{ "idpBindingType" | i18n }}</bit-label>
<select bitInput formControlName="idpBindingType">
<option
*ngFor="let o of saml2BindingTypeOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "idpSingleSignOnServiceUrl" | i18n }}</bit-label>
<input
bitInput
type="text"
formControlName="idpSingleSignOnServiceUrl"
appInputStripSpaces
/>
<bit-hint>{{ "idpSingleSignOnServiceUrlRequired" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "idpSingleLogoutServiceUrl" | i18n }}</bit-label>
<input
bitInput
type="text"
formControlName="idpSingleLogoutServiceUrl"
appInputStripSpaces
/>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "idpX509PublicCert" | i18n }}</bit-label>
<textarea bitInput rows="6" formControlName="idpX509PublicCert"></textarea>
</bit-form-field>
<bit-form-field>
<bit-label>{{ "idpOutboundSigningAlgorithm" | i18n }}</bit-label>
<select bitInput formControlName="idpOutboundSigningAlgorithm">
<option
*ngFor="let o of samlSigningAlgorithmOptions"
[ngValue]="o.value"
disabled="{{ o.disabled }}"
>
{{ o.name }}
</option>
</select>
</bit-form-field>
<!--TODO: Uncomment once Unsolicited IdP Response is supported-->
<!-- <app-input-checkbox
controlId="idpAllowUnsolicitedAuthnResponse"
formControlName="idpAllowUnsolicitedAuthnResponse"
[label]="'idpAllowUnsolicitedAuthnResponse' | i18n"
></app-input-checkbox> -->
<bit-form-control>
<bit-label>{{ "idpAllowOutboundLogoutRequests" | i18n }}</bit-label>
<input
bitCheckbox
type="checkbox"
formControlName="idpAllowOutboundLogoutRequests"
id="idpAllowOutboundLogoutRequests"
/>
</bit-form-control>
<bit-form-control>
<bit-label>{{ "idpSignAuthenticationRequests" | i18n }}</bit-label>
<input
bitCheckbox
type="checkbox"
formControlName="idpWantAuthnRequestsSigned"
id="idpWantAuthnRequestsSigned"
/>
</bit-form-control>
</div>
</div>
<button type="submit" buttonType="primary" bitButton bitFormButton>
{{ "save" | i18n }}
</button>
<bit-error-summary [formGroup]="ssoConfigForm"></bit-error-summary>
</form>
</bit-container>