Implement /oauth2/token endpoint; token auth middleware
This commit is contained in:
33
src/auth/middleware/ScopeRequiredMiddleware.ts
Normal file
33
src/auth/middleware/ScopeRequiredMiddleware.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import {Middleware} from '../../http/routing/Middleware'
|
||||
import {ResponseObject} from '../../http/routing/Route'
|
||||
import {OAuth2Token} from '../server/types'
|
||||
import {HTTPError} from '../../http/HTTPError'
|
||||
import {HTTPStatus, Pipeline} from '../../util'
|
||||
import {Request} from '../../http/lifecycle/Request'
|
||||
import {Constructable, Container} from '../../di'
|
||||
|
||||
export class ScopeRequiredMiddleware extends Middleware {
|
||||
constructor(
|
||||
request: Request,
|
||||
protected readonly scope: string,
|
||||
) {
|
||||
super(request)
|
||||
}
|
||||
|
||||
apply(): ResponseObject {
|
||||
if ( !this.request.hasInstance(OAuth2Token) ) {
|
||||
throw new HTTPError(HTTPStatus.UNAUTHORIZED, 'Must specify an OAuth2 token.')
|
||||
}
|
||||
|
||||
const token: OAuth2Token = this.request.getExistingInstance(OAuth2Token)
|
||||
if ( typeof token.scope !== 'undefined' && token.scope !== this.scope ) {
|
||||
throw new HTTPError(HTTPStatus.UNAUTHORIZED, 'Insufficient token permissions (requires: ' + this.scope + ')')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const scope = (name: string): Constructable<ScopeRequiredMiddleware> => {
|
||||
return new Pipeline<Container, ScopeRequiredMiddleware>(
|
||||
container => container.make(ScopeRequiredMiddleware, name),
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import {Middleware} from '../../http/routing/Middleware'
|
||||
import {Inject, Injectable, Instantiable} from '../../di'
|
||||
import {Inject, Injectable} from '../../di'
|
||||
import {Config} from '../../service/Config'
|
||||
import {Logging} from '../../service/Logging'
|
||||
import {AuthenticatableRepository} from '../types'
|
||||
import {Maybe} from '../../util'
|
||||
import {AuthenticationConfig, isAuthenticationConfig} from '../config'
|
||||
import {ResponseObject} from '../../http/routing/Route'
|
||||
import {SessionSecurityContext} from '../context/SessionSecurityContext'
|
||||
import {SecurityContext} from '../context/SecurityContext'
|
||||
@@ -23,22 +21,9 @@ export class SessionAuthMiddleware extends Middleware {
|
||||
|
||||
async apply(): Promise<ResponseObject> {
|
||||
this.logging.debug('Applying session auth middleware.')
|
||||
const context = <SessionSecurityContext> this.make(SessionSecurityContext, this.getRepository())
|
||||
const repo = <AuthenticatableRepository> this.make(AuthenticatableRepository)
|
||||
const context = <SessionSecurityContext> this.make(SessionSecurityContext, repo)
|
||||
this.request.registerSingletonInstance(SecurityContext, context)
|
||||
await context.resume()
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the correct AuthenticatableRepository based on the auth config.
|
||||
* @protected
|
||||
*/
|
||||
protected getRepository(): AuthenticatableRepository {
|
||||
const config: Maybe<AuthenticationConfig> = this.config.get('auth')
|
||||
if ( !isAuthenticationConfig(config) ) {
|
||||
throw new TypeError('Invalid authentication config.')
|
||||
}
|
||||
|
||||
const repo: Instantiable<AuthenticatableRepository> = config.storage
|
||||
return this.make(repo)
|
||||
}
|
||||
}
|
||||
|
||||
45
src/auth/middleware/TokenAuthMiddleware.ts
Normal file
45
src/auth/middleware/TokenAuthMiddleware.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {Middleware} from '../../http/routing/Middleware'
|
||||
import {Inject, Injectable} from '../../di'
|
||||
import {Config} from '../../service/Config'
|
||||
import {Logging} from '../../service/Logging'
|
||||
import {AuthenticatableRepository} from '../types'
|
||||
import {ResponseObject} from '../../http/routing/Route'
|
||||
import {SecurityContext} from '../context/SecurityContext'
|
||||
import {TokenSecurityContext} from '../context/TokenSecurityContext'
|
||||
import {OAuth2Token, oauth2TokenString, TokenRepository} from '../server/types'
|
||||
|
||||
/**
|
||||
* Injects a TokenSecurityContext into the request and attempts to
|
||||
* resume the user's authentication.
|
||||
*/
|
||||
@Injectable()
|
||||
export class TokenAuthMiddleware extends Middleware {
|
||||
@Inject()
|
||||
protected readonly config!: Config
|
||||
|
||||
@Inject()
|
||||
protected readonly logging!: Logging
|
||||
|
||||
@Inject()
|
||||
protected readonly tokens!: TokenRepository
|
||||
|
||||
async apply(): Promise<ResponseObject> {
|
||||
this.logging.debug('Applying token auth middleware.')
|
||||
let tokenString = this.request.getHeader('Authorization')
|
||||
if ( Array.isArray(tokenString) ) {
|
||||
tokenString = tokenString[0]
|
||||
}
|
||||
|
||||
if ( tokenString ) {
|
||||
const token = await this.tokens.decode(oauth2TokenString(tokenString))
|
||||
if ( token ) {
|
||||
this.request.registerSingletonInstance(OAuth2Token, token)
|
||||
}
|
||||
}
|
||||
|
||||
const repo = <AuthenticatableRepository> this.make(AuthenticatableRepository)
|
||||
const context = <TokenSecurityContext> this.make(TokenSecurityContext, repo)
|
||||
this.request.registerSingletonInstance(SecurityContext, context)
|
||||
await context.resume()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user