@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
JavaScript
;
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);
}
});
};