Initial Commit - NG UI
[osm/NG-UI.git] / src / services / AuthInterceptorService.ts
diff --git a/src/services/AuthInterceptorService.ts b/src/services/AuthInterceptorService.ts
new file mode 100644 (file)
index 0000000..ede10a8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
+ */
+
+/**
+ * @file HttpInterceptor file
+ */
+import {
+    HttpErrorResponse, HttpHandler, HttpHeaderResponse, HttpInterceptor, HttpProgressEvent,
+    HttpRequest, HttpResponse, HttpSentEvent, HttpUserEvent
+} from '@angular/common/http';
+import { Injectable, Injector } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { AuthenticationService } from 'AuthenticationService';
+import * as HttpStatus from 'http-status-codes';
+import { Observable, throwError } from 'rxjs';
+import { catchError, retry } from 'rxjs/operators';
+
+/**
+ * An Injectable is a class adorned with the @Injectable decorator function.
+ * @Injectable takes a metadata object that tells Angular how to compile and run module code
+ */
+@Injectable()
+export class AuthInterceptorService implements HttpInterceptor {
+    /** Holds header options @private */
+    private clonedReq: HttpRequest<{}>;
+
+    /** To inject services @private */
+    private injector: Injector;
+
+    /** Notifier service to popup notification @private */
+    private notifierService: NotifierService;
+
+    /** Contains tranlsate instance @private */
+    private translateService: TranslateService;
+
+    /** Utilizes auth service for any auth operations @private */
+    private authService: AuthenticationService;
+
+    /** create the instance of the component */
+    constructor(injector: Injector) {
+        this.injector = injector;
+        this.notifierService = this.injector.get(NotifierService);
+        this.authService = this.injector.get(AuthenticationService);
+        this.translateService = this.injector.get(TranslateService);
+    }
+
+    /**
+     * intercept logic
+     * @param req
+     * @param next
+     */
+    public intercept(req: HttpRequest<{}>, next: HttpHandler): Observable<HttpSentEvent |
+        // tslint:disable-next-line:no-any
+        HttpHeaderResponse | HttpProgressEvent | HttpResponse<{}> | HttpUserEvent<any> | any> {
+        const idToken: string = localStorage.getItem('id_token');
+        const excludedUrl: string[] = ['osm/admin/v1/tokens', 'assets/i18n/', 'osm/version'];
+        if (excludedUrl.some((x: string): boolean => { return req.url.includes(x); })) { return next.handle(req); }
+        if (idToken.length > 0) {
+            this.setHeader(req, idToken);
+            return next.handle(this.clonedReq).pipe(
+                catchError((err: HttpErrorResponse) => {
+                    this.errorRes(err, req, next);
+                    return throwError(err);
+                })
+            );
+        } else {
+            //TODO: Handle error via notification service
+        }
+    }
+
+    /** Set header options @public */
+    // tslint:disable-next-line:no-any
+    public setHeader(req: HttpRequest<any>, idToken: string): void {
+        if (req.body !== null && req.body.byteLength !== null) {
+            this.clonedReq = req.clone({
+                setHeaders: { Authorization: 'Bearer ' + idToken, 'Cache-Control': 'no-cache', Pragma: 'no-cache' }
+            });
+        } else {
+            this.clonedReq = req.clone({
+                setHeaders: { Authorization: 'Bearer ' + idToken, 'Content-Type': 'charset=UTF-8',
+                'Cache-Control': 'no-cache', Pragma: 'no-cache' }
+            });
+        }
+    }
+
+    /** Handles error response @public */
+    public errorRes(err: HttpErrorResponse, req: HttpRequest<{}>, next: HttpHandler): Observable<{}> {
+        if (err instanceof HttpErrorResponse) {
+            switch (err.status) {
+                case HttpStatus.UNAUTHORIZED || HttpStatus.FORBIDDEN:
+                    this.handleError(err);
+                    break;
+                default: return throwError(err);
+            }
+        } else { return throwError(err); }
+    }
+
+    /** Method to handle  401 & 403 error */
+    private handleError(err: HttpErrorResponse): void {
+        if (err.error.detail === 'Expired Token or Authorization HTTP header' ||
+            err.error.detail === 'Invalid Token or Authorization HTTP header') {
+            this.notifierService.hideAll();
+            this.authService.logoutResponse();
+            if (this.authService.handle401) {
+                this.notifierService.notify('error', this.translateService.instant('SESSIONEXPIRY'));
+                this.authService.handle401 = false;
+            }
+        }
+    }
+}