feat(login): add login authentication and authorization (#122)

Add login basic authentication, oauth2 authentication, two factor
authentication and authorization and allow to reset password on expiry.

Fixes #117, #118, #119, #120
This commit is contained in:
Abhay Chawla
2018-07-14 20:09:27 +05:30
committed by GitHub
parent 91e9744bb8
commit d9c35b8759
33 changed files with 953 additions and 271 deletions
@@ -0,0 +1,37 @@
<p><strong>Two Factor Authentication</strong></p>
<mat-divider></mat-divider>
<p *ngIf="!otpRequested">Please select a delivery method:</p>
<form fxLayout="column" *ngIf="!otpRequested" [formGroup]="twoFactorAuthenticationDeliveryMethodForm" (ngSubmit)="requestOTP()">
<mat-radio-group fxLayout="column" fxFlexAlign="center" formControlName="twoFactorAuthenticationDeliveryMethod">
<mat-radio-button *ngFor="let twoFactorAuthenticationDeliveryMethod of twoFactorAuthenticationDeliveryMethods"
[value]="twoFactorAuthenticationDeliveryMethod">
Send {{ twoFactorAuthenticationDeliveryMethod.name }} to {{ twoFactorAuthenticationDeliveryMethod.target }}
</mat-radio-button>
</mat-radio-group>
<button mat-raised-button color="primary" fxFlexAlign="center" fxFlexFill [disabled]="!twoFactorAuthenticationDeliveryMethodForm.valid">
Request OTP
<mat-spinner [diameter]="20" *ngIf="loading"></mat-spinner>
</button>
</form>
<!-- show input for otp request -->
<p *ngIf="otpRequested">Please enter the OTP:</p>
<form fxLayout="column" *ngIf="otpRequested" [formGroup]="twoFactorAuthenticationForm" (ngSubmit)="validateOTP()">
<mat-form-field fxFlexAlign="center" class="textfield">
<span matPrefix><mat-icon>verified_user</mat-icon>&nbsp;&nbsp;</span>
<input matInput placeholder="OTP" autocomplete="off" formControlName="otp">
<mat-hint align="start"><strong>Delivery Method:</strong> {{ selectedTwoFactorAuthenticationDeliveryMethod.name }} </mat-hint>
<mat-hint align="end"><strong>Validity:</strong> {{ tokenValidityTime / 60 }} mins </mat-hint>
<mat-error *ngIf="twoFactorAuthenticationForm.controls.otp.hasError('required')">
OTP is <strong>required</strong>
</mat-error>
</mat-form-field>
<button mat-raised-button color="primary" fxFlexAlign="center" class="btn" [disabled]="!twoFactorAuthenticationForm.valid">
Validate OTP
<mat-spinner [diameter]="20" *ngIf="loading"></mat-spinner>
</button>
<button type="button" mat-button fxFlexAlign="center" class="btn" (click)="resendOTP()" [disabled]="loading || resendOTPLoading">
Resend OTP
<mat-spinner [diameter]="20" *ngIf="resendOTPLoading"></mat-spinner>
</button>
</form>
@@ -0,0 +1,22 @@
.btn {
width: 14rem;
margin-top: 0.5rem;
}
mat-radio-button {
margin-bottom: 0.5rem;
}
mat-radio-button:last-child {
margin-bottom: 1rem;
}
.textfield {
width: 14rem;
}
mat-spinner {
z-index: 4;
float: right;
margin: 0.5rem 0;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TwoFactorAuthenticationComponent } from './two-factor-authentication.component';
describe('TwoFactorAuthenticationComponent', () => {
let component: TwoFactorAuthenticationComponent;
let fixture: ComponentFixture<TwoFactorAuthenticationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TwoFactorAuthenticationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TwoFactorAuthenticationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,91 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { AuthenticationService } from '../../core';
import { finalize } from 'rxjs/operators';
@Component({
selector: 'mifosx-two-factor-authentication',
templateUrl: './two-factor-authentication.component.html',
styleUrls: ['./two-factor-authentication.component.scss']
})
export class TwoFactorAuthenticationComponent implements OnInit {
twoFactorAuthenticationDeliveryMethods: any;
selectedTwoFactorAuthenticationDeliveryMethod: any;
loading = false;
resendOTPLoading = false;
otpRequested = false;
tokenValidityTime: number;
twoFactorAuthenticationDeliveryMethodForm: FormGroup;
twoFactorAuthenticationForm: FormGroup;
constructor(private formBuilder: FormBuilder,
private authenticationService: AuthenticationService) { }
ngOnInit() {
this.createTwoFactorAuthenticationDeliveryMethodForm();
this.authenticationService.getDeliveryMethods()
.subscribe(deliveryMethods => {
this.twoFactorAuthenticationDeliveryMethods = deliveryMethods;
});
}
private createTwoFactorAuthenticationDeliveryMethodForm() {
this.twoFactorAuthenticationDeliveryMethodForm = this.formBuilder.group({
'twoFactorAuthenticationDeliveryMethod': ['', Validators.required]
});
}
requestOTP() {
this.loading = true;
this.twoFactorAuthenticationDeliveryMethodForm.disable();
this.selectedTwoFactorAuthenticationDeliveryMethod =
this.twoFactorAuthenticationDeliveryMethodForm.value.twoFactorAuthenticationDeliveryMethod;
this.authenticationService.requestOTP(this.selectedTwoFactorAuthenticationDeliveryMethod)
.pipe(finalize(() => {
this.twoFactorAuthenticationDeliveryMethodForm.reset();
this.twoFactorAuthenticationDeliveryMethodForm.markAsPristine();
// Bug: Validation errors won't get removed on reset
this.twoFactorAuthenticationDeliveryMethodForm.enable();
this.loading = false;
}))
.subscribe((response: any) => {
this.createTwoFactorAuthenticationForm();
this.otpRequested = true;
this.tokenValidityTime = response.tokenLiveTimeInSec;
});
}
private createTwoFactorAuthenticationForm() {
this.twoFactorAuthenticationForm = this.formBuilder.group({
'otp': ['', Validators.required]
});
}
validateOTP() {
this.loading = true;
this.twoFactorAuthenticationForm.disable();
this.authenticationService.validateOTP(this.twoFactorAuthenticationForm.value.otp)
.pipe(finalize(() => {
this.twoFactorAuthenticationForm.reset();
this.twoFactorAuthenticationForm.markAsPristine();
// Bug: Validation errors won't get removed on reset
this.twoFactorAuthenticationForm.enable();
this.loading = false;
})).subscribe();
}
resendOTP() {
this.resendOTPLoading = true;
this.twoFactorAuthenticationForm.disable();
this.authenticationService.requestOTP(this.selectedTwoFactorAuthenticationDeliveryMethod)
.pipe(finalize(() => {
this.twoFactorAuthenticationForm.reset();
this.twoFactorAuthenticationForm.markAsPristine();
// Bug: Validation errors won't get removed on reset
this.twoFactorAuthenticationForm.enable();
this.resendOTPLoading = false;
})).subscribe();
}
}