UNPKG

oidc-provider

Version:

OAuth 2.0 Authorization Server implementation for Node.js with OpenID Connect

201 lines (182 loc) 10.4 kB
import noCache from '../../shared/no_cache.js'; import bodyParser from '../../shared/conditional_body.js'; import rejectDupes from '../../shared/reject_dupes.js'; import paramsMiddleware from '../../shared/assemble_params.js'; import sessionMiddleware from '../../shared/session.js'; import instance from '../../helpers/weak_cache.js'; import { PARAM_LIST } from '../../consts/index.js'; import checkRar from '../../shared/check_rar.js'; import checkResource from '../../shared/check_resource.js'; import getClientAuth from '../../shared/client_auth.js'; import checkClient from './check_client.js'; import checkResponseMode from './check_response_mode.js'; import rejectUnsupported from './reject_unsupported.js'; import rejectRegistration from './reject_registration.js'; import oauthRequired from './oauth_required.js'; import oneRedirectUriClients from './one_redirect_uri_clients.js'; import loadPushedAuthorizationRequest from './load_pushed_authorization_request.js'; import processRequestObject from './process_request_object.js'; import oidcRequired from './oidc_required.js'; import cibaRequired from './ciba_required.js'; import checkPrompt from './check_prompt.js'; import checkMaxAge from './check_max_age.js'; import checkIdTokenHint from './check_id_token_hint.js'; import checkScope from './check_scope.js'; import checkResponseType from './check_response_type.js'; import checkRedirectUri from './check_redirect_uri.js'; import assignDefaults from './assign_defaults.js'; import checkClaims from './check_claims.js'; import assignClaims from './assign_claims.js'; import loadAccount from './load_account.js'; import loadGrant from './load_grant.js'; import interactions from './interactions.js'; import respond from './respond.js'; import checkPKCE from './check_pkce.js'; import interactionEmit from './interaction_emit.js'; import getResume from './resume.js'; import checkClientGrantType from './check_client_grant_type.js'; import checkOpenidScope from './check_openid_scope.js'; import deviceAuthorizationResponse from './device_authorization_response.js'; import authenticatedClientId from './authenticated_client_id.js'; import deviceUserFlow from './device_user_flow.js'; import deviceUserFlowErrors from './device_user_flow_errors.js'; import deviceUserFlowResponse from './device_user_flow_response.js'; import pushedAuthorizationRequestRemapErrors from './pushed_authorization_request_remap_errors.js'; import backchannelRequestRemapErrors from './backchannel_request_remap_errors.js'; import stripOutsideJarParams from './strip_outside_jar_params.js'; import pushedAuthorizationRequestResponse from './pushed_authorization_request_response.js'; import cibaLoadAccount from './ciba_load_account.js'; import checkRequestedExpiry from './check_requested_expiry.js'; import backchannelRequestResponse from './backchannel_request_response.js'; import checkCibaContext from './check_ciba_context.js'; import checkDpopJkt from './check_dpop_jkt.js'; import checkExtraParams from './check_extra_params.js'; import unsupportedRar from './unsupported_rar.js'; const A = 'authorization'; const R = 'resume'; const DA = 'device_authorization'; const CV = 'code_verification'; const DR = 'device_resume'; const PAR = 'pushed_authorization_request'; const BA = 'backchannel_authentication'; const authRequired = new Set([DA, PAR, BA]); const parseBody = bodyParser.bind(undefined, 'application/x-www-form-urlencoded'); export default function authorizationAction(provider, endpoint) { const { features: { claimsParameter, dPoP, resourceIndicators, richAuthorizationRequests, webMessageResponseMode, }, extraParams, } = instance(provider).configuration; const allowList = new Set(PARAM_LIST); if (webMessageResponseMode.enabled) { allowList.add('web_message_uri'); // adding it just so that it can be rejected when detected } if (claimsParameter.enabled) { allowList.add('claims'); } let rejectDupesMiddleware = rejectDupes.bind(undefined, {}); if (resourceIndicators.enabled) { allowList.add('resource'); rejectDupesMiddleware = rejectDupes.bind(undefined, { except: new Set(['resource']) }); } if (richAuthorizationRequests.enabled) { allowList.add('authorization_details'); } extraParams.forEach(Set.prototype.add.bind(allowList)); if ([DA, CV, DR, BA].includes(endpoint)) { allowList.delete('web_message_uri'); allowList.delete('response_type'); allowList.delete('response_mode'); allowList.delete('code_challenge_method'); allowList.delete('code_challenge'); allowList.delete('state'); allowList.delete('redirect_uri'); allowList.delete('prompt'); } if (endpoint === BA) { allowList.add('client_notification_token'); allowList.add('login_hint_token'); allowList.add('binding_message'); allowList.add('user_code'); allowList.add('request_context'); allowList.add('requested_expiry'); } if (dPoP && [A, R, PAR].includes(endpoint)) { allowList.add('dpop_jkt'); } const stack = []; const use = (middleware, ...only) => { if (only.includes(endpoint)) { stack.push(middleware()); } }; const returnTo = /^(code|device)_/.test(endpoint) ? 'device_resume' : 'resume'; /* eslint-disable no-multi-spaces, space-in-parens, function-paren-newline */ use(() => noCache, A, DA, R, CV, DR, PAR, BA); use(() => sessionMiddleware, A, R, DR ); use(() => deviceUserFlowErrors, CV, DR ); use(() => getResume.bind(undefined, allowList, returnTo), R, DR ); use(() => deviceUserFlow.bind(undefined, allowList), CV, DR ); use(() => parseBody, A, DA, PAR, BA); if (authRequired.has(endpoint)) { const { params: authParams, middleware: clientAuth } = getClientAuth(provider); use(() => paramsMiddleware.bind(undefined, authParams), DA, PAR, BA); for (const clientAuthMiddlware of clientAuth) { use(() => clientAuthMiddlware, DA, PAR, BA); } } use(() => authenticatedClientId, DA, BA); use(() => paramsMiddleware.bind(undefined, allowList), A, DA, PAR, BA); use(() => rejectDupesMiddleware, A, DA, PAR, BA); use(() => rejectUnsupported, A, DA, PAR, BA); use(() => stripOutsideJarParams, PAR, BA); use(() => checkClient, A, DA, R, CV, DR ); use(() => checkClientGrantType, DA, BA); use(() => pushedAuthorizationRequestRemapErrors, PAR ); use(() => backchannelRequestRemapErrors, BA); use(() => loadPushedAuthorizationRequest, A ); use(() => processRequestObject.bind( undefined, allowList, rejectDupesMiddleware, ), A, DA, PAR, BA); use(() => checkResponseMode, A, PAR ); use(() => oneRedirectUriClients, A, PAR ); use(() => oauthRequired, A, PAR ); use(() => rejectRegistration, A, DA, PAR, BA); use(() => checkResponseType, A, PAR ); use(() => oidcRequired, A, PAR ); use(() => cibaRequired, BA); use(() => assignDefaults, A, DA, BA); use(() => checkPrompt, A, PAR ); use(() => checkScope.bind(undefined, allowList), A, DA, PAR, BA); use(() => checkOpenidScope.bind(undefined, allowList), A, DA, PAR, BA); use(() => checkRedirectUri, A, PAR ); use(() => checkPKCE, A, PAR ); use(() => checkClaims, A, DA, PAR, BA); use(() => unsupportedRar, DA, BA); use(() => checkRar, A, PAR ); use(() => checkResource, A, DA, R, CV, DR, PAR, BA); use(() => checkMaxAge, A, DA, PAR, BA); use(() => checkRequestedExpiry, BA); use(() => checkCibaContext, BA); use(() => checkIdTokenHint, A, DA, PAR ); use(() => checkDpopJkt, PAR ); use(() => checkExtraParams, A, DA, PAR, BA); use(() => interactionEmit, A, R, CV, DR ); use(() => assignClaims, A, R, CV, DR, BA); use(() => cibaLoadAccount, BA); use(() => loadAccount, A, R, CV, DR ); use(() => loadGrant, A, R, CV, DR ); use(() => interactions.bind(undefined, returnTo), A, R, CV, DR ); use(() => respond, A, R ); use(() => deviceAuthorizationResponse, DA ); use(() => deviceUserFlowResponse, CV, DR ); use(() => pushedAuthorizationRequestResponse, PAR ); use(() => backchannelRequestResponse, BA); /* eslint-enable no-multi-spaces, space-in-parens, function-paren-newline */ return stack; }