Sso link existing user (#616)
* created and applied link-sso component * implemented linking existing user to sso * removed an unused import * created and applied link-sso component * implemented linking existing user to sso * removed an unused import * merge * added a token to the sso linking flow * [jslib] Update (5d874d0
->6ab444a
) (#618) * Update jslib (5d874d0
->6ab444a
) * Update dependency flows * created and applied link-sso component * implemented linking existing user to sso * removed an unused import * merge * added a token to the sso linking flow * implemented linking existing user to sso * removed an unused import * account for some variable shakeup in jslib for link sso * updated jslib * updated jslib * still trying to fix jslib * finally, really, truly updated jslib Co-authored-by: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com>
This commit is contained in:
parent
bc71ffa6f2
commit
e17a49acd5
2
jslib
2
jslib
|
@ -1 +1 @@
|
|||
Subproject commit e55528e61737635e7f8970b913bcc3f10bede85d
|
||||
Subproject commit e07526a1b6cae520561e452a6695a1508d785585
|
|
@ -109,6 +109,7 @@ import { CreateOrganizationComponent } from './settings/create-organization.comp
|
|||
import { DeauthorizeSessionsComponent } from './settings/deauthorize-sessions.component';
|
||||
import { DeleteAccountComponent } from './settings/delete-account.component';
|
||||
import { DomainRulesComponent } from './settings/domain-rules.component';
|
||||
import { LinkSsoComponent } from './settings/link-sso.component';
|
||||
import { OptionsComponent } from './settings/options.component';
|
||||
import { OrganizationPlansComponent } from './settings/organization-plans.component';
|
||||
import { OrganizationsComponent } from './settings/organizations.component';
|
||||
|
@ -295,6 +296,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||
ImportComponent,
|
||||
InactiveTwoFactorReportComponent,
|
||||
InputVerbatimDirective,
|
||||
LinkSsoComponent,
|
||||
LockComponent,
|
||||
LoginComponent,
|
||||
ModalComponent,
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<a class="dropdown-item" href="#" appStopClick (click)="submit(returnUri, true)">
|
||||
<i class="fa fa-fw fa-link" aria-hidden="true"></i>
|
||||
Link SSO
|
||||
</a>
|
|
@ -0,0 +1,48 @@
|
|||
import {
|
||||
AfterContentInit,
|
||||
Component,
|
||||
Input,
|
||||
} 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 } from 'jslib/angular/components/sso.component';
|
||||
|
||||
import { Organization } from 'jslib/models/domain/organization';
|
||||
|
||||
@Component({
|
||||
selector: 'app-link-sso',
|
||||
templateUrl: 'link-sso.component.html',
|
||||
})
|
||||
export class LinkSsoComponent extends SsoComponent implements AfterContentInit {
|
||||
@Input() organization: Organization;
|
||||
returnUri: string = '/settings/organizations'
|
||||
|
||||
constructor(platformUtilsService: PlatformUtilsService, i18nService: I18nService,
|
||||
apiService: ApiService, authService: AuthService,
|
||||
router: Router, route: ActivatedRoute,
|
||||
cryptoFunctionService: CryptoFunctionService, passwordGenerationService: PasswordGenerationService,
|
||||
storageService: StorageService, stateService: StateService) {
|
||||
super(authService, router,
|
||||
i18nService, route,
|
||||
storageService, stateService,
|
||||
platformUtilsService, apiService,
|
||||
cryptoFunctionService, passwordGenerationService);
|
||||
|
||||
this.returnUri = '/settings/organizations';
|
||||
this.redirectUri = window.location.origin + '/sso-connector.html';
|
||||
this.clientId = 'web';
|
||||
}
|
||||
|
||||
async ngAfterContentInit() {
|
||||
this.identifier = this.organization.identifier;
|
||||
}
|
||||
}
|
|
@ -74,6 +74,17 @@
|
|||
<i class="fa fa-cog fa-lg" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<ng-container *ngIf="o.useSso && o.identifier">
|
||||
<a *ngIf="o.ssoBound; else linkSso" class="dropdown-item" href="#" appStopClick
|
||||
(click)="unlinkSso(o)">
|
||||
<i class="fa fa-fw fa-chain-broken" aria-hidden="true"></i>
|
||||
Unlink SSO
|
||||
</a>
|
||||
<ng-template #linkSso>
|
||||
<app-link-sso [organization]="o">
|
||||
</app-link-sso>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="leave(o)">
|
||||
<i class="fa fa-fw fa-sign-out" aria-hidden="true"></i>
|
||||
{{'leave' | i18n}}
|
||||
|
|
|
@ -35,6 +35,7 @@ export class OrganizationsComponent implements OnInit {
|
|||
|
||||
async ngOnInit() {
|
||||
if (!this.vault) {
|
||||
await this.syncService.fullSync(true);
|
||||
await this.load();
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +47,25 @@ export class OrganizationsComponent implements OnInit {
|
|||
this.loaded = true;
|
||||
}
|
||||
|
||||
async unlinkSso(org: Organization) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
'Are you sure you want to unlink SSO for this organization?', org.name,
|
||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.actionPromise = this.apiService.deleteSsoUser(org.id).then(() => {
|
||||
return this.syncService.fullSync(true);
|
||||
});
|
||||
await this.actionPromise;
|
||||
this.analytics.eventTrack.next({ action: 'Unlinked SSO' });
|
||||
this.toasterService.popAsync('success', null, 'Unlinked SSO');
|
||||
await this.load();
|
||||
} catch { }
|
||||
}
|
||||
|
||||
async leave(org: Organization) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('leaveOrganizationConfirmation'), org.name,
|
||||
|
|
|
@ -9,6 +9,13 @@ document.addEventListener('DOMContentLoaded', (event) => {
|
|||
initiateBrowserSso(code, state);
|
||||
} else {
|
||||
window.location.href = window.location.origin + '/#/sso?code=' + code + '&state=' + state;
|
||||
// Match any characters between "_returnUri='" and the next "'"
|
||||
const returnUri = extractFromRegex(state, '(?<=_returnUri=\')(.*)(?=\')');
|
||||
if (returnUri) {
|
||||
window.location.href = window.location.origin + `/#${returnUri}`;
|
||||
} else {
|
||||
window.location.href = window.location.origin + '/#/sso?code=' + code + '&state=' + state;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -31,3 +38,14 @@ function getQsParam(name: string) {
|
|||
function initiateBrowserSso(code: string, state: string) {
|
||||
window.postMessage({ command: 'authResult', code: code, state: state }, '*');
|
||||
}
|
||||
|
||||
function extractFromRegex(s: string, regexString: string) {
|
||||
const regex = new RegExp(regexString);
|
||||
const results = regex.exec(s);
|
||||
|
||||
if (!results) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return results[0];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue