mirror of
https://github.com/bitwarden/web
synced 2025-12-11 13:53:17 +00:00
SSO feature (#604)
* Update feature/sso jslib 261a200 -> 2e823ea (#589) * [SSO] Reset master password (#580) * Initial commit reset master password (sso) * Reverted order of two factor/reset password conditional * Added necessary resetMasterPassword flag for potential entry into RMP flow * Complete Revamp: Reverted Register // Deleted reset-master-password // updated sso/(settings)change password to use use super class // Adjust routing/messages // Created (accounts) change-password * Updated button -> Set Master Password * Refactored change password sub classes to use new submit pattern * Cleaned import statements * Update jslib (7fa5178 -> fe167be) * Update jslib fe167be - >34632e5 * Fixed sso base class import * merge master * Fixed missing semicolon // updated jslib to whats in feature/sso * Fixed two factor formatting * Added new change password component to app module * Updated component selector * updating jslib 34632e5 -> 2e823ea * Fixed lint warning in two-factor component Co-authored-by: Kyle Spearrin <kyle.spearrin@gmail.com> * Update jslib to 101c568 (#594) * Support for dynamic clientid (#595) * support third party sso clients * jslib update * update jslib * Update change-password.component.ts * Update sso.component.ts * Update app.module.ts Co-authored-by: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com>
This commit is contained in:
@@ -13,108 +13,22 @@ import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
import { AuthResult } from 'jslib/models/domain/authResult';
|
||||
import { SsoComponent as BaseSsoComponent } from 'jslib/angular/components/sso.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sso',
|
||||
templateUrl: 'sso.component.html',
|
||||
})
|
||||
export class SsoComponent {
|
||||
identifier: string;
|
||||
loggingIn = false;
|
||||
|
||||
formPromise: Promise<AuthResult>;
|
||||
onSuccessfulLogin: () => Promise<any>;
|
||||
onSuccessfulLoginNavigate: () => Promise<any>;
|
||||
onSuccessfulLoginTwoFactorNavigate: () => Promise<any>;
|
||||
|
||||
protected twoFactorRoute = '2fa';
|
||||
protected successRoute = 'lock';
|
||||
|
||||
private redirectUri = window.location.origin + '/sso-connector.html';
|
||||
|
||||
constructor(private authService: AuthService, private router: Router,
|
||||
private i18nService: I18nService, private route: ActivatedRoute,
|
||||
private storageService: StorageService, private stateService: StateService,
|
||||
private platformUtilsService: PlatformUtilsService, private apiService: ApiService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private passwordGenerationService: PasswordGenerationService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
const queryParamsSub = this.route.queryParams.subscribe(async (qParams) => {
|
||||
if (qParams.code != null && qParams.state != null) {
|
||||
const codeVerifier = await this.storageService.get<string>(ConstantsService.ssoCodeVerifierKey);
|
||||
const state = await this.storageService.get<string>(ConstantsService.ssoStateKey);
|
||||
await this.storageService.remove(ConstantsService.ssoCodeVerifierKey);
|
||||
await this.storageService.remove(ConstantsService.ssoStateKey);
|
||||
if (qParams.code != null && codeVerifier != null && state != null && state === qParams.state) {
|
||||
await this.logIn(qParams.code, codeVerifier);
|
||||
}
|
||||
}
|
||||
if (queryParamsSub != null) {
|
||||
queryParamsSub.unsubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async submit() {
|
||||
const passwordOptions: any = {
|
||||
type: 'password',
|
||||
length: 64,
|
||||
uppercase: true,
|
||||
lowercase: true,
|
||||
numbers: true,
|
||||
special: false,
|
||||
};
|
||||
const state = await this.passwordGenerationService.generatePassword(passwordOptions);
|
||||
const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
|
||||
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, 'sha256');
|
||||
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
|
||||
|
||||
await this.storageService.save(ConstantsService.ssoCodeVerifierKey, codeVerifier);
|
||||
await this.storageService.save(ConstantsService.ssoStateKey, state);
|
||||
|
||||
const authorizeUrl = this.apiService.identityBaseUrl + '/connect/authorize?' +
|
||||
'client_id=web&redirect_uri=' + this.redirectUri + '&' +
|
||||
'response_type=code&scope=api offline_access&' +
|
||||
'state=' + state + '&code_challenge=' + codeChallenge + '&' +
|
||||
'code_challenge_method=S256&response_mode=query&' +
|
||||
'domain_hint=' + this.identifier;
|
||||
this.platformUtilsService.launchUri(authorizeUrl, { sameWindow: true });
|
||||
}
|
||||
|
||||
private async logIn(code: string, codeVerifier: string) {
|
||||
this.loggingIn = true;
|
||||
try {
|
||||
this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri);
|
||||
const response = await this.formPromise;
|
||||
if (response.twoFactor) {
|
||||
this.platformUtilsService.eventTrack('SSO Logged In To Two-step');
|
||||
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
|
||||
this.onSuccessfulLoginTwoFactorNavigate();
|
||||
} else {
|
||||
this.router.navigate([this.twoFactorRoute]);
|
||||
}
|
||||
} else if (response.resetMasterPassword) {
|
||||
// TODO: launch reset master password flow
|
||||
} else {
|
||||
const disableFavicon = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
|
||||
await this.stateService.save(ConstantsService.disableFaviconKey, !!disableFavicon);
|
||||
if (this.onSuccessfulLogin != null) {
|
||||
this.onSuccessfulLogin();
|
||||
}
|
||||
this.platformUtilsService.eventTrack('SSO Logged In');
|
||||
if (this.onSuccessfulLoginNavigate != null) {
|
||||
this.onSuccessfulLoginNavigate();
|
||||
} else {
|
||||
this.router.navigate([this.successRoute]);
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
this.loggingIn = false;
|
||||
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.redirectUri = window.location.origin + '/sso-connector.html';
|
||||
this.clientId = 'web';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user