OnlyOrg Policy (#669)

* added localization strings needed for the OnlyOrg policy

* added deprecation warning to policies page

* allowed OnlyOrg policy configuration

* blocked creating new orgs if already in an org with OnlyOrg enabled

* code review cleanup for onlyOrg

* removed a blank line

* code review cleanup for onlyOrg
This commit is contained in:
Addison Beck 2020-10-16 15:36:06 -04:00 committed by GitHub
parent b7b970e654
commit a51331d6b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 2 deletions

View File

@ -1,3 +1,8 @@
<app-callout [type]="'warning'">
<p>{{'webPoliciesDeprecationWarning' | i18n}}</p>
<button type="button" class="btn btn-outline-secondary"
(click)="goToEnterprisePortal()">{{'businessPortal' | i18n}}</button>
</app-callout>
<div class="page-header d-flex">
<h1>{{'policies' | i18n}}</h1>
</div>

View File

@ -13,6 +13,7 @@ import {
import { PolicyType } from 'jslib/enums/policyType';
import { ApiService } from 'jslib/abstractions/api.service';
import { EnvironmentService } from 'jslib/abstractions';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { UserService } from 'jslib/abstractions/user.service';
@ -34,14 +35,19 @@ export class PoliciesComponent implements OnInit {
organizationId: string;
policies: any[];
// Remove when removing deprecation warning
enterpriseTokenPromise: Promise<any>;
private enterpriseUrl: string;
private modal: ModalComponent = null;
private orgPolicies: PolicyResponse[];
private policiesEnabledMap: Map<PolicyType, boolean> = new Map<PolicyType, boolean>();
constructor(private apiService: ApiService, private route: ActivatedRoute,
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
private platformUtilsService: PlatformUtilsService, private userService: UserService,
private router: Router) {
private router: Router, private environmentService: EnvironmentService) {
this.policies = [
{
name: i18nService.t('twoStepLogin'),
@ -61,6 +67,12 @@ export class PoliciesComponent implements OnInit {
type: PolicyType.PasswordGenerator,
enabled: false,
},
{
name: i18nService.t('onlyOrg'),
description: i18nService.t('onlyOrgDesc'),
type: PolicyType.OnlyOrg,
enabled: false,
},
];
}
@ -74,6 +86,14 @@ export class PoliciesComponent implements OnInit {
}
await this.load();
});
// Remove when removing deprecation warning
this.enterpriseUrl = 'https://portal.bitwarden.com';
if (this.environmentService.enterpriseUrl != null) {
this.enterpriseUrl = this.environmentService.enterpriseUrl;
} else if (this.environmentService.baseUrl != null) {
this.enterpriseUrl = this.environmentService.baseUrl + '/portal';
}
}
async load() {
@ -111,4 +131,22 @@ export class PoliciesComponent implements OnInit {
this.modal = null;
});
}
// 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

@ -17,6 +17,10 @@
title="{{'warning' | i18n}}" icon="fa-warning">
{{'twoStepLoginPolicyWarning' | i18n}}
</app-callout>
<app-callout type="warning" *ngIf="type === policyType.OnlyOrg"
title="{{'warning' | i18n}}" icon="fa-warning">
{{'onlyOrgPolicyWarning' | i18n}}
</app-callout>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="enabled" [(ngModel)]="enabled"

View File

@ -222,6 +222,9 @@
<small class="text-muted font-italic mt-2 d-block" *ngIf="!createOrganization">
{{'paymentCharged' | i18n : (interval | i18n) }}</small>
</div>
<div *ngIf="onlyOrgPolicyBlock" class="mt-4">
<app-callout [type]="'error'">{{'onlyOrgBlockCreateMessage' | i18n}}</app-callout>
</div>
<div class="mt-4">
<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>

View File

@ -17,12 +17,14 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { PolicyService } from 'jslib/abstractions/policy.service';
import { SyncService } from 'jslib/abstractions/sync.service';
import { PaymentComponent } from './payment.component';
import { TaxInfoComponent } from './tax-info.component';
import { PlanType } from 'jslib/enums/planType';
import { PolicyType } from 'jslib/enums/policyType';
import { ProductType } from 'jslib/enums/productType';
import { OrganizationCreateRequest } from 'jslib/models/request/organizationCreateRequest';
@ -56,13 +58,15 @@ export class OrganizationPlansComponent implements OnInit {
businessName: string;
productTypes = ProductType;
formPromise: Promise<any>;
onlyOrgPolicyBlock: boolean = false;
plans: PlanResponse[];
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService,
platformUtilsService: PlatformUtilsService, private cryptoService: CryptoService,
private router: Router, private syncService: SyncService) {
private router: Router, private syncService: SyncService,
private policyService: PolicyService) {
this.selfHosted = platformUtilsService.isSelfHost();
}
@ -193,6 +197,16 @@ export class OrganizationPlansComponent implements OnInit {
}
async submit() {
if (this.onlyOrgPolicyBlock) {
return;
} else {
const policies = await this.policyService.getAll(PolicyType.OnlyOrg);
this.onlyOrgPolicyBlock = policies.some(policy => policy.enabled);
if (this.onlyOrgPolicyBlock) {
return;
}
}
let files: FileList = null;
if (this.createOrganization && this.selfHosted) {
const fileEl = document.getElementById('file') as HTMLInputElement;

View File

@ -3206,5 +3206,20 @@
},
"linkSso": {
"message": "Link SSO"
},
"webPoliciesDeprecationWarning": {
"message": "Policy configuration has been moved, and this page will soon be deprecated. Please click below to use the Business Portal policies page instead."
},
"onlyOrg": {
"message": "Only Organization"
},
"onlyOrgDesc": {
"message": "Restrict users from being able to join any other organizations."
},
"onlyOrgBlockCreateMessage": {
"message": "Your current organization has a policy that does not allow you to join more than one organization. Please contact your organization admins or sign up from a different Bitwarden account."
},
"onlyOrgPolicyWarning": {
"message": "Organization members who are already a member of another organization will be removed from your organization."
}
}