1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 08:43:33 +00:00

Remove Business Portal and add SSO configuration (#1213)

This commit is contained in:
Oscar Hinton
2021-10-06 20:45:45 +02:00
committed by GitHub
parent 4ff38c7148
commit 3eda0aa2cd
23 changed files with 637 additions and 111 deletions

View File

@@ -10,6 +10,7 @@ import { AppComponent } from './app.component';
import { OssRoutingModule } from './oss-routing.module';
import { OssModule } from './oss.module';
import { ServicesModule } from './services/services.module';
import { WildcardRoutingModule } from './wildcard-routing.module';
@NgModule({
imports: [
@@ -21,6 +22,7 @@ import { ServicesModule } from './services/services.module';
InfiniteScrollModule,
DragDropModule,
OssRoutingModule,
WildcardRoutingModule, // Needs to be last to catch all non-existing routes
],
declarations: [
AppComponent,

View File

@@ -48,15 +48,6 @@
</li>
</ul>
</div>
<div class="ml-auto d-flex align-items-center">
<button class="btn btn-primary" (click)="goToBusinessPortal()" #businessBtn
[appApiAction]="businessTokenPromise" *ngIf="showBusinessPortalButton">
<i class="fa fa-bank fa-fw" [hidden]="businessBtn.loading" aria-hidden="true"></i>
<i class="fa fa-spinner fa-spin fa-fw" [hidden]="!businessBtn.loading" title="{{'loading' | i18n}}"
aria-hidden="true"></i>
{{'businessPortal' | i18n}} →
</button>
</div>
</div>
</div>
<router-outlet></router-outlet>

View File

@@ -9,9 +9,6 @@ import { ActivatedRoute } from '@angular/router';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { ApiService } from 'jslib-common/abstractions/api.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { Organization } from 'jslib-common/models/domain/organization';
@@ -26,16 +23,11 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
organization: Organization;
businessTokenPromise: Promise<any>;
private organizationId: string;
private businessUrl: string;
constructor(private route: ActivatedRoute, private userService: UserService,
private broadcasterService: BroadcasterService, private ngZone: NgZone,
private apiService: ApiService, private platformUtilsService: PlatformUtilsService,
private environmentService: EnvironmentService) { }
private broadcasterService: BroadcasterService, private ngZone: NgZone) { }
ngOnInit() {
this.businessUrl = this.environmentService.getEnterpriseUrl();
document.body.classList.remove('layout_frontend');
this.route.params.subscribe(async params => {
this.organizationId = params.organizationId;
@@ -60,22 +52,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
this.organization = await this.userService.getOrganization(this.organizationId);
}
async goToBusinessPortal() {
if (this.businessTokenPromise != null) {
return;
}
try {
this.businessTokenPromise = this.apiService.getEnterprisePortalSignInToken();
const token = await this.businessTokenPromise;
if (token != null) {
const userId = await this.userService.getUserId();
this.platformUtilsService.launchUri(this.businessUrl + '/login?userId=' + userId +
'&token=' + (window as any).encodeURIComponent(token) + '&organizationId=' + this.organization.id);
}
} catch { }
this.businessTokenPromise = null;
}
get showMenuBar() {
return this.showManageTab || this.showToolsTab || this.organization.isOwner;
}
@@ -93,10 +69,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
return this.organization.canAccessImportExport || this.organization.canAccessReports;
}
get showBusinessPortalButton(): boolean {
return this.organization.useBusinessPortal && this.organization.canAccessBusinessPortal;
}
get toolsRoute(): string {
return this.organization.canAccessImportExport ?
'tools/import' :

View File

@@ -20,6 +20,10 @@
*ngIf="organization.canManagePolicies && accessPolicies">
{{'policies' | i18n}}
</a>
<a routerLink="sso" class="list-group-item" routerLinkActive="active"
*ngIf="organization.canManageSso && accessSso">
{{'singleSignOn' | i18n}}
</a>
<a routerLink="events" class="list-group-item" routerLinkActive="active"
*ngIf="organization.canAccessEventLogs && accessEvents">
{{'eventLogs' | i18n}}

View File

@@ -14,16 +14,18 @@ import { Organization } from 'jslib-common/models/domain/organization';
})
export class ManageComponent implements OnInit {
organization: Organization;
accessPolicies = false;
accessGroups = false;
accessEvents = false;
accessPolicies: boolean = false;
accessGroups: boolean = false;
accessEvents: boolean = false;
accessSso: boolean = false;
constructor(private route: ActivatedRoute, private userService: UserService) { }
constructor(private route: ActivatedRoute, private userService: UserService) {}
ngOnInit() {
this.route.parent.params.subscribe(async params => {
this.organization = await this.userService.getOrganization(params.organizationId);
this.accessPolicies = this.organization.usePolicies;
this.accessSso = this.organization.useSso;
this.accessEvents = this.organization.useEvents;
this.accessGroups = this.organization.useGroups;
});

View File

@@ -12,9 +12,6 @@ import {
import { PolicyType } from 'jslib-common/enums/policyType';
import { ApiService } from 'jslib-common/abstractions/api.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { ModalService } from 'jslib-angular/services/modal.service';
@@ -25,7 +22,7 @@ import { Organization } from 'jslib-common/models/domain/organization';
import { PolicyEditComponent } from './policy-edit.component';
import { PolicyListService } from 'src/app/services/policy-list.service';
import { PolicyListService } from '../../services/policy-list.service';
import { BasePolicy } from '../policies/base-policy.component';
@Component({
@@ -40,19 +37,12 @@ export class PoliciesComponent implements OnInit {
policies: BasePolicy[];
organization: Organization;
// Remove when removing deprecation warning
enterpriseTokenPromise: Promise<any>;
private enterpriseUrl: string;
private orgPolicies: PolicyResponse[];
private policiesEnabledMap: Map<PolicyType, boolean> = new Map<PolicyType, boolean>();
constructor(private apiService: ApiService, private route: ActivatedRoute,
private i18nService: I18nService, private modalService: ModalService,
private platformUtilsService: PlatformUtilsService, private userService: UserService,
private policyListService: PolicyListService, private router: Router,
private environmentService: EnvironmentService) { }
private modalService: ModalService, private userService: UserService,
private policyListService: PolicyListService, private router: Router) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async params => {
@@ -89,9 +79,6 @@ export class PoliciesComponent implements OnInit {
}
});
});
// Remove when removing deprecation warning
this.enterpriseUrl = this.environmentService.getEnterpriseUrl();
}
async load() {
@@ -115,21 +102,4 @@ export class PoliciesComponent implements OnInit {
});
});
}
// Remove when removing deprecation warning
async goToEnterprisePortal() {
if (this.enterpriseTokenPromise != null) {
return;
}
try {
this.enterpriseTokenPromise = this.apiService.getEnterprisePortalSignInToken();
const token = await this.enterpriseTokenPromise;
if (token != null) {
const userId = await this.userService.getUserId();
this.platformUtilsService.launchUri(this.enterpriseUrl + '/login?userId=' + userId +
'&token=' + (window as any).encodeURIComponent(token) + '&organizationId=' + this.organizationId);
}
} catch { }
this.enterpriseTokenPromise = null;
}
}

