[Require SSO] Enterprise policy adjustment (#676)

* Commits for policies/edit/strings

* more initial commits of policy/edit/strings

* More changes for require sso

* Updated strings to match policy string patterns

* Updated false enable on error

* Removed sso prevalidate prereq // adjusted callout

* Updated policy array creation and added display value
This commit is contained in:
Vincent Salucci 2020-10-26 11:56:02 -05:00 committed by GitHub
parent a51331d6b2
commit beebe7c98b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 121 additions and 70 deletions

View File

@ -13,7 +13,7 @@
<table class="table table-hover table-list" *ngIf="!loading"> <table class="table table-hover table-list" *ngIf="!loading">
<tbody> <tbody>
<tr *ngFor="let p of policies"> <tr *ngFor="let p of policies">
<td> <td *ngIf="p.display">
<a href="#" appStopClick (click)="edit(p)">{{p.name}}</a> <a href="#" appStopClick (click)="edit(p)">{{p.name}}</a>
<span class="badge badge-success" *ngIf="p.enabled">{{'enabled' | i18n}}</span> <span class="badge badge-success" *ngIf="p.enabled">{{'enabled' | i18n}}</span>
<small class="text-muted d-block">{{p.description}}</small> <small class="text-muted d-block">{{p.description}}</small>

View File

@ -47,34 +47,7 @@ export class PoliciesComponent implements OnInit {
constructor(private apiService: ApiService, private route: ActivatedRoute, constructor(private apiService: ApiService, private route: ActivatedRoute,
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver, private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
private platformUtilsService: PlatformUtilsService, private userService: UserService, private platformUtilsService: PlatformUtilsService, private userService: UserService,
private router: Router, private environmentService: EnvironmentService) { private router: Router, private environmentService: EnvironmentService) { }
this.policies = [
{
name: i18nService.t('twoStepLogin'),
description: i18nService.t('twoStepLoginPolicyDesc'),
type: PolicyType.TwoFactorAuthentication,
enabled: false,
},
{
name: i18nService.t('masterPass'),
description: i18nService.t('masterPassPolicyDesc'),
type: PolicyType.MasterPassword,
enabled: false,
},
{
name: i18nService.t('passwordGenerator'),
description: i18nService.t('passwordGeneratorPolicyDesc'),
type: PolicyType.PasswordGenerator,
enabled: false,
},
{
name: i18nService.t('onlyOrg'),
description: i18nService.t('onlyOrgDesc'),
type: PolicyType.OnlyOrg,
enabled: false,
},
];
}
async ngOnInit() { async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => { this.route.parent.parent.params.subscribe(async (params) => {
@ -84,6 +57,43 @@ export class PoliciesComponent implements OnInit {
this.router.navigate(['/organizations', this.organizationId]); this.router.navigate(['/organizations', this.organizationId]);
return; return;
} }
this.policies = [
{
name: this.i18nService.t('twoStepLogin'),
description: this.i18nService.t('twoStepLoginPolicyDesc'),
type: PolicyType.TwoFactorAuthentication,
enabled: false,
display: true,
},
{
name: this.i18nService.t('masterPass'),
description: this.i18nService.t('masterPassPolicyDesc'),
type: PolicyType.MasterPassword,
enabled: false,
display: true,
},
{
name: this.i18nService.t('passwordGenerator'),
description: this.i18nService.t('passwordGeneratorPolicyDesc'),
type: PolicyType.PasswordGenerator,
enabled: false,
display: true,
},
{
name: this.i18nService.t('onlyOrg'),
description: this.i18nService.t('onlyOrgDesc'),
type: PolicyType.OnlyOrg,
enabled: false,
display: true,
},
{
name: this.i18nService.t('requireSso'),
description: this.i18nService.t('requireSsoPolicyDesc'),
type: PolicyType.RequireSso,
enabled: false,
display: organization.useSso,
},
];
await this.load(); await this.load();
}); });
@ -122,6 +132,7 @@ export class PoliciesComponent implements OnInit {
childComponent.description = p.description; childComponent.description = p.description;
childComponent.type = p.type; childComponent.type = p.type;
childComponent.organizationId = this.organizationId; childComponent.organizationId = this.organizationId;
childComponent.policiesEnabledMap = this.policiesEnabledMap;
childComponent.onSavedPolicy.subscribe(() => { childComponent.onSavedPolicy.subscribe(() => {
this.modal.close(); this.modal.close();
this.load(); this.load();

View File

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

View File

@ -27,6 +27,7 @@ export class PolicyEditComponent implements OnInit {
@Input() description: string; @Input() description: string;
@Input() type: PolicyType; @Input() type: PolicyType;
@Input() organizationId: string; @Input() organizationId: string;
@Input() policiesEnabledMap: Map<PolicyType, boolean> = new Map<PolicyType, boolean>();
@Output() onSavedPolicy = new EventEmitter(); @Output() onSavedPolicy = new EventEmitter();
policyType = PolicyType; policyType = PolicyType;
@ -127,45 +128,66 @@ export class PolicyEditComponent implements OnInit {
} }
async submit() { async submit() {
const request = new PolicyRequest(); if (this.preValidate()) {
request.enabled = this.enabled; const request = new PolicyRequest();
request.type = this.type; request.enabled = this.enabled;
request.data = null; request.type = this.type;
switch (this.type) { request.data = null;
case PolicyType.PasswordGenerator: switch (this.type) {
request.data = { case PolicyType.PasswordGenerator:
defaultType: this.passGenDefaultType, request.data = {
minLength: this.passGenMinLength || null, defaultType: this.passGenDefaultType,
useUpper: this.passGenUseUpper, minLength: this.passGenMinLength || null,
useLower: this.passGenUseLower, useUpper: this.passGenUseUpper,
useNumbers: this.passGenUseNumbers, useLower: this.passGenUseLower,
useSpecial: this.passGenUseSpecial, useNumbers: this.passGenUseNumbers,
minNumbers: this.passGenMinNumbers || null, useSpecial: this.passGenUseSpecial,
minSpecial: this.passGenMinSpecial || null, minNumbers: this.passGenMinNumbers || null,
minNumberWords: this.passGenMinNumberWords || null, minSpecial: this.passGenMinSpecial || null,
capitalize: this.passGenCapitalize, minNumberWords: this.passGenMinNumberWords || null,
includeNumber: this.passGenIncludeNumber, capitalize: this.passGenCapitalize,
}; includeNumber: this.passGenIncludeNumber,
break; };
case PolicyType.MasterPassword: break;
request.data = { case PolicyType.MasterPassword:
minComplexity: this.masterPassMinComplexity || null, request.data = {
minLength: this.masterPassMinLength || null, minComplexity: this.masterPassMinComplexity || null,
requireUpper: this.masterPassRequireUpper, minLength: this.masterPassMinLength || null,
requireLower: this.masterPassRequireLower, requireUpper: this.masterPassRequireUpper,
requireNumbers: this.masterPassRequireNumbers, requireLower: this.masterPassRequireLower,
requireSpecial: this.masterPassRequireSpecial, requireNumbers: this.masterPassRequireNumbers,
}; requireSpecial: this.masterPassRequireSpecial,
break; };
default: break;
break; default:
break;
}
try {
this.formPromise = this.apiService.putPolicy(this.organizationId, this.type, request);
await this.formPromise;
this.analytics.eventTrack.next({ action: 'Edited Policy' });
this.toasterService.popAsync('success', null, this.i18nService.t('editedPolicyId', this.name));
this.onSavedPolicy.emit();
} catch { }
}
}
private preValidate(): boolean {
switch (this.type) {
case PolicyType.RequireSso:
if (!this.enabled) { // Don't need prevalidation checks if submitting to disable
return true;
}
// Have OnlyOrg policy enabled?
if (!(this.policiesEnabledMap.has(PolicyType.OnlyOrg)
&& this.policiesEnabledMap.get(PolicyType.OnlyOrg))) {
this.toasterService.popAsync('error', null, this.i18nService.t('requireSsoPolicyReqError'));
return false;
}
return true;
default:
return true;
} }
try {
this.formPromise = this.apiService.putPolicy(this.organizationId, this.type, request);
await this.formPromise;
this.analytics.eventTrack.next({ action: 'Edited Policy' });
this.toasterService.popAsync('success', null, this.i18nService.t('editedPolicyId', this.name));
this.onSavedPolicy.emit();
} catch { }
} }
} }

View File

@ -3221,5 +3221,20 @@
}, },
"onlyOrgPolicyWarning": { "onlyOrgPolicyWarning": {
"message": "Organization members who are already a member of another organization will be removed from your organization." "message": "Organization members who are already a member of another organization will be removed from your organization."
},
"requireSso": {
"message": "Single Sign-On Authentication"
},
"requireSsoPolicyDesc": {
"message": "Require users to log in with the Enterprise Single Sign-On method."
},
"prerequisite": {
"message": "Prerequisite"
},
"requireSsoPolicyReq": {
"message": "The Single Organization enterprise policy must be enabled before activating this policy."
},
"requireSsoPolicyReqError": {
"message": "Single Organization policy not enabled."
} }
} }