/** Angular Imports */ import { Injectable } from '@angular/core' ; import { HttpClient , HttpParams } from '@angular/common/http' ; /** rxjs Imports */ import { Observable , of } from 'rxjs' ; import { map } from 'rxjs/operators' ; /** Custom Services */ import { AlertService } from '../alert/alert.service' ; /** Custom Interceptors */ import { AuthenticationInterceptor } from './authentication.interceptor' ; /** Environment Configuration */ import { environment } from '../../../environments/environment' ; /** Custom Models */ import { LoginContext } from './login-context.model' ; import { Credentials } from './credentials.model' ; import { OAuth2Token } from './o-auth2-token.model' ; /**
 * Authentication workflow.
 */ @ Injectable ( ) export class AuthenticationService { /** Denotes whether the user credentials should persist through sessions. */ private rememberMe : boolean ; /**
     * Denotes the type of storage:
     *
     * Session Storage: User credentials should not persist through sessions.
     *
     * Local Storage: User credentials should persist through sessions.
     */ private storage : any ; /** User credentials. */ private credentials : Credentials ; /** Key to store credentials in storage. */ private credentialsStorageKey = 'mifosXCredentials' ; /** Key to store oauth token details in storage. */ private oAuthTokenDetailsStorageKey = 'mifosXOAuthTokenDetails' ; /** Key to store two factor authentication token in storage. */ private twoFactorAuthenticationTokenStorageKey = 'mifosXTwoFactorAuthenticationToken' ; param { HttpClient } http param { AlertService } alertService param { AuthenticationInterceptor } authenticationInterceptor constructor ( private http , private alertService , private authenticationInterceptor ) { this . rememberMe = false ; this . storage = sessionStorage ; const savedCredentials = JSON . parse ( sessionStorage . getItem ( this . credentialsStorageKey ) || localStorage . getItem ( this . credentialsStorageKey ) ) ; if ( savedCredentials ) { if ( savedCredentials . rememberMe ) { this . rememberMe = true ; this . storage = localStorage ; } const twoFactorAccessToken = JSON . parse ( this . storage . getItem ( this . twoFactorAuthenticationTokenStorageKey ) ) ; if ( environment . oauth . enabled ) { this . refreshOAuthAccessToken ( ) ; } else { authenticationInterceptor . setAuthorizationToken ( savedCredentials . base64EncodedAuthenticationKey ) ; } if ( twoFactorAccessToken ) { authenticationInterceptor . setTwoFactorAccessToken ( twoFactorAccessToken . token ) ; } } } param { LoginContext } loginContext returns { Observable < boolean > } login ( loginContext ) { this . alertService . alert ( { type : 'Authentication Start' , message : 'Please wait...' } ) ; this . rememberMe = loginContext . remember ; this . storage = this . rememberMe ? localStorage : sessionStorage ; if ( environment . oauth . enabled ) { let httpParams = new HttpParams ( ) ; httpParams = httpParams . set ( 'client_id' , 'community-app' ) ; httpParams = httpParams . set ( 'grant_type' , 'password' ) ; httpParams = httpParams . set ( 'client_secret' , '123' ) ; return this . http . disableApiPrefix ( ) . post ( `${ environment . oauth . serverUrl }/oauth/token` , { } , { params : httpParams } ) . pipe ( map ( ( tokenResponse ) => { this . getUserDetails ( tokenResponse ) ; return of ( true ) ; } ) ) ; } else { return this . http . post ( '/authentication' , { username : loginContext . username , password : loginContext . password } ) . pipe ( map ( ( credentials ) => { this . onLoginSuccess ( credentials ) ; return of ( true ) ; } ) ) ; } } param { OAuth2Token } tokenResponse private getUserDetails ( tokenResponse ) { const httpParams = new HttpParams ( ) . set ( 'access_token' , tokenResponse . access_token ) ; this . refreshTokenOnExpiry ( tokenResponse . expires_in ) ; this . http . get ( '/userdetails' , { params : httpParams } ) . subscribe ( ( credentials ) => { this . onLoginSuccess ( credentials ) ; if ( ! credentials . shouldRenewPassword ) { this . storage . setItem ( this . oAuthTokenDetailsStorageKey , JSON . stringify ( tokenResponse ) ) ; } } ) ; } param { number } expiresInTime private refreshTokenOnExpiry ( expiresInTime ) { setTimeout ( ( ) => this . refreshOAuthAccessToken ( ) , expiresInTime * 1000 ) ; } /**
     * Refreshes the oauth2 authorization token.
     */ private refreshOAuthAccessToken ( ) { const oAuthRefreshToken = JSON . parse ( this . storage . getItem ( this . oAuthTokenDetailsStorageKey ) ) . refresh_token ; this . authenticationInterceptor . removeAuthorization ( ) ; let httpParams = new HttpParams ( ) ; httpParams = httpParams . set ( 'client_id' , 'community-app' ) ; httpParams = httpParams . set ( 'grant_type' , 'refresh_token' ) ; httpParams = httpParams . set ( 'client_secret' , '123' ) ; httpParams = httpParams . set ( 'refresh_token' , oAuthRefreshToken ) ; this . http . disableApiPrefix ( ) . post ( `${ environment . oauth . serverUrl }/oauth/token` , { } , { params : httpParams } ) . subscribe ( ( tokenResponse ) => { this . storage . setItem ( this . oAuthTokenDetailsStorageKey , JSON . stringify ( tokenResponse ) ) ; this . authenticationInterceptor . setAuthorizationToken ( tokenResponse . access_token ) ; this . refreshTokenOnExpiry ( tokenResponse . expires_in ) ; const credentials = JSON . parse ( this . storage . getItem ( this . credentialsStorageKey ) ) ; credentials . accessToken = tokenResponse . access_token ; this . storage . setItem ( this . credentialsStorageKey , JSON . stringify ( credentials ) ) ; } ) ; } param { Credentials } credentials private onLoginSuccess ( credentials ) { if ( environment . oauth . enabled ) { this . authenticationInterceptor . setAuthorizationToken ( credentials . accessToken ) ; } else { this . authenticationInterceptor . setAuthorizationToken ( credentials . base64EncodedAuthenticationKey ) ; } if ( credentials . isTwoFactorAuthenticationRequired ) { this . credentials = credentials ; this . alertService . alert ( { type : 'Two Factor Authentication Required' , message : 'Two Factor Authentication Required' } ) ; } else { if ( credentials . shouldRenewPassword ) { this . credentials = credentials ; this . alertService . alert ( { type : 'Password Expired' , message : 'Your password has expired, please reset your password!' } ) ; } else { this . setCredentials ( credentials ) ; this . alertService . alert ( { type : 'Authentication Success' , message : `${ credentials . username } successfully logged in!` } ) ; delete this . credentials ; } } } returns { Observable < boolean > } logout ( ) { const twoFactorToken = JSON . parse ( this . storage . getItem ( this . twoFactorAuthenticationTokenStorageKey ) ) ; if ( twoFactorToken ) { this . http . post ( '/twofactor/invalidate' , { token : twoFactorToken . token } ) . subscribe ( ) ; this . authenticationInterceptor . removeTwoFactorAuthorization ( ) ; } this . authenticationInterceptor . removeAuthorization ( ) ; this . setCredentials ( ) ; return of ( true ) ; } returns { boolean } twoFactorAccessTokenIsValid ( ) { const twoFactorAccessToken = JSON . parse ( this . storage . getItem ( this . twoFactorAuthenticationTokenStorageKey ) ) ; if ( twoFactorAccessToken ) { return ( ( new Date ( ) ) . getTime ( ) < twoFactorAccessToken . validTo ) ; } return true ; } returns { boolean } isAuthenticated ( ) { return ! ! ( JSON . parse ( sessionStorage . getItem ( this . credentialsStorageKey ) || localStorage . getItem ( this . credentialsStorageKey ) ) && this . twoFactorAccessTokenIsValid ( ) ) ; } returns { Credentials } getCredentials ( ) { return JSON . parse ( this . storage . getItem ( this . credentialsStorageKey ) ) ; } param { Credentials } credentials private setCredentials ( credentials ? ) { if ( credentials ) { credentials . rememberMe = this . rememberMe ; this . storage . setItem ( this . credentialsStorageKey , JSON . stringify ( credentials ) ) ; } else { this . storage . removeItem ( this . credentialsStorageKey ) ; this . storage . removeItem ( this . oAuthTokenDetailsStorageKey ) ; this . storage . removeItem ( this . twoFactorAuthenticationTokenStorageKey ) ; } } /**
     * Following functions are for two factor authentication and require
     * first level authorization headers to be setup for the requests.
     */ /**
     * Gets the two factor authentication delivery methods available for the user.
     */ getDeliveryMethods ( ) { return this . http . get ( '/twofactor' ) ; } param { any } deliveryMethod requestOTP ( deliveryMethod ) { let httpParams = new HttpParams ( ) ; httpParams = httpParams . set ( 'deliveryMethod' , deliveryMethod . name ) ; httpParams = httpParams . set ( 'extendedToken' , this . rememberMe . toString ( ) ) ; return this . http . post ( `/twofactor` , { } , { params : httpParams } ) ; } param { string } otp validateOTP ( otp ) { const httpParams = new HttpParams ( ) . set ( 'token' , otp ) ; return this . http . post ( `/twofactor/validate` , { } , { params : httpParams } ) . pipe ( map ( response => { this . onOTPValidateSuccess ( response ) ; } ) ) ; } param { any } response private onOTPValidateSuccess ( response ) { this . authenticationInterceptor . setTwoFactorAccessToken ( response . token ) ; if ( this . credentials . shouldRenewPassword ) { this . alertService . alert ( { type : 'Password Expired' , message : 'Your password has expired, please reset your password!' } ) ; } else { this . setCredentials ( this . credentials ) ; this . alertService . alert ( { type : 'Authentication Success' , message : `${ this . credentials . username } successfully logged in!` } ) ; delete this . credentials ; this . storage . setItem ( this . twoFactorAuthenticationTokenStorageKey , JSON . stringify ( response ) ) ; } } param { any } passwordDetails resetPassword ( passwordDetails ) { return this . http . put ( `/users/${ this . credentials . userId }` , passwordDetails ) . pipe ( map ( ( ) => { this . alertService . alert ( { type : 'Password Reset Success' , message : `Your password was sucessfully reset!` } ) ; this . authenticationInterceptor . removeAuthorization ( ) ; this . authenticationInterceptor . removeTwoFactorAuthorization ( ) ; const loginContext = { username : this . credentials . username , password : passwordDetails . password , remember : this . rememberMe } ; this . login ( loginContext ) . subscribe ( ) ; } ) ) ; } }