View File

@@ -102,15 +102,6 @@
<div class="mb-3">
<label class="font-weight-bold mb-0">Admin Permissions</label>
<hr class="my-0 mr-2" />
<div class="form-group mb-0">
<div class="form-check mt-1 form-check-block">
<input class="form-check-input" type="checkbox" name="accessBusinessPortal"
id="accessBusinessPortal" [(ngModel)]="permissions.accessBusinessPortal">
<label class="form-check-label font-weight-normal" for="accessBusinessPortal">
{{'accessBusinessPortal' | i18n}}
</label>
</div>
</div>
<div class="form-group mb-0">
<div class="form-check mt-1 form-check-block">
<input class="form-check-input" type="checkbox" name="accessEventLogs"

View File

@@ -216,7 +216,7 @@ export class OrganizationSubscriptionComponent implements OnInit {
}
get subscriptionDesc() {
if (this.sub.maxAutoscaleSeats == this.sub.seats && this.sub.seats != null) {
if (this.sub.maxAutoscaleSeats === this.sub.seats && this.sub.seats != null) {
return this.i18nService.t('subscriptionMaxReached', this.sub.seats.toString());
} else if (this.sub.maxAutoscaleSeats == null) {
return this.i18nService.t('subscriptionUserSeatsUnlimitedAutoscale');

View File

@@ -443,7 +443,6 @@ const routes: Routes = [
},
],
},
{ path: '**', redirectTo: '' },
];
@NgModule({

View File

@@ -18,7 +18,6 @@ export class OrganizationTypeGuardService implements CanActivate {
const permissions = route.data == null ? null : route.data.permissions as Permissions[];
if (
(permissions.indexOf(Permissions.AccessBusinessPortal) !== -1 && org.canAccessBusinessPortal) ||
(permissions.indexOf(Permissions.AccessEventLogs) !== -1 && org.canAccessEventLogs) ||
(permissions.indexOf(Permissions.AccessImportExport) !== -1 && org.canAccessImportExport) ||
(permissions.indexOf(Permissions.AccessReports) !== -1 && org.canAccessReports) ||
@@ -31,7 +30,8 @@ export class OrganizationTypeGuardService implements CanActivate {
(permissions.indexOf(Permissions.ManageOrganization) !== -1 && org.isOwner) ||
(permissions.indexOf(Permissions.ManagePolicies) !== -1 && org.canManagePolicies) ||
(permissions.indexOf(Permissions.ManageUsers) !== -1 && org.canManageUsers) ||
(permissions.indexOf(Permissions.ManageUsersPassword) !== -1 && org.canManageUsersPassword)
(permissions.indexOf(Permissions.ManageUsersPassword) !== -1 && org.canManageUsersPassword) ||
(permissions.indexOf(Permissions.ManageSso) !== -1 && org.canManageSso)
) {
return true;
}

View File

@@ -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 { }

View File

@@ -2154,6 +2154,9 @@
"policies": {
"message": "Policies"
},
"singleSignOn": {
"message": "Single Sign-On"
},
"editPolicy": {
"message": "Edit Policy"
},
@@ -3396,10 +3399,6 @@
"ssoHandOff": {
"message": "You may now close this tab and continue in the extension."
},
"businessPortal": {
"message": "Business Portal",
"description": "The web portal used by business organizations for configuring certain features."
},
"includeAllTeamsFeatures": {
"message": "All Teams features, plus:"
},
@@ -3809,9 +3808,6 @@
"permissions": {
"message": "Permissions"
},
"accessBusinessPortal": {
"message": "Access Business Portal"
},
"accessEventLogs": {
"message": "Access Event Logs"
},
@@ -4329,5 +4325,122 @@
},
"personalVaultExportPolicyInEffect": {
"message": "One or more organization policies prevents you from exporting your personal vault."
},
"selectType": {
"message": "Select SSO Type"
},
"type": {
"message": "Type"
},
"openIdConnectConfig": {
"message": "OpenID Connect Configuration"
},
"samlSpConfig": {
"message": "SAML Service Provider Configuration"
},
"samlIdpConfig": {
"message": "SAML Identity Provider Configuration"
},
"callbackPath": {
"message": "Callback Path"
},
"signedOutCallbackPath": {
"message": "Signed Out Callback Path"
},
"authority": {
"message": "Authority"
},
"clientId": {
"message": "Client ID"
},
"clientSecret": {
"message": "Client Secret"
},
"metadataAddress": {
"message": "Metadata Address"
},
"oidcRedirectBehavior": {
"message": "OIDC Redirect Behavior"
},
"getClaimsFromUserInfoEndpoint": {
"message": "Get Claims From User Info Endpoint"
},
"additionalScopes": {
"message": "Additional/Custom Scopes (comma delimited)"
},
"additionalUserIdClaimTypes": {
"message": "Additional/Custom User ID Claim Types (comma delimited)"
},
"additionalEmailClaimTypes": {
"message": "Additional/Custom Email Claim Types (comma delimited)"
},
"additionalNameClaimTypes": {
"message": "Additional/Custom Name Claim Types (comma delimited)"
},
"acrValues": {
"message": "Requested Authentication Context Class Reference values (acr_values)"
},
"expectedReturnAcrValue": {
"message": "Expected \"acr\" Claim Value In Response (acr validation)"
},
"spEntityId": {
"message": "SP Entity ID"
},
"spMetadataUrl": {
"message": "SAML 2.0 Metadata URL"
},
"spAcsUrl": {
"message": "Assertion Consumer Service (ACS) URL"
},
"spNameIdFormat": {
"message": "Name ID Format"
},
"spOutboundSigningAlgorithm": {
"message": "Outbound Signing Algorithm"
},
"spSigningBehavior": {
"message": "Signing Behavior"
},
"spMinIncomingSigningAlgorithm": {
"message": "Minimum Incoming Signing Algorithm"
},
"spWantAssertionsSigned": {
"message": "Want Assertions Signed"
},
"spValidateCertificates": {
"message": "Validate Certificates"
},
"idpEntityId": {
"message": "Entity ID"
},
"idpBindingType": {
"message": "Binding Type"
},
"idpSingleSignOnServiceUrl": {
"message": "Single Sign On Service URL"
},
"idpSingleLogoutServiceUrl": {
"message": "Single Log Out Service URL"
},
"idpArtifactResolutionServiceUrl": {
"message": "Artifact Resolution Service URL"
},
"idpX509PublicCert": {
"message": "X509 Public Certificate"
},
"idpOutboundSigningAlgorithm": {
"message": "Outbound Signing Algorithm"
},
"idpAllowUnsolicitedAuthnResponse": {
"message": "Allow Unsolicited Authentication Response"
},
"idpDisableOutboundLogoutRequests": {
"message": "Disable Outbound Logout Requests"
},
"idpWantAuthnRequestsSigned": {
"message": "Want Authentication Requests Signed"
},
"ssoSettingsSaved": {
"message": "Single Sign-On configuration was saved."
}
}