mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
move auth interceptor to the core lib [ci:force]
This commit is contained in:
parent
40a9b37f63
commit
371dd9b5fe
@ -18,3 +18,4 @@
|
|||||||
export * from './lib/types';
|
export * from './lib/types';
|
||||||
export * from './lib/adf-http-client.service';
|
export * from './lib/adf-http-client.service';
|
||||||
export * from './lib/interfaces';
|
export * from './lib/interfaces';
|
||||||
|
export * from './lib/tokens';
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/auth';
|
|
||||||
import { Emitters as JsApiEmitters, HttpClient as JsApiHttpClient } from '@alfresco/js-api';
|
import { Emitters as JsApiEmitters, HttpClient as JsApiHttpClient } from '@alfresco/js-api';
|
||||||
import { HttpClient, HttpContext, HttpErrorResponse, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
|
import { HttpClient, HttpContext, HttpErrorResponse, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
@ -35,6 +34,7 @@ import { AlfrescoApiResponseError } from './alfresco-api/alfresco-api.response-e
|
|||||||
import { Constructor } from './types';
|
import { Constructor } from './types';
|
||||||
import { RequestOptions, SecurityOptions } from './interfaces';
|
import { RequestOptions, SecurityOptions } from './interfaces';
|
||||||
import ee, { Emitter } from 'event-emitter';
|
import ee, { Emitter } from 'event-emitter';
|
||||||
|
import { SHOULD_ADD_AUTH_TOKEN } from './tokens';
|
||||||
|
|
||||||
export interface Emitters {
|
export interface Emitters {
|
||||||
readonly eventEmitter: Emitter;
|
readonly eventEmitter: Emitter;
|
||||||
|
@ -15,5 +15,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './authentication';
|
import { HttpContextToken } from '@angular/common/http';
|
||||||
export * from './authentication-interceptor/authentication.interceptor';
|
|
||||||
|
export const SHOULD_ADD_AUTH_TOKEN = new HttpContextToken<boolean>(() => false);
|
@ -1,3 +0,0 @@
|
|||||||
# @alfresco/adf-core/auth
|
|
||||||
|
|
||||||
Secondary entry point of `@alfresco/adf-core`. It can be used by importing from `@alfresco/adf-core/auth`.
|
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"lib": {
|
|
||||||
"entryFile": "src/index.ts"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
# 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -1,67 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* 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(_: string, 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', () => {
|
|
||||||
addTokenToHeaderSpy.and.callThrough();
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,77 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* 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.url, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,69 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 } from './authentication.interceptor';
|
||||||
|
import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/api';
|
||||||
|
|
||||||
|
class MockAuthentication extends Authentication {
|
||||||
|
addTokenToHeader(_: string, 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', () => {
|
||||||
|
addTokenToHeaderSpy.and.callThrough();
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,70 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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,
|
||||||
|
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';
|
||||||
|
import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/api';
|
||||||
|
|
||||||
|
@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.url, 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;
|
||||||
|
}
|
||||||
|
}
|
@ -15,8 +15,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export * from './authentication';
|
||||||
export * from './authentication-interceptor/auth-bearer.interceptor';
|
export * from './authentication-interceptor/auth-bearer.interceptor';
|
||||||
|
export * from './authentication-interceptor/authentication.interceptor';
|
||||||
export * from './guard/auth-guard.service';
|
export * from './guard/auth-guard.service';
|
||||||
export * from './guard/auth-guard';
|
export * from './guard/auth-guard';
|
||||||
export * from './guard/auth-guard-ecm.service';
|
export * from './guard/auth-guard-ecm.service';
|
||||||
|
@ -41,7 +41,7 @@ import { TranslationService } from './translation/translation.service';
|
|||||||
import { TranslateLoaderService } from './translation/translate-loader.service';
|
import { TranslateLoaderService } from './translation/translate-loader.service';
|
||||||
import { SEARCH_TEXT_INPUT_DIRECTIVES } from './search-text/search-text-input.module';
|
import { SEARCH_TEXT_INPUT_DIRECTIVES } from './search-text/search-text-input.module';
|
||||||
import { AdfHttpClient } from '@alfresco/adf-core/api';
|
import { AdfHttpClient } from '@alfresco/adf-core/api';
|
||||||
import { AuthenticationInterceptor, Authentication } from '@alfresco/adf-core/auth';
|
import { AuthenticationInterceptor, Authentication } from './auth';
|
||||||
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
import { AuthenticationService } from './auth/services/authentication.service';
|
import { AuthenticationService } from './auth/services/authentication.service';
|
||||||
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
"@alfresco/adf-extensions": ["../../../dist/libs/extensions"],
|
||||||
"@alfresco/adf-extensions/*": ["../../../dist/libs/extensions/*"],
|
"@alfresco/adf-extensions/*": ["../../../dist/libs/extensions/*"],
|
||||||
"@alfresco/adf-core/auth": ["../auth/src/index.ts"],
|
|
||||||
"@alfresco/adf-core/shell": ["../shell/src/index.ts"],
|
"@alfresco/adf-core/shell": ["../shell/src/index.ts"],
|
||||||
"@alfresco/adf-core/api": ["../api/src/index.ts"],
|
"@alfresco/adf-core/api": ["../api/src/index.ts"],
|
||||||
"@alfresco/adf-core/feature-flags": ["../feature-flags/src/index.ts"],
|
"@alfresco/adf-core/feature-flags": ["../feature-flags/src/index.ts"],
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
"@alfresco/adf-core": ["lib/core/src/public-api.ts"],
|
"@alfresco/adf-core": ["lib/core/src/public-api.ts"],
|
||||||
"@alfresco/adf-core/*": ["lib/core/*/public-api.ts"],
|
"@alfresco/adf-core/*": ["lib/core/*/public-api.ts"],
|
||||||
"@alfresco/adf-core/api": ["lib/core/api/src/index.ts"],
|
"@alfresco/adf-core/api": ["lib/core/api/src/index.ts"],
|
||||||
"@alfresco/adf-core/auth": ["lib/core/auth/src/index.ts"],
|
|
||||||
"@alfresco/adf-core/breadcrumbs": ["lib/core/breadcrumbs/src/index.ts"],
|
"@alfresco/adf-core/breadcrumbs": ["lib/core/breadcrumbs/src/index.ts"],
|
||||||
"@alfresco/adf-core/feature-flags": ["lib/core/feature-flags/src/index.ts"],
|
"@alfresco/adf-core/feature-flags": ["lib/core/feature-flags/src/index.ts"],
|
||||||
"@alfresco/adf-core/shell": ["lib/core/shell/src/index.ts"],
|
"@alfresco/adf-core/shell": ["lib/core/shell/src/index.ts"],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user