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

sso login from bwdc desktop app (#58)

This commit is contained in:
Kyle Spearrin
2020-08-05 11:09:06 -04:00
committed by GitHub
parent 2b2d8a9fab
commit 150164534f
9 changed files with 109 additions and 3 deletions

2
jslib

Submodule jslib updated: 14b01f2e5d...4fec611314

View File

@@ -26,6 +26,9 @@
<button type="button" class="btn btn-link" (click)="settings()">
{{'settings' | i18n}}
</button>
<a routerLink="/sso" class="btn btn-outline-secondary btn-block mt-2">
<i class="fa fa-bank" aria-hidden="true"></i> Enterprise Single Sign-On
</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,32 @@
<div class="container-fluid">
<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-body" *ngIf="loggingIn">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
Logging in, please wait...
</div>
<div class="card-body" *ngIf="!loggingIn">
<p>
Quickly log in using your organization's single sign-on portal. Please enter your
organization's identifier to begin.</p>
<div class="form-group">
<label for="identifier">Organization Identifier</label>
<input id="identifier" class="form-control" type="text" name="Identifier"
[(ngModel)]="identifier" required>
</div>
<button type="submit" class="btn btn-primary" [disabled]="form.loading">
<i class="fa fa-spinner fa-fw fa-spin" [hidden]="!form.loading"></i>
<i class="fa fa-sign-in fa-fw" [hidden]="form.loading"></i>
{{'logIn' | i18n}}
</button>
<a routerLink="/" class="btn btn-link">
{{'cancel' | i18n}}
</a>
</div>
</div>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1,41 @@
import { Component } from '@angular/core';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { ApiService } from 'jslib/abstractions/api.service';
import { AuthService } from 'jslib/abstractions/auth.service';
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { SsoComponent as BaseSsoComponent } from 'jslib/angular/components/sso.component';
@Component({
selector: 'app-sso',
templateUrl: 'sso.component.html',
})
export class SsoComponent extends BaseSsoComponent {
constructor(authService: AuthService, router: Router,
i18nService: I18nService, route: ActivatedRoute,
storageService: StorageService, stateService: StateService,
platformUtilsService: PlatformUtilsService, apiService: ApiService,
cryptoFunctionService: CryptoFunctionService,
passwordGenerationService: PasswordGenerationService) {
super(authService, router, i18nService, route, storageService, stateService, platformUtilsService,
apiService, cryptoFunctionService, passwordGenerationService);
this.successRoute = '/tabs/dashboard';
this.redirectUri = 'bwdc://sso-callback';
this.clientId = 'connector';
}
async submit() {
await super.submit();
this.router.navigate(['login']);
}
}

View File

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

View File

@@ -133,6 +133,9 @@ export class AppComponent implements OnInit {
properties: { label: message.label },
});
break;
case 'ssoCallback':
this.router.navigate(['sso'], { queryParams: { code: message.code, state: message.state } });
break;
default:
}
});

View File

@@ -21,6 +21,7 @@ import { ModalComponent } from 'jslib/angular/components/modal.component';
import { EnvironmentComponent } from './accounts/environment.component';
import { LoginComponent } from './accounts/login.component';
import { SsoComponent } from './accounts/sso.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
import { TwoFactorComponent } from './accounts/two-factor.component';
import { DashboardComponent } from './tabs/dashboard.component';
@@ -72,6 +73,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
MoreComponent,
SearchCiphersPipe,
SettingsComponent,
SsoComponent,
StopClickDirective,
StopPropDirective,
TabsComponent,

View File

@@ -62,7 +62,7 @@ const stateService = new StateService();
const broadcasterService = new BroadcasterService();
const messagingService = new ElectronRendererMessagingService(broadcasterService);
const storageService: StorageServiceAbstraction = new ElectronStorageService(remote.app.getPath('userData'));
const platformUtilsService = new ElectronPlatformUtilsService(i18nService, messagingService, true, storageService);
const platformUtilsService = new ElectronPlatformUtilsService(i18nService, messagingService, false, storageService);
const secureStorageService: StorageServiceAbstraction = new ElectronRendererSecureStorageService();
const cryptoFunctionService: CryptoFunctionServiceAbstraction = new NodeCryptoFunctionService();
const cryptoService = new CryptoService(storageService, secureStorageService, cryptoFunctionService);
@@ -140,6 +140,7 @@ export function initFactory(): Function {
{ provide: ConfigurationService, useValue: configurationService },
{ provide: SyncService, useValue: syncService },
{ provide: PasswordGenerationServiceAbstraction, useValue: passwordGenerationService },
{ provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService },
{
provide: APP_INITIALIZER,
useFactory: initFactory,

View File

@@ -52,7 +52,8 @@ export class Main {
this.i18nService = new I18nService('en', './locales/');
this.storageService = new ElectronStorageService(app.getPath('userData'));
this.windowMain = new WindowMain(this.storageService, false, 800, 600);
this.windowMain = new WindowMain(this.storageService, false, 800, 600,
(arg) => this.processDeepLink(arg));
this.menuMain = new MenuMain(this);
this.updaterMain = new UpdaterMain(this.i18nService, this.windowMain, 'directory-connector', () => {
this.messagingService.send('checkingForUpdate');
@@ -78,11 +79,32 @@ export class Main {
this.messagingMain.init();
await this.updaterMain.init();
await this.trayMain.init(this.i18nService.t('bitwardenDirectoryConnector'));
if (!app.isDefaultProtocolClient('bwdc')) {
app.setAsDefaultProtocolClient('bwdc');
}
// Process protocol for macOS
app.on('open-url', (event, url) => {
event.preventDefault();
this.processDeepLink([url]);
});
}, (e: any) => {
// tslint:disable-next-line
console.error(e);
});
}
private processDeepLink(argv: string[]): void {
argv.filter((s) => s.indexOf('bwdc://') === 0).forEach((s) => {
const url = new URL(s);
const code = url.searchParams.get('code');
const receivedState = url.searchParams.get('state');
if (code != null && receivedState != null) {
this.messagingService.send('ssoCallback', { code: code, state: receivedState });
}
});
}
}
const main = new Main();