oidc-provider
Version:
OAuth 2.0 Authorization Server implementation for Node.js with OpenID Connect
105 lines (90 loc) • 3.27 kB
JavaScript
import Debug from 'debug';
import { InvalidRedirectUri } from '../helpers/errors.js';
import instance from '../helpers/weak_cache.js';
import errOut from '../helpers/err_out.js';
import resolveResponseMode from '../helpers/resolve_response_mode.js';
import oneRedirectUriClients from '../actions/authorization/one_redirect_uri_clients.js';
const debug = new Debug('oidc-provider:authentication:error');
const serverError = new Debug('oidc-provider:server_error');
const serverErrorTrace = new Debug('oidc-provider:server_error:trace');
export default (provider) => {
const AD_ACTA_CHECKS = Object.entries({
redirect_uri: {
Err: InvalidRedirectUri,
method: 'redirectUriAllowed',
check: 'redirectUriCheckPerformed',
recovery: oneRedirectUriClients,
},
});
function getOutAndEmit(ctx, err, state) {
const out = { ...errOut(err, state), iss: ctx.oidc.provider.issuer };
if (err.expose) {
provider.emit('authorization.error', ctx, err);
debug('%o', out);
} else {
provider.emit('server_error', ctx, err);
serverError('path=%s method=%s error=%o', ctx.path, ctx.method, err);
serverErrorTrace(err);
}
return out;
}
function safe(param) {
if (param && typeof param === 'string') {
return param;
}
return undefined;
}
return async function authorizationErrorHandler(ctx, next) {
try {
await next();
} catch (caught) {
let err = caught;
ctx.status = err.statusCode || 500;
const { oidc } = ctx;
const { params = (ctx.method === 'POST' ? oidc.body : ctx.query) || {} } = oidc;
if (!oidc.client && safe(params.client_id) && !ctx.oidc.noclient) {
try {
oidc.entity('Client', await provider.Client.find(safe(params.client_id)));
} catch (e) {}
}
for (const [param, {
Err, check, flag, method, recovery,
}] of AD_ACTA_CHECKS) {
if (
(!flag || instance(provider).configuration[flag])
&& !(err instanceof Err) && oidc.client
&& !oidc[check]
) {
if (recovery && !safe(params[param])) {
recovery(ctx, () => {});
}
if (safe(params[param]) && !oidc.client[method](params[param])) {
getOutAndEmit(ctx, caught, safe(params.state));
err = new Err();
ctx.status = err.statusCode;
break;
}
}
}
const out = getOutAndEmit(ctx, err, safe(params.state));
// in case redirect_uri or client could not be verified no successful
// response should happen, render instead
if (
!safe(params.client_id)
|| (safe(params.client_id) && !oidc.client)
|| !safe(params.redirect_uri)
|| !err.allow_redirect
) {
const { renderError } = instance(provider).configuration;
await renderError(ctx, out, err);
} else {
let mode = safe(params.response_mode);
if (!instance(provider).responseModes.has(mode)) {
mode = resolveResponseMode(safe(params.response_type));
}
const handler = instance(provider).responseModes.get(mode);
await handler(ctx, safe(params.redirect_uri), out);
}
}
};
};