UNPKG

@sap/xsodata

Version:

Expose data from a HANA database as OData V2 service with help of .xsodata files.

75 lines (60 loc) 3.02 kB
"use strict"; var BadRequestError = require("../utils/errors/http/badRequest"); var xsenv = require('@sap/xsenv'); var xssec = require("@sap/xssec"); /** * Validates and extracts the authorization token from OData context without prefixes. * According to RFC-6750, the HTTP request's authorization header must look like: * "Bearer <JWT-Token>". * @param context {Object} The OData context of the framework. * @returns {string} "<JWT-Token>". */ exports.getAuthToken = function getAuthToken(context) { const authorizationHeader = context.request.headers.Authorization || context.request.headers.authorization; if (!authorizationHeader) { throw new BadRequestError("Missing Authorization request header", context); } // see RFC6750, section 2.1, correct bearer header parsing const matches = authorizationHeader.match(/^(?:bearer)(?:\s)+(.*)$/i); if (matches === null || matches.length !== 2) { throw new BadRequestError("Bad Authorization request header", context); } return matches[1]; }; /** * Checks the collected scopes against the given token. It uses the xssec module to check the scopes * one by one. A scope name must be given in the xsodata corresponding file WITHOUT the app name, because * checkLocalScope appends the app name automatically. * @param token {string} Authorization token extracted from the HTTP header. * @param scopes {Array<String>} Collection of scopes from all strategies. * @param callback {Function} Callback to be called when scopes checks are done. */ exports.checkScopes = function checkScopes(context, token, scopes, callback) { // The UAA service is read (using xsenv module) from the default-services.json file at root-dir var uaaService = xsenv.getServices({ uaa: { tag: 'xsuaa' } }).uaa || xsenv.getServices({ uaa: 'uaa' }).uaa; xssec.createSecurityContext(token, uaaService, function (err, externalSecurityContext) { if (err) { context.securityContext = externalSecurityContext; return context.callRegisteredStep(9, 'CreateSecurityContext creation failed', context, () => { if (err === false) { // would interfere with async cancel water fall, error should be an error return new Error('Security context could not be created'); } return callback(err, null); }); } var isAuthorized = true; scopes.forEach(function (scope) { if (externalSecurityContext.checkLocalScope(scope) !== true) { isAuthorized = false; } }); if (!isAuthorized && context && context.callRegisteredStep) { context.securityContext = externalSecurityContext; return context.callRegisteredStep(9, 'Not Authorized (scope check failed)', context, () => { return callback(null, isAuthorized); }); } else { return callback(null, isAuthorized); } }); };