1
0
mirror of https://github.com/bitwarden/directory-connector synced 2025-12-05 23:53:21 +00:00

[SSO] Adjust set password flow (#64)

* Removed set-password // Adjusted sso UI // Added string

* Removed test logic

* Update jslib (6ab444a -> 700e945)

* Passing null for expectes sync service

* Removing unnecessary async

* Deleted set-password files. RIP

* Removed non-existent import (fixes build)
This commit is contained in:
Vincent Salucci
2020-08-28 09:54:45 -05:00
committed by GitHub
parent 094ec23f04
commit 752e26db6d
8 changed files with 50 additions and 164 deletions

2
jslib

Submodule jslib updated: 6ab444a986...700e945008

View File

@@ -1,96 +0,0 @@
<div class="container-fluid">
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate autocomplete="off">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card d-block">
<h5 class="card-header">{{'setMasterPassword' | i18n}}</h5>
<div class="card-body">
<app-callout type="info">{{'ssoCompleteRegistration' | i18n}}</app-callout>
<div class="form-group">
<app-callout type="info" *ngIf="enforcedPolicyOptions">
{{'masterPasswordPolicyInEffect' | i18n}}
<ul class="mb-0">
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
{{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
</li>
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
{{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
</li>
<li *ngIf="enforcedPolicyOptions?.requireUpper">
{{'policyInEffectUppercase' | i18n}}</li>
<li *ngIf="enforcedPolicyOptions?.requireLower">
{{'policyInEffectLowercase' | i18n}}</li>
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
{{'policyInEffectNumbers' | i18n}}</li>
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
{{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}</li>
</ul>
</app-callout>
<label for="masterPassword">{{'masterPass' | i18n}}
<strong class="form-text d-inline-block ml-2 text-{{masterPasswordScoreColor}}"
*ngIf="masterPasswordScoreText">
{{masterPasswordScoreText}}
</strong>
</label>
<div class="d-flex">
<div class="w-100">
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}"
name="MasterPasswordHash" class="text-monospace form-control mb-1"
[(ngModel)]="masterPassword" (input)="updatePasswordStrength()" required
appInputVerbatim>
<div class="progress">
<div class="progress-bar bg-{{masterPasswordScoreColor}}" role="progressbar"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
[ngStyle]="{width: (masterPasswordScoreWidth + '%')}"
attr.aria-valuenow="{{masterPasswordScoreWidth}}">
</div>
</div>
</div>
<div>
<button type="button" class="ml-1 btn btn-link"
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
<div class="progress-bar invisible"></div>
</div>
</div>
<small class="form-text text-muted">{{'masterPassDesc' | i18n}}</small>
</div>
<div class="form-group">
<label for="masterPasswordRetype">{{'reTypeMasterPass' | i18n}}</label>
<div class="d-flex">
<input id="masterPasswordRetype" type="{{showPassword ? 'text' : 'password'}}"
name="MasterPasswordRetype" class="text-monospace form-control"
[(ngModel)]="masterPasswordRetype" required appInputVerbatim>
<button type="button" class="ml-1 btn btn-link"
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword(true)">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
</div>
</div>
<div class="form-group">
<label for="hint">{{'masterPassHint' | i18n}}</label>
<input id="hint" class="form-control" type="text" name="Hint" [(ngModel)]="hint">
<small class="form-text text-muted">{{'masterPassHintDesc' | i18n}}</small>
</div>
<hr>
<div class="d-flex">
<button type="submit" class="btn btn-primary btn-block btn-submit"
[disabled]="form.loading">
<i [hidden]="!form.loading" class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"
aria-hidden="true"></i>
<span [hidden]="form.loading">{{'submit' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary btn-block ml-2 mt-0"
(click)="logOut()">
{{'logOut' | i18n}}
</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>

View File

@@ -1,61 +0,0 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { ApiService } from 'jslib/abstractions/api.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { PolicyService } from 'jslib/abstractions/policy.service';
import { UserService } from 'jslib/abstractions/user.service';
import {
SetPasswordComponent as BaseSetPasswordComponent,
} from 'jslib/angular/components/set-password.component';
@Component({
selector: 'app-set-password',
templateUrl: 'set-password.component.html',
})
export class SetPasswordComponent extends BaseSetPasswordComponent {
constructor(apiService: ApiService, i18nService: I18nService,
cryptoService: CryptoService, messagingService: MessagingService,
userService: UserService, passwordGenerationService: PasswordGenerationService,
platformUtilsService: PlatformUtilsService, policyService: PolicyService, router: Router) {
super(i18nService, cryptoService, messagingService, userService, passwordGenerationService,
platformUtilsService, policyService, router, apiService);
super.successRoute = '/tabs/dashboard';
}
get masterPasswordScoreWidth() {
return this.masterPasswordScore == null ? 0 : (this.masterPasswordScore + 1) * 20;
}
get masterPasswordScoreColor() {
switch (this.masterPasswordScore) {
case 4:
return 'success';
case 3:
return 'primary';
case 2:
return 'warning';
default:
return 'danger';
}
}
get masterPasswordScoreText() {
switch (this.masterPasswordScore) {
case 4:
return this.i18nService.t('strong');
case 3:
return this.i18nService.t('good');
case 2:
return this.i18nService.t('weak');
default:
return this.masterPasswordScore != null ? this.i18nService.t('weak') : null;
}
}
}

View File

@@ -2,12 +2,28 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card">
<div class="card" *ngIf="!showMasterPassRedirect">
<div class="card-body">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
{{'loading' | i18n}}
</div>
</div>
<div class="card" *ngIf="showMasterPassRedirect">
<h5 class="card-header">{{'setMasterPassword' | i18n}}</h5>
<div class="card-body">
<p class="text-center">{{'setMasterPasswordRedirect' | i18n}}</p>
<hr>
<div class="d-flex">
<button type="button" class="btn btn-primary btn-block btn-submit"
(click)="launchWebVault()">
{{'launchWebVault' | i18n}}
</button>
<button type="button" class="btn btn-secondary btn-block ml-2 mt-0" (click)="logOut()">
{{'logOut' | i18n}}
</button>
</div>
</div>
</div>
</div>
</div>
</form>

View File

@@ -8,7 +8,9 @@ import {
import { ApiService } from 'jslib/abstractions/api.service';
import { AuthService } from 'jslib/abstractions/auth.service';
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
import { EnvironmentService } from 'jslib/abstractions/environment.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service';
@@ -21,16 +23,39 @@ import { SsoComponent as BaseSsoComponent } from 'jslib/angular/components/sso.c
templateUrl: 'sso.component.html',
})
export class SsoComponent extends BaseSsoComponent {
showMasterPassRedirect: boolean = false;
constructor(authService: AuthService, router: Router,
i18nService: I18nService, route: ActivatedRoute,
storageService: StorageService, stateService: StateService,
platformUtilsService: PlatformUtilsService, apiService: ApiService,
cryptoFunctionService: CryptoFunctionService,
passwordGenerationService: PasswordGenerationService) {
passwordGenerationService: PasswordGenerationService, private messagingService: MessagingService,
private environmentService: EnvironmentService) {
super(authService, router, i18nService, route, storageService, stateService, platformUtilsService,
apiService, cryptoFunctionService, passwordGenerationService);
this.successRoute = '/tabs/dashboard';
this.redirectUri = 'bwdc://sso-callback';
this.clientId = 'connector';
this.onSuccessfulLoginChangePasswordNavigate = this.redirectSetMasterPass;
}
async redirectSetMasterPass() {
this.showMasterPassRedirect = true;
}
launchWebVault() {
const webUrl = this.environmentService.webVaultUrl == null ? 'https://vault.bitwarden.com' :
this.environmentService.webVaultUrl;
this.platformUtilsService.launchUri(webUrl);
}
async logOut() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('logOutConfirmation'),
this.i18nService.t('logOut'), this.i18nService.t('logOut'), this.i18nService.t('cancel'));
if (confirmed) {
this.messagingService.send('logout');
}
}
}

View File

@@ -8,7 +8,6 @@ import { AuthGuardService } from './services/auth-guard.service';
import { LaunchGuardService } from './services/launch-guard.service';
import { LoginComponent } from './accounts/login.component';
import { SetPasswordComponent } from './accounts/set-password.component';
import { SsoComponent } from './accounts/sso.component';
import { TwoFactorComponent } from './accounts/two-factor.component';
import { DashboardComponent } from './tabs/dashboard.component';
@@ -25,7 +24,6 @@ const routes: Routes = [
},
{ path: '2fa', component: TwoFactorComponent },
{ path: 'sso', component: SsoComponent },
{ path: 'set-password', component: SetPasswordComponent },
{
path: 'tabs',
component: TabsComponent,

View File

@@ -26,7 +26,6 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone
import { TwoFactorComponent } from './accounts/two-factor.component';
import { DashboardComponent } from './tabs/dashboard.component';
import { MoreComponent } from './tabs/more.component';
import { SetPasswordComponent } from './accounts/set-password.component';
import { SettingsComponent } from './tabs/settings.component';
import { TabsComponent } from './tabs/tabs.component';
@@ -73,7 +72,6 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
ModalComponent,
MoreComponent,
SearchCiphersPipe,
SetPasswordComponent,
SettingsComponent,
SsoComponent,
StopClickDirective,

View File

@@ -716,5 +716,11 @@
},
"loading": {
"message": "Loading"
},
"setMasterPasswordRedirect": {
"message": "In order to log in with SSO from the Directory Connector, you must first log in through the web vault to set your master password."
},
"launchWebVault": {
"message": "Launch Web Vault"
}
}