Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Relay Auth header via Query Params on Redirect #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"mime-types": "^2.1.35",
"mkdirp": "^0.5.5",
"node-forge": "^1.3.0",
"qs": "^6.12.0",
"semaphore": "^1.1.0",
"ua-parser-js": "^1.0.37",
"url": "^0.11.3",
Expand Down
78 changes: 51 additions & 27 deletions src/components/proxy-middleware/helpers/proxy_ctx_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
CONSTANTS as GLOBAL_CONSTANTS,
} from "@requestly/requestly-core"

import qs from 'qs';

function extractUrlComponent(url, name) { // need this in proxy
const myUrl = new URL(url);
Expand Down Expand Up @@ -37,38 +38,14 @@ function extractUrlComponent(url, name) { // need this in proxy
* @returns object { paramName -> [value1, value2] }
*/
export function getQueryParamsMap(queryString) {
var map = {},
queryParams;

if (!queryString || queryString === "?") {
return map;
}

if (queryString[0] === "?") {
queryString = queryString.substr(1);
}

queryParams = queryString.split("&");

queryParams.forEach(function (queryParam) {
var paramName = queryParam.split("=")[0],
paramValue = queryParam.split("=")[1];

// We are keeping value of param as array so that in future we can support multiple param values of same name
// And we do not want to lose the params if url already contains multiple params of same name
map[paramName] = map[paramName] || [];
map[paramName].push(paramValue);
});

return map;
return qs.parse(queryString, { ignoreQueryPrefix: true });
}


export const get_request_url = (ctx) => {
return (
(ctx.isSSL ? "https://" : "http://") +
ctx.clientToProxyRequest.headers.host +
ctx.clientToProxyRequest.url
ctx.proxyToServerRequestOptions.headers.host || ctx.proxyToServerRequestOptions.host +
ctx.proxyToServerRequestOptions.url
);
};

Expand Down Expand Up @@ -150,3 +127,50 @@ export const getResponseStatusCode = (ctx) => {
return ctx.serverToProxyResponse.statusCode;
}
};


const HEADERS_IGNORED_ON_REDIRECT = ["authorization"];
const CUSTOM_QUERY_PARAM_PREFIX = "x-rq-";

export function getExtraQueryParamsForRedirect(ctx) {
const customQueryParams = {};
HEADERS_IGNORED_ON_REDIRECT.forEach((ignoredHeader) => {
if(ctx.rq.original_request.headers[ignoredHeader]) {
const customQueryParamKey = `${CUSTOM_QUERY_PARAM_PREFIX}${ignoredHeader}`;
customQueryParams[customQueryParamKey] = ctx.rq.original_request.headers[ignoredHeader];
}
})
return customQueryParams;
}

function extractDataFromRQQueryParams(ctx) {
const metaData = {};
const queryParams = get_json_query_params(ctx);
for (const param in queryParams) {
if (param.startsWith(CUSTOM_QUERY_PARAM_PREFIX)) {
const key = param.substring(CUSTOM_QUERY_PARAM_PREFIX.length);
metaData[key] = queryParams[param]
delete queryParams[param];
}
}

const newUrl = new URL(get_request_url(ctx));
for (const [key, value] of Object.entries(queryParams)) {
newUrl.searchParams.set(key, value);
}

ctx.proxyToServerRequestOptions.path = newUrl.pathname;
ctx.proxyToServerRequestOptions.url = newUrl.toString();

ctx.rq.set_original_request({ path: newUrl.pathname, query_params: queryParams });
}

export function handleRQMetadataInQueryParam(ctx) {
const headersToBeAddedToRequest = extractDataFromRQQueryParams(ctx);
if (headersToBeAddedToRequest) {
for (const [name, value] in Object.entries(headersToBeAddedToRequest)) {
ctx.proxyToServerRequestOptions.headers[name] = value;
}
}
ctx.rq.set_original_request({ headers: ctx.proxyToServerRequestOptions.headers });
}
6 changes: 4 additions & 2 deletions src/components/proxy-middleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
getResponseHeaders,
getResponseStatusCode,
get_request_options,
get_request_url,
get_response_options,
handleRQMetadataInQueryParam,
} from "./helpers/proxy_ctx_helper";

import RulesMiddleware from "./middlewares/rules_middleware";
Expand Down Expand Up @@ -124,6 +124,9 @@ class ProxyMiddlewareManager {
ctx.rq = new CtxRQNamespace();
ctx.rq.set_original_request(get_request_options(ctx));
ctx.proxyToServerRequestOptions.rejectUnauthorized = false;

handleRQMetadataInQueryParam(ctx);

// Figure out a way to enable/disable middleware dynamically
// instead of re-initing this again
const rules_middleware = new RulesMiddleware(
Expand Down Expand Up @@ -179,7 +182,6 @@ class ProxyMiddlewareManager {
const contentType = getContentType(contentTypeHeader);
const parsedBody = bodyParser(contentTypeHeader, body);

// Request body before any modifications
let pre_final_body = parsedBody || body.toString("utf8");
ctx.rq.set_original_request({ body: pre_final_body });
ctx.rq_request_body = pre_final_body;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PROXY_HANDLER_TYPE } from "../../../../lib/proxy";
import {
getExtraQueryParamsForRedirect,
get_request_url,
is_request_preflight,
} from "../../helpers/proxy_ctx_helper";
Expand Down Expand Up @@ -28,7 +29,17 @@ const process_redirect_action = async (action, ctx) => {
}

const current_url = get_request_url(ctx);
const new_url = action.url;
let new_url = action.url;

// Sending back authorization header in query param for new location
const extraQueryParams = getExtraQueryParamsForRedirect(ctx);
if (extraQueryParams) {
const url = new URL(new_url);
for (const [key, value] of Object.entries(extraQueryParams)) {
url.searchParams.set(key, value);
}
new_url = url.toString();
}

const request_url = current_url.replace(/www\./g, "");

Expand Down