[ACS-3551] feat: add context to outgoing requests for auth intgerceptors (#7913)

This commit is contained in:
Mikołaj Serwicki
2022-10-24 10:28:06 +02:00
committed by GitHub
parent 2d57ca31ca
commit 18a5197b5a
14 changed files with 246 additions and 23 deletions

View File

@@ -0,0 +1,25 @@
# AuthenticationInterceptor
This interceptor is responsible for providing authentication to angular HttpClient requests when a context `SHOULD_ADD_AUTH_TOKEN` is set to true.
By default, the interceptor won't do anything to the intercepted request.
## Usage
```typescript
import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/auth';
import { HttpClient, HttpContext } from '@angular/common/http';
getSth() {
return this.httpClient.get('http://example.com', { context: new HttpContext().set(SHOULD_ADD_AUTH_TOKEN, true)});
}
// or
getSth() {
const someRequest = this.httpClient.get('GET', 'http://example.com');
someRequest.context.set(SHOULD_ADD_AUTH_TOKEN, true);
return someRequest;
}
```

View File

@@ -0,0 +1,66 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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.
*/
import { HttpHandler, HttpHeaders, HttpRequest } from '@angular/common/http';
import { TestBed } from '@angular/core/testing';
import { Observable, of } from 'rxjs';
import { Authentication } from '../authentication';
import { AuthenticationInterceptor, SHOULD_ADD_AUTH_TOKEN } from './authentication.interceptor';
class MockAuthentication extends Authentication {
addTokenToHeader(httpHeaders: HttpHeaders): Observable<HttpHeaders> {
return of(httpHeaders);
}
}
const mockNext: HttpHandler = {
handle: () => new Observable(subscriber => {
subscriber.complete();
})
};
const request = new HttpRequest('GET', 'http://localhost:4200');
describe('AuthenticationInterceptor', () => {
let interceptor: AuthenticationInterceptor;
let addTokenToHeaderSpy: jasmine.Spy<any>;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AuthenticationInterceptor, {provide: Authentication, useClass: MockAuthentication}]
});
interceptor = TestBed.inject(AuthenticationInterceptor);
addTokenToHeaderSpy = spyOn(interceptor['authService'], 'addTokenToHeader');
});
it('should call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to true', () => {
request.context.set(SHOULD_ADD_AUTH_TOKEN, true);
interceptor.intercept(request, mockNext);
expect(addTokenToHeaderSpy).toHaveBeenCalled();
});
it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is set to false', () => {
request.context.set(SHOULD_ADD_AUTH_TOKEN, false);
interceptor.intercept(request, mockNext);
expect(addTokenToHeaderSpy).not.toHaveBeenCalled();
});
it('should not call add auth token method when SHOULD_ADD_AUTH_TOKEN context is not provided', () => {
interceptor.intercept(request, mockNext);
expect(addTokenToHeaderSpy).not.toHaveBeenCalled();
});
});

View File

@@ -0,0 +1,77 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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.
*/
import {
HttpContextToken,
HttpHandler,
HttpHeaderResponse,
HttpHeaders,
HttpInterceptor,
HttpProgressEvent,
HttpRequest,
HttpResponse,
HttpSentEvent,
HttpUserEvent
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError as observableThrowError } from 'rxjs';
import { catchError, mergeMap } from 'rxjs/operators';
import { Authentication } from '../authentication';
export const SHOULD_ADD_AUTH_TOKEN = new HttpContextToken<boolean>(() => false);
@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
constructor( private authService: Authentication) { }
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
if (req.context.get(SHOULD_ADD_AUTH_TOKEN)) {
return this.authService.addTokenToHeader(req.headers).pipe(
mergeMap((headersWithBearer) => {
const headerWithContentType = this.appendJsonContentType(headersWithBearer);
const kcReq = req.clone({ headers: headerWithContentType});
return next.handle(kcReq)
.pipe(
catchError((error) => observableThrowError(error))
);
})
);
}
return next.handle(req).pipe(catchError((error) => observableThrowError(error)));
}
private appendJsonContentType(headers: HttpHeaders): HttpHeaders {
// prevent adding any content type, to properly handle formData with boundary browser generated value,
// as adding any Content-Type its going to break the upload functionality
if (headers.get('Content-Type') === 'multipart/form-data') {
return headers.delete('Content-Type');
}
if (!headers.get('Content-Type')) {
return headers.set('Content-Type', 'application/json;charset=UTF-8');
}
return headers;
}
}

View File

@@ -0,0 +1,23 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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.
*/
import { HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
export abstract class Authentication {
public abstract addTokenToHeader(headers: HttpHeaders): Observable<HttpHeaders>;
}

View File

@@ -0,0 +1,20 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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.
*/
export * from './authentication';
export * from './authentication-interceptor/authentication.interceptor';