Skip to content

Commit

Permalink
fix: Authentication fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Aug 6, 2023
1 parent caa4909 commit adafd6b
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 59 deletions.
104 changes: 72 additions & 32 deletions packages/express-support/src/auth-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import express, { NextFunction } from 'express'
import express, { NextFunction, RequestHandler } from 'express'
import { ParamsDictionary } from 'express-serve-static-core'
import passport from 'passport'
import { EndpointArgs } from './types'
import { ParsedQs } from 'qs'
import { EndpointArgs, hasEndpointOpts, HasEndpointOpts } from './types'

export const checkUserIsInRole = (opts: { roles: string | string[] }) => (req: express.Request, res: express.Response, next: NextFunction) => {
if (!opts?.roles || opts.roles.length === 0) {
Expand All @@ -20,24 +22,50 @@ export const checkUserIsInRole = (opts: { roles: string | string[] }) => (req: e
return next()
}

const checkAuthenticationImpl = (req: express.Request, res: express.Response, opts?: EndpointArgs) => {
const checkAuthenticationImpl = (req: express.Request, res: express.Response, next: express.NextFunction, opts?: EndpointArgs) => {
if (!opts || !opts.authentication || opts.authentication.enabled === false) {
return
return next()
}
if (!opts.authentication.strategy) {
return res.status(401).end()
}
passport.authenticate(opts.authentication.strategy)

if (typeof req.isAuthenticated !== 'function' || !req.isAuthenticated()) {
return res.status(403).end()
}
return
const options = { authInfo: true, session: false }
passport
.authenticate(
opts.authentication.strategy,
options,
(
err: any,
user?: Express.User | false | null,
_info?: object | string | Array<string | undefined>,
_status?: number | Array<number | undefined>
) => {
if (err) {
return next({ statusCode: 403, message: err })
} else if (!user) {
return next({ statusCode: 403, message: 'user not found' })
}
if (options.session) {
req.logIn(user, function (err) {
if (err) {
return next(err)
}
return res.send(user)
})
}
return next()
}
)
.call(this, req, res, next)
// next()
}
const checkAuthorizationImpl = (req: express.Request, res: express.Response, opts?: EndpointArgs) => {
const checkAuthorizationImpl = (req: express.Request, res: express.Response, next: express.NextFunction, opts?: EndpointArgs) => {
if (!opts || !opts.authentication || !opts.authorization || opts.authentication.enabled === false || opts?.authorization.enabled === false) {
return
return next()
}
/*if (!req.isAuthenticated()) {
return sendErrorResponse(res, 403, 'Authorization with an unauthenticated request is not possible')
}*/
const authorization = opts.authorization

if (!authorization.enforcer && (!authorization.requireUserInRoles || authorization.requireUserInRoles.length === 0)) {
Expand All @@ -55,31 +83,43 @@ const checkAuthorizationImpl = (req: express.Request, res: express.Response, opt
return res.status(403).end()
}
}
return
return next()
}

const executeRequestHandlers = (req: express.Request, res: express.Response, next: NextFunction, opts?: EndpointArgs) => {
if (opts?.handlers) {
opts.handlers.forEach((requestHandler) => requestHandler(req, res, next))
}
export const checkAuthenticationOnly = (opts?: EndpointArgs) => (req: express.Request, res: express.Response, next: express.NextFunction) => {
// executeRequestHandlers(req, res, next, opts)
return checkAuthenticationImpl(req, res, next, opts)
}

export const checkAuthenticationOnly = (opts?: EndpointArgs) => (req: express.Request, res: express.Response, next: NextFunction) => {
executeRequestHandlers(req, res, next, opts)
return checkAuthenticationImpl(req, res, opts) ?? next()
export const checkAuthorizationOnly = (opts?: EndpointArgs) => (req: express.Request, res: express.Response, next: express.NextFunction) => {
// executeRequestHandlers(req, res, next, opts)
return checkAuthorizationImpl(req, res, next, opts)
}
export const checkAuth = (opts?: EndpointArgs): RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>[] => {
const handlers: RequestHandler<ParamsDictionary, any, any, ParsedQs, Record<string, any>>[] = []
handlers.push(checkAuthenticationOnly(opts))
handlers.push(checkAuthorizationOnly(opts))
opts?.handlers && handlers.push(...opts.handlers)
return handlers
}

export const checkAuthorizationOnly = (opts?: EndpointArgs) => (req: express.Request, res: express.Response, next: NextFunction) => {
executeRequestHandlers(req, res, next, opts)
return checkAuthorizationImpl(req, res, opts) ?? next()
export function copyGlobalAuthToEndpoint(args?: { opts?: HasEndpointOpts; key: string }) {
const opts = args?.opts
const key = args?.key
if (!opts || !key || !hasEndpointOpts(opts)) {
return
}
if (opts.endpointOpts?.globalAuth) {
if (opts.endpointOpts[key]?.disableGlobalAuth === true) {
return
}
opts.endpointOpts[key] = {
...opts.endpointOpts[key],
endpoint: { ...opts.endpointOpts.globalAuth, ...opts.endpointOpts[key]?.endpoint },
}
}
}
export const checkAuth = (opts?: EndpointArgs) => (req: express.Request, res: express.Response, next: NextFunction) => {
/*const handlers = /!*this._handlers ??*!/ []
checkAuthenticationImpl(req, res, opts))
handlers.push(checkAuthorizationImpl(req, res, opts))
handlers.push(next)
return handlers
*/
executeRequestHandlers(req, res, next, opts)
return checkAuthenticationImpl(req, res, opts) ?? checkAuthorizationImpl(req, res, opts) ?? next()

export function copyGlobalAuthToEndpoints(args?: { opts?: HasEndpointOpts; keys: string[] }) {
args?.keys.forEach((key) => copyGlobalAuthToEndpoint({ opts: args?.opts, key }))
}
33 changes: 33 additions & 0 deletions packages/express-support/src/express-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import express, { NextFunction } from 'express'
export function sendErrorResponse(response: express.Response, statusCode: number, message: string | object, error?: Error) {
console.log(`sendErrorResponse: ${message}`)
if (error) {
console.log(JSON.stringify(error))
}
if (response.headersSent) {
console.log(`sendErrorResponse headers already sent`)
return
}
if (response.headersSent) {
return
}
response.statusCode = statusCode
if (typeof message === 'string' && !message.startsWith('{')) {
message = { error: message }
}
if (typeof message === 'string' && message.startsWith('{')) {
return response.status(statusCode).end(message)
}
return response.status(statusCode).json(message)
}

export const jsonErrorHandler = (err: any, req: express.Request, res: express.Response, next: NextFunction) => {
const statusCode: number = 'statusCode' in err ? err.statusCode : 500
const errorMsg = typeof err === 'string' ? err : err.message
if (res.headersSent) {
console.log('Headers already sent, when calling error handler. Will defer to next error handler')
console.log(`Error was: ${JSON.stringify(err)}`)
return next(err)
}
return sendErrorResponse(res, statusCode, errorMsg, typeof err !== 'string' ? err : undefined)
}
25 changes: 0 additions & 25 deletions packages/express-support/src/functions.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
import express, { NextFunction } from 'express'
import process from 'process'

export function env(key?: string, prefix?: string): string | undefined {
if (!key) {
return
}
return process.env[`${prefix ? prefix.trim() : ''}${key}`]
}

export function sendErrorResponse(response: express.Response, statusCode: number, message: string | object, error?: Error) {
console.log(message)
if (error) {
console.log(error)
}
response.statusCode = statusCode
if (typeof message === 'string' && !message.startsWith('{')) {
message = { error: message }
}
if (typeof message === 'string' && message.startsWith('{')) {
return response.status(statusCode).end(message)
}
return response.status(statusCode).json(message)
}

export const jsonErrorHandler = (err: any, req: express.Request, res: express.Response, next: NextFunction) => {
if (res.headersSent) {
return next(err)
}
return sendErrorResponse(res, 500, err.message, err)
}
7 changes: 5 additions & 2 deletions packages/express-support/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export * from './entra-id-auth'
export * from './static-bearer-auth'
export * from './auth-utils'
export * from './builders'
export * from './express-builders'
export * from './types'
export { sendErrorResponse, jsonErrorHandler, env } from './functions'
export { sendErrorResponse, jsonErrorHandler } from './express-utils'
export * from './functions'

0 comments on commit adafd6b

Please sign in to comment.