forked from sourcefuse/loopback4-microservice-catalog
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): add component to authenticate swagger ui access (sourcefu…
- Loading branch information
1 parent
b46815e
commit 40f669f
Showing
13 changed files
with
196 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './bearer-verifier'; | ||
export * from './logger-extension'; | ||
export * from './swagger-authentication'; |
31 changes: 31 additions & 0 deletions
31
packages/core/src/components/swagger-authentication/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# SwaggerAuthentication Component | ||
|
||
## Overview | ||
|
||
A Loopback Component that adds an authenticating middleware for Rest Explorer | ||
|
||
### Installation | ||
|
||
```bash | ||
|
||
npm i @sourceloop/authentication-service | ||
|
||
``` | ||
|
||
### Usage | ||
|
||
- Create a new Loopback4 Application (If you don't have one already) | ||
`lb4 testapp` | ||
- Install the authentication service | ||
`npm i @sourceloop/core` | ||
- Configure `@sourceloop/core` component to include `SwaggerAuthenticateComponent` - | ||
```typescript | ||
this.bind(SFCoreBindings.config).to({ | ||
authenticateSwaggerUI: true, | ||
swaggerUsername: '<username>', | ||
swaggerPassword: '<password>', | ||
}); | ||
``` | ||
- Bind the `HttpAuthenticationVerifier` to override the basic authentication logic provided by [default](/providers/http-authentication.verifier.ts). | ||
- Start the application | ||
`npm start` |
29 changes: 29 additions & 0 deletions
29
packages/core/src/components/swagger-authentication/component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { | ||
Binding, | ||
Component, | ||
CoreBindings, | ||
inject, | ||
ProviderMap, | ||
} from '@loopback/core'; | ||
import {Class, Model, Repository} from '@loopback/repository'; | ||
import {RestApplication} from '@loopback/rest'; | ||
import {SwaggerAuthenticationBindings} from './keys'; | ||
import {AuthenticateSwaggerMiddlewareInterceptor} from './middlewares'; | ||
import {HttpAuthenticationVerifierProvider} from './providers/http-authentication.verifier'; | ||
|
||
export class SwaggerAuthenticationComponent implements Component { | ||
providers?: ProviderMap; | ||
bindings: Binding[] = []; | ||
repositories?: Class<Repository<Model>>[]; | ||
models?: Class<Model>[]; | ||
constructor( | ||
@inject(CoreBindings.APPLICATION_INSTANCE) | ||
private readonly application: RestApplication, | ||
) { | ||
this.providers = { | ||
[SwaggerAuthenticationBindings.VERIFIER.key]: | ||
HttpAuthenticationVerifierProvider, | ||
}; | ||
this.application.middleware(AuthenticateSwaggerMiddlewareInterceptor); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from './component'; | ||
export * from './keys'; | ||
export * from './types'; | ||
export * from './providers'; | ||
export * from './middlewares'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import {BindingKey} from '@loopback/core'; | ||
import {BINDING_PREFIX} from '../../constants'; | ||
import {HttpAuthenticationVerifier} from './types'; | ||
export namespace SwaggerAuthenticationBindings { | ||
export const VERIFIER = BindingKey.create<HttpAuthenticationVerifier>( | ||
`${BINDING_PREFIX}.bearer-verfier.config`, | ||
); | ||
} |
83 changes: 83 additions & 0 deletions
83
...core/src/components/swagger-authentication/middlewares/authenticate-swagger.middleware.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { | ||
Context, | ||
globalInterceptor, | ||
inject, | ||
InvocationResult, | ||
Provider, | ||
ValueOrPromise, | ||
} from '@loopback/core'; | ||
import {Request, RequestContext} from '@loopback/rest'; | ||
import { | ||
RestExplorerBindings, | ||
RestExplorerConfig, | ||
} from '@loopback/rest-explorer'; | ||
import {MiddlewareContext, Middleware} from '@loopback/express'; | ||
import {SwaggerAuthenticationBindings} from '../keys'; | ||
import {HttpAuthenticationVerifier} from '../types'; | ||
|
||
@globalInterceptor('auth', {tags: {name: 'AuthenticateSwaggerMiddleware'}}) | ||
export class AuthenticateSwaggerMiddlewareInterceptor | ||
implements Provider<Middleware> | ||
{ | ||
constructor( | ||
@inject(SwaggerAuthenticationBindings.VERIFIER) | ||
private readonly verifier: HttpAuthenticationVerifier, | ||
@inject(RestExplorerBindings.CONFIG) | ||
private readonly config: RestExplorerConfig, | ||
) {} | ||
value() { | ||
return this.intercept.bind(this); | ||
} | ||
|
||
async intercept( | ||
context: MiddlewareContext, | ||
next: () => ValueOrPromise<InvocationResult>, | ||
) { | ||
let request, response; | ||
if (this.isRequestContext(context.parent)) { | ||
request = context.parent.request; | ||
response = context.parent.response; | ||
} | ||
if (request && response && this.isOpenAPISpecRequest(request)) { | ||
const {username, password} = this.decodeHeader(request); | ||
const verified = this.verifier(username, password); | ||
if (!verified) { | ||
response | ||
.status(401) | ||
.setHeader('WWW-Authenticate', 'Basic realm="Node"'); | ||
response.end('Unauthorized'); | ||
return null; | ||
} | ||
} | ||
return next(); | ||
} | ||
|
||
private decodeHeader(request: Request) { | ||
const header = request.headers.authorization ?? ''; // get the auth header | ||
const token = header.split(/\s+/).pop() ?? ''; // and the encoded auth token | ||
const auth = Buffer.from(token, 'base64').toString(); // convert from base64 | ||
const parts = auth.split(/:/); // split on colon | ||
const username = parts.shift(); // username is first | ||
const password = parts.join(':'); | ||
|
||
return { | ||
username, | ||
password, | ||
}; | ||
} | ||
|
||
private isOpenAPISpecRequest(request: Request) { | ||
const swaggerUrl = `${this.config.path}/openapi.json`; | ||
if (request.url.includes(swaggerUrl)) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private isRequestContext(context?: Context): context is RequestContext { | ||
return !!( | ||
(context as RequestContext).request && | ||
(context as RequestContext).response | ||
); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
packages/core/src/components/swagger-authentication/middlewares/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './authenticate-swagger.middleware'; |
21 changes: 21 additions & 0 deletions
21
...ages/core/src/components/swagger-authentication/providers/http-authentication.verifier.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import {inject, Provider} from '@loopback/core'; | ||
import {SFCoreBindings} from '../../../keys'; | ||
import {CoreConfig} from '../../../types'; | ||
import {HttpAuthenticationVerifier} from '../types'; | ||
|
||
export class HttpAuthenticationVerifierProvider | ||
implements Provider<HttpAuthenticationVerifier> | ||
{ | ||
constructor( | ||
@inject(SFCoreBindings.config, {optional: true}) | ||
private readonly coreConfig: CoreConfig, | ||
) {} | ||
value(): HttpAuthenticationVerifier { | ||
return (username, password) => { | ||
return ( | ||
username === this.coreConfig.swaggerUsername && | ||
password === this.coreConfig.swaggerPassword | ||
); | ||
}; | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
packages/core/src/components/swagger-authentication/providers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './http-authentication.verifier'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export type HttpAuthenticationVerifier = ( | ||
username?: string, | ||
password?: string, | ||
) => boolean; | ||
|
||
export type ISwaggerAuthenticationConfig = {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters