mirror of https://github.com/bitwarden/web.git
23 changed files with 637 additions and 111 deletions
@ -0,0 +1,284 @@ |
|||||||
|
<div class="page-header d-flex"> |
||||||
|
<h1>{{'singleSignOn' | i18n}}</h1> |
||||||
|
</div> |
||||||
|
|
||||||
|
<ng-container *ngIf="loading"> |
||||||
|
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i> |
||||||
|
<span class="sr-only">{{'loading' | i18n}}</span> |
||||||
|
</ng-container> |
||||||
|
|
||||||
|
<form #form (ngSubmit)="submit()" [formGroup]="data" [appApiAction]="formPromise" *ngIf="!loading"> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled"> |
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="form-group"> |
||||||
|
<label for="type">{{'type' | i18n}}</label> |
||||||
|
<select class="form-control" id="type" formControlName="configType"> |
||||||
|
<option value="0" disabled>{{'selectType' | i18n}}</option> |
||||||
|
<option value="1">OpenID Connect</option> |
||||||
|
<option value="2">SAML 2.0</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- OIDC --> |
||||||
|
<div *ngIf="data.value.configType == 1"> |
||||||
|
<div class="config-section"> |
||||||
|
<h2>{{'openIdConnectConfig' | i18n}}</h2> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'callbackPath' | i18n}}</label> |
||||||
|
<div class="input-group"> |
||||||
|
<input class="form-control" readonly [value]="callbackPath"> |
||||||
|
<div class="input-group-append"> |
||||||
|
<button type="button" class="btn btn-outline-secondary" |
||||||
|
appA11yTitle="{{'copyValue' | i18n}}" |
||||||
|
(click)="copy(data.value.callbackPath)"> |
||||||
|
<i class="fa fa-lg fa-clone" aria-hidden="true"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'signedOutCallbackPath' | i18n}}</label> |
||||||
|
<div class="input-group"> |
||||||
|
<input class="form-control" readonly [value]="signedOutCallbackPath"> |
||||||
|
<div class="input-group-append"> |
||||||
|
<button type="button" class="btn btn-outline-secondary" |
||||||
|
appA11yTitle="{{'copyValue' | i18n}}" |
||||||
|
(click)="copy(data.value.signedOutCallbackPath)"> |
||||||
|
<i class="fa fa-lg fa-clone" aria-hidden="true"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'authority' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="authority"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'clientId' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="clientId"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'clientSecret' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="clientSecret"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'metadataAddress' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="metadataAddress"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'oidcRedirectBehavior' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="redirectBehavior"> |
||||||
|
<option value="0">Redirect GET</option> |
||||||
|
<option value="1">Form POST</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="getClaimsFromUserInfoEndpoint" |
||||||
|
formControlName="getClaimsFromUserInfoEndpoint"> |
||||||
|
<label class="form-check-label" for="getClaimsFromUserInfoEndpoint"> |
||||||
|
{{'getClaimsFromUserInfoEndpoint' | i18n}} |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'additionalScopes' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="additionalScopes"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'additionalUserIdClaimTypes' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="additionalUserIdClaimTypes"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'additionalEmailClaimTypes' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="additionalEmailClaimTypes"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'additionalNameClaimTypes' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="additionalNameClaimTypes"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'acrValues' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="acrValues"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'expectedReturnAcrValue' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="expectedReturnAcrValue"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div *ngIf="data.value.configType == 2"> |
||||||
|
<!-- SAML2 SP --> |
||||||
|
<div class="config-section"> |
||||||
|
<h2>{{'samlSpConfig' | i18n}}</h2> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spEntityId' | i18n}}</label> |
||||||
|
<div class="input-group"> |
||||||
|
<input class="form-control" readonly [value]="spEntityId" > |
||||||
|
<div class="input-group-append"> |
||||||
|
<button type="button" class="btn btn-outline-secondary" |
||||||
|
appA11yTitle="{{'copyValue' | i18n}}" |
||||||
|
(click)="copy(data.value.spEntityId)"> |
||||||
|
<i class="fa fa-lg fa-clone" aria-hidden="true"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spMetadataUrl' | i18n}}</label> |
||||||
|
<div class="input-group"> |
||||||
|
<input class="form-control" readonly [value]="spMetadataUrl"> |
||||||
|
<div class="input-group-append"> |
||||||
|
<button type="button" class="btn btn-outline-secondary" |
||||||
|
appA11yTitle="{{'copyValue' | i18n}}" |
||||||
|
(click)="launchUri(data.value.spMetadataUrl)"> |
||||||
|
<i class="fa fa-lg fa-external-link" aria-hidden="true"></i> |
||||||
|
</button> |
||||||
|
<button type="button" class="btn btn-outline-secondary" |
||||||
|
appA11yTitle="{{'copyValue' | i18n}}" |
||||||
|
(click)="copy(data.value.spMetadataUrl)"> |
||||||
|
<i class="fa fa-lg fa-clone" aria-hidden="true"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spAcsUrl' | i18n}}</label> |
||||||
|
<div class="input-group"> |
||||||
|
<input class="form-control" readonly [value]="spAcsUrl"> |
||||||
|
<div class="input-group-append"> |
||||||
|
<button type="button" class="btn btn-outline-secondary" |
||||||
|
appA11yTitle="{{'copyValue' | i18n}}" |
||||||
|
(click)="copy(data.value.spAcsUrl)"> |
||||||
|
<i class="fa fa-lg fa-clone" aria-hidden="true"></i> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spNameIdFormat' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="spNameIdFormat"> |
||||||
|
<option value="0">Not Configured</option> |
||||||
|
<option value="1">Unspecified</option> |
||||||
|
<option value="2">Email Address</option> |
||||||
|
<option value="3">X.509 Subject Name</option> |
||||||
|
<option value="4">Windows Domain Qualified Name</option> |
||||||
|
<option value="5">Kerberos Principal Name</option> |
||||||
|
<option value="6">Entity Identifier</option> |
||||||
|
<option value="7">Persistent</option> |
||||||
|
<option value="8">Transient</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spOutboundSigningAlgorithm' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="spOutboundSigningAlgorithm"> |
||||||
|
<option *ngFor="let o of samlSigningAlgorithms" [ngValue]="o">{{o}}</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spSigningBehavior' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="spSigningBehavior"> |
||||||
|
<option value="0">If IdP Wants Authn Requests Signed</option> |
||||||
|
<option value="1">Always</option> |
||||||
|
<option value="3">Never</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'spMinIncomingSigningAlgorithm' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="spMinIncomingSigningAlgorithm"> |
||||||
|
<option *ngFor="let o of samlSigningAlgorithms" [ngValue]="o">{{o}}</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="spWantAssertionsSigned" formControlName="spWantAssertionsSigned"> |
||||||
|
<label class="form-check-label" for="spWantAssertionsSigned">{{'spWantAssertionsSigned' | i18n}}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="spValidateCertificates" formControlName="spValidateCertificates"> |
||||||
|
<label class="form-check-label" for="spValidateCertificates">{{'spValidateCertificates' | i18n}}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- SAML2 IDP --> |
||||||
|
<div class="config-section"> |
||||||
|
<h2>{{'samlIdpConfig' | i18n}}</h2> |
||||||
|
|
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpEntityId' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="idpEntityId"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpBindingType' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="idpBindingType"> |
||||||
|
<option value="1">Redirect</option> |
||||||
|
<option value="2">HTTP POST</option> |
||||||
|
<option value="4">Artifact</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpSingleSignOnServiceUrl' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="idpSingleSignOnServiceUrl"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpSingleLogoutServiceUrl' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="idpSingleLogoutServiceUrl"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpArtifactResolutionServiceUrl' | i18n}}</label> |
||||||
|
<input class="form-control" formControlName="idpArtifactResolutionServiceUrl"> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpX509PublicCert' | i18n}}</label> |
||||||
|
<textarea formControlName="idpX509PublicCert" class="form-control form-control-sm text-monospace" rows="6"></textarea> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<label>{{'idpOutboundSigningAlgorithm' | i18n}}</label> |
||||||
|
<select class="form-control" formControlName="idpOutboundSigningAlgorithm"> |
||||||
|
<option *ngFor="let o of samlSigningAlgorithms" [ngValue]="o">{{o}}</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="idpAllowUnsolicitedAuthnResponse" |
||||||
|
formControlName="idpAllowUnsolicitedAuthnResponse"> |
||||||
|
<label class="form-check-label" for="idpAllowUnsolicitedAuthnResponse"> |
||||||
|
{{'idpAllowUnsolicitedAuthnResponse' | i18n}} |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="idpDisableOutboundLogoutRequests" |
||||||
|
formControlName="idpDisableOutboundLogoutRequests"> |
||||||
|
<label class="form-check-label" for="idpDisableOutboundLogoutRequests"> |
||||||
|
{{'idpDisableOutboundLogoutRequests' | i18n}} |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="form-group"> |
||||||
|
<div class="form-check"> |
||||||
|
<input class="form-check-input" type="checkbox" id="idpWantAuthnRequestsSigned" |
||||||
|
formControlName="idpWantAuthnRequestsSigned"> |
||||||
|
<label class="form-check-label" for="idpWantAuthnRequestsSigned"> |
||||||
|
{{'idpWantAuthnRequestsSigned' | i18n}} |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading"> |
||||||
|
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i> |
||||||
|
<span>{{'save' | i18n}}</span> |
||||||
|
</button> |
||||||
|
</form> |
||||||
@ -0,0 +1,121 @@ |
|||||||
|
import { |
||||||
|
Component, |
||||||
|
OnInit, |
||||||
|
} from '@angular/core'; |
||||||
|
import { FormBuilder } from '@angular/forms'; |
||||||
|
import { ActivatedRoute } from '@angular/router'; |
||||||
|
|
||||||
|
import { ApiService } from 'jslib-common/abstractions/api.service'; |
||||||
|
import { I18nService } from 'jslib-common/abstractions/i18n.service'; |
||||||
|
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; |
||||||
|
import { OrganizationSsoRequest } from 'jslib-common/models/request/organization/organizationSsoRequest'; |
||||||
|
|
||||||
|
@Component({ |
||||||
|
selector: 'app-org-manage-sso', |
||||||
|
templateUrl: 'sso.component.html', |
||||||
|
}) |
||||||
|
export class SsoComponent implements OnInit { |
||||||
|
|
||||||
|
samlSigningAlgorithms = [ |
||||||
|
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', |
||||||
|
'http://www.w3.org/2000/09/xmldsig#rsa-sha384', |
||||||
|
'http://www.w3.org/2000/09/xmldsig#rsa-sha512', |
||||||
|
'http://www.w3.org/2000/09/xmldsig#rsa-sha1', |
||||||
|
]; |
||||||
|
|
||||||
|
loading = true; |
||||||
|
organizationId: string; |
||||||
|
formPromise: Promise<any>; |
||||||
|
|
||||||
|
callbackPath: string; |
||||||
|
signedOutCallbackPath: string; |
||||||
|
spEntityId: string; |
||||||
|
spMetadataUrl: string; |
||||||
|
spAcsUrl: string; |
||||||
|
|
||||||
|
enabled = this.fb.control(false); |
||||||
|
data = this.fb.group({ |
||||||
|
configType: [], |
||||||
|
|
||||||
|
// OpenId
|
||||||
|
authority: [], |
||||||
|
clientId: [], |
||||||
|
clientSecret: [], |
||||||
|
metadataAddress: [], |
||||||
|
redirectBehavior: [], |
||||||
|
getClaimsFromUserInfoEndpoint: [], |
||||||
|
additionalScopes: [], |
||||||
|
additionalUserIdClaimTypes: [], |
||||||
|
additionalEmailClaimTypes: [], |
||||||
|
additionalNameClaimTypes: [], |
||||||
|
acrValues: [], |
||||||
|
expectedReturnAcrValue: [], |
||||||
|
|
||||||
|
// SAML
|
||||||
|
spNameIdFormat: [], |
||||||
|
spOutboundSigningAlgorithm: [], |
||||||
|
spSigningBehavior: [], |
||||||
|
spMinIncomingSigningAlgorithm: [], |
||||||
|
spWantAssertionsSigned: [], |
||||||
|
spValidateCertificates: [], |
||||||
|
|
||||||
|
idpEntityId: [], |
||||||
|
idpBindingType: [], |
||||||
|
idpSingleSignOnServiceUrl: [], |
||||||
|
idpSingleLogoutServiceUrl: [], |
||||||
|
idpArtifactResolutionServiceUrl: [], |
||||||
|
idpX509PublicCert: [], |
||||||
|
idpOutboundSigningAlgorithm: [], |
||||||
|
idpAllowUnsolicitedAuthnResponse: [], |
||||||
|
idpDisableOutboundLogoutRequests: [], |
||||||
|
idpWantAuthnRequestsSigned: [], |
||||||
|
}); |
||||||
|
|
||||||
|
constructor(private fb: FormBuilder, private route: ActivatedRoute, private apiService: ApiService, |
||||||
|
private platformUtilsService: PlatformUtilsService, private i18nService: I18nService) { } |
||||||
|
|
||||||
|
async ngOnInit() { |
||||||
|
this.route.parent.parent.params.subscribe(async params => { |
||||||
|
this.organizationId = params.organizationId; |
||||||
|
await this.load(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
async load() { |
||||||
|
const ssoSettings = await this.apiService.getOrganizationSso(this.organizationId); |
||||||
|
|
||||||
|
this.data.patchValue(ssoSettings.data); |
||||||
|
this.enabled.setValue(ssoSettings.enabled); |
||||||
|
|
||||||
|
this.callbackPath = ssoSettings.urls.callbackPath; |
||||||
|
this.signedOutCallbackPath = ssoSettings.urls.signedOutCallbackPath; |
||||||
|
this.spEntityId = ssoSettings.urls.spEntityId; |
||||||
|
this.spMetadataUrl = ssoSettings.urls.spMetadataUrl; |
||||||
|
this.spAcsUrl = ssoSettings.urls.spAcsUrl; |
||||||
|
|
||||||
|
this.loading = false; |
||||||
|
} |
||||||
|
|
||||||
|
copy(value: string) { |
||||||
|
this.platformUtilsService.copyToClipboard(value); |
||||||
|
} |
||||||
|
|
||||||
|
launchUri(url: string) { |
||||||
|
this.platformUtilsService.launchUri(url); |
||||||
|
} |
||||||
|
|
||||||
|
async submit() { |
||||||
|
const request = new OrganizationSsoRequest(); |
||||||
|
request.enabled = this.enabled.value; |
||||||
|
request.data = this.data.value; |
||||||
|
|
||||||
|
this.formPromise = this.apiService.postOrganizationSso(this.organizationId, request); |
||||||
|
|
||||||
|
const response = await this.formPromise; |
||||||
|
this.data.patchValue(response.data); |
||||||
|
this.enabled.setValue(response.enabled); |
||||||
|
|
||||||
|
this.formPromise = null; |
||||||
|
this.platformUtilsService.showToast('success', null, this.i18nService.t('ssoSettingsSaved')); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
import { NgModule } from '@angular/core'; |
||||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||||
|
|
||||||
|
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service'; |
||||||
|
|
||||||
|
import { Permissions } from 'jslib-common/enums/permissions'; |
||||||
|
|
||||||
|
import { OrganizationLayoutComponent } from 'src/app/layouts/organization-layout.component'; |
||||||
|
import { ManageComponent } from 'src/app/organizations/manage/manage.component'; |
||||||
|
import { OrganizationGuardService } from 'src/app/services/organization-guard.service'; |
||||||
|
import { OrganizationTypeGuardService } from 'src/app/services/organization-type-guard.service'; |
||||||
|
|
||||||
|
import { SsoComponent } from './manage/sso.component'; |
||||||
|
|
||||||
|
const routes: Routes = [ |
||||||
|
{ |
||||||
|
path: 'organizations/:organizationId', |
||||||
|
component: OrganizationLayoutComponent, |
||||||
|
canActivate: [AuthGuardService, OrganizationGuardService], |
||||||
|
children: [ |
||||||
|
{ |
||||||
|
path: 'manage', |
||||||
|
component: ManageComponent, |
||||||
|
canActivate: [OrganizationTypeGuardService], |
||||||
|
data: { |
||||||
|
permissions: [ |
||||||
|
Permissions.ManageAssignedCollections, |
||||||
|
Permissions.ManageAllCollections, |
||||||
|
Permissions.AccessEventLogs, |
||||||
|
Permissions.ManageGroups, |
||||||
|
Permissions.ManageUsers, |
||||||
|
Permissions.ManagePolicies, |
||||||
|
Permissions.ManageSso, |
||||||
|
], |
||||||
|
}, |
||||||
|
children: [ |
||||||
|
{ |
||||||
|
path: 'sso', |
||||||
|
component: SsoComponent, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
]; |
||||||
|
|
||||||
|
@NgModule({ |
||||||
|
imports: [RouterModule.forChild(routes)], |
||||||
|
exports: [RouterModule], |
||||||
|
}) |
||||||
|
export class OrganizationsRoutingModule { } |
||||||
@ -0,0 +1,22 @@ |
|||||||
|
import { CommonModule } from '@angular/common'; |
||||||
|
import { NgModule } from '@angular/core'; |
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; |
||||||
|
|
||||||
|
import { OssModule } from 'src/app/oss.module'; |
||||||
|
|
||||||
|
import { SsoComponent } from './manage/sso.component'; |
||||||
|
import { OrganizationsRoutingModule } from './organizations-routing.module'; |
||||||
|
|
||||||
|
@NgModule({ |
||||||
|
imports: [ |
||||||
|
CommonModule, |
||||||
|
FormsModule, |
||||||
|
ReactiveFormsModule, |
||||||
|
OssModule, |
||||||
|
OrganizationsRoutingModule, |
||||||
|
], |
||||||
|
declarations: [ |
||||||
|
SsoComponent, |
||||||
|
], |
||||||
|
}) |
||||||
|
export class OrganizationsModule {} |
||||||
@ -1,7 +1,6 @@ |
|||||||
{ |
{ |
||||||
"urls": { |
"urls": { |
||||||
"icons": "https://icons.qa.bitwarden.pw", |
"icons": "https://icons.qa.bitwarden.pw", |
||||||
"notifications": "https://notifications.qa.bitwarden.pw", |
"notifications": "https://notifications.qa.bitwarden.pw" |
||||||
"enterprise": "https://portal.qa.bitwarden.pw" |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1 +1 @@ |
|||||||
Subproject commit 91c5393ae7a84e9f4d90391d072cae56e7a3ff41 |
Subproject commit bfa9a1e1bc05fe96c121eb4709729e85dfb3b008 |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
import { NgModule } from '@angular/core'; |
||||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||||
|
|
||||||
|
const routes: Routes = [ |
||||||
|
{ path: '**', redirectTo: '' }, |
||||||
|
]; |
||||||
|
|
||||||
|
@NgModule({ |
||||||
|
imports: [RouterModule.forChild(routes)], |
||||||
|
exports: [RouterModule], |
||||||
|
}) |
||||||
|
export class WildcardRoutingModule { } |
||||||
Loading…
Reference in new issue