hosted target nodejs request object headers undefined

Hi,

I am using the hosted target node js proxy in that my index.js has code to returns the token.

var svr = http.createServer(function(req, resp) {

my logic goes here........

svr.listen(9000, function() { console.log('Node HTTP server is listening 9000'); });

I am using another proxy and making a service-callout to the above hosted target proxy and this returns me a 500 error response(See below). and noticed that the request i.e. req object has headers values undefined.

when i check runtime logs it seems like whole request i.e. req not having any values. However the curl (Request sent to target server) has got all correct request values and target server being 'http://localhost'

appreciate if anyone can look into the above problem please.

500 error response
<html><head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title>500 Server Error</title> </head> <body text=#000000 bgcolor=#ffffff> <h1>Error: Server Error</h1> <h2>The server encountered an error and could not complete your request.<p>Please try <h2></h2> </body></html>

0 11 2,291
11 REPLIES 11

Per the doc for hosted targets, you must use process.env.PORT, and you cannot just allow your code to listen on an arbitrary port.

Therefore,

var svr = http.createServer(function(req, resp) {
  // request handling logic goes here...
 });

svr.listen(process.env.PORT || 9000, function() {
  console.log('Node HTTP server is listening, port ' + svr.address().port); 
});


Hi,

I updated the code as per above but still not working and my request i.e. req object have null values..

from below logs the username, password and other fields i am passing in headers but their values coming as undefined.

see the run time logs:

npm ERR! Exit status 1

npm ERR!

npm ERR! Failed at the hostedtarget@1.0.0 start script.

npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

throw new Error('The authority url must be an https endpoint.');

^

at Server.<anonymous> (/index.js:62:19)

at emitTwo (events.js:126:13)

at Server.emit (events.js:214:7)

{ 'user-agent': 'Wget/1.18 (linux-musl)',

accept: '*/*',

'accept-encoding': 'identity',

host: '169.254.8.129:9000',

connection: 'Keep-Alive' }

{"user-agent":"Wget/1.18 (linux-musl)","accept":"*/*","accept-encoding":"identity","host":"169.254.8.129:9000","connection":"Keep-Alive"}

{

username: undefined,

password: undefined,

clientsecret: undefined,

granttype: undefined,

resource: undefined }

undefined

undefined

Node HTTP server is listening

node.js application starting...

npm ERR! code ELIFECYCLE

npm ERR! errno 1

> hostedtarget@1.0.0 start /

> node index.js

We're unable to reproduce this on our end using a service callout to a hosted target proxy. Can you verify that your hosted target code works locally? It looks like you're throwing an exception at line 62.

Are you using https://github.com/AzureAD/azure-activedirectory-library-for-nodejs ?

I found the error phrase, "The authority url must be an https endpoint" in that library.

From what I can see, it seems like you're using that library incorrectly.

I'll second Josh's suggestion: Maybe try running your nodejs code outside of Apigee Edge to sort that out.

Hi,

let me giving you more clarity to the nature of my issue.I am using adal-node to generate the adfs token.

1. I have tested the nodejs code in vscode editor this has works fine and got the expected output.

2. I have even tested this code in APIGEE hosted target by hard coding the variable objects like username,password, clientid, resource etc. this has works fine got the expected response.

The above two points indicate that there is nothing wrong in the node js code.

I am using service call-out and in that passing all required values like username,password, clientid, resource, authority etc. in the headers.

When a service-callout hit the hosted target proxy somehow the request object values are null i.e. undefined including the headers and hence AuthenticationContext is failed

I am experiencing same issue even if calling from the rest client.

Any idea why the request object is coming as null ????

my package.json file:

{

"name": "hostedtarget",

"version": "1.0.0",

"main": "index.js",

"scripts": {

"start": "node index.js"

},

"author": "",

"license": "ISC",

"description": "",

"dependencies": {

"adal-node": "^0.1.28"

}

}

my app.yaml:

runtime: node

runtimeVersion: 8

env:

- name: NODE_ENV

value: dev

- name: LOG_LEVEL

value: 3

Oh thanks for the context.

From the error message you posted earlier, it appears that adal-node is throwing an Error, based on a call you made to the library in line 62 of index.js.

You haven't showed what that line is.

I think it would be a good idea to eliminate the servicecallout part of the solution, just to be able to isolate the issue you're dealing with here. The issue is in your nodejs code, and it appears your code is making an assumption that is incorrect. It is passing something incorrect to adal-node.

you wrote

I have tested the nodejs code in vscode editor this has works fine and got the expected output.

But the key thing is to run the nodejs code as a server, and invoke it with a curl or wget. Have you done that? Run the exact code that you have configured to ruin as the hosted target.

I attempted to reproduce this issue using the following proxies:


A hosted target with the following index.js:

var http = require('http');


console.log('node.js application starting...');
console.log(process.env);


var svr = http.createServer(function(req, resp) {
  console.log(req.headers);
  resp.setHeader("Content-Type", "application/json");
  resp.end("Hello World!");
});


svr.listen(process.env.PORT || 3000, function() {
  console.log('Node HTTP server is listening');
});

And a separate no target proxy with a service callout of:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="Service-Callout-1">
    <DisplayName>Service Callout-1</DisplayName>
    <Properties/>
    <Request clearPayload="true" variable="myRequest">
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
        <Set>
            <Headers>
                <Header name="testHeader1">value1</Header>
                <Header name="testHeader2">value2</Header>
            </Headers>
        </Set>
    </Request>
    <Response>calloutResponse</Response>
    <HTTPTargetConnection>
        <URL>http://apigee-hf-testing-test.apigee.net/josh-hf-test1</URL>
    </HTTPTargetConnection>
</ServiceCallout>

I've verified that I get the correct headers through my runtime logs:

Feb 1, 2019 1:28:56 PMstdoutsvr.0{ host: '169.254.8.129:9000',
Feb 1, 2019 1:28:56 PMstdoutsvr.0connection: 'close',
Feb 1, 2019 1:28:56 PMstdoutsvr.0'x-forwarded-for': '54.148.126.54',
Feb 1, 2019 1:28:56 PMstdoutsvr.0'x-forwarded-port': '80',
Feb 1, 2019 1:28:56 PMstdoutsvr.0'x-forwarded-proto': 'https',
Feb 1, 2019 1:28:56 PMstdoutsvr.0testheader1: 'value1',
Feb 1, 2019 1:28:56 PMstdoutsvr.0testheader2: 'value2',

The only thing I can think of is it you're using invalid header names, such as ones using underscores(_) as those will be stripped.

Hi ben,

see below my service call-out to an hosted target proxy /hellonode2 appreciate if you can figure out what wrong i might be doing in the SC policy.

i noticed above you were using <HTTPTargetConnection> whereas i am using proxy base path.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="Service-Callout-JS">
    <DisplayName>Service Callout-JS</DisplayName>
    <Properties/>
    <Request clearPayload="true" variable="myRequest">
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
        <Set>
            <Headers>
                  <Header name="tenant">"value1 "</Header>
                <Header name="authorityhosturl">"value2"</Header>
                <Header name="clientid">"value3 "</Header>
                <Header name="username">"value4"</Header>
                <Header name="password">"value5"</Header>
                <Header name="clientsecret">"value6"</Header>
                <Header name="resource">"value7"</Header>
                <Header name="granttype">"value8"</Header>
            </Headers>
           
        </Set>
	 <Verb>GET</Verb>
    </Request>
    <Response>calloutResponse</Response>
    <LocalTargetConnection>
        <Path>/hellonode2</Path>
    </LocalTargetConnection>
</ServiceCallout>


1. Show us your nodejs code

2. I think you told us that the same problem occurs when you call the hosted target from curl. That means it's not the ServiceCallout.

Hi,

For some security reason i cannot provide you the complete index.js code but you can see the below code in which my request object req always carrying null headers values as undefined...

var adal = require('adal-node');
var fs = require('fs');
var https = require('https');
var http = require('http');
var AuthenticationContext = adal.AuthenticationContext;


http.globalAgent.maxSockets = Infinity;
 
function turnOnLogging() {
    var log = adal.Logging;
    log.setLoggingOptions(
    {
      level : log.LOGGING_LEVEL.VERBOSE,
      log : function(level, message, error) {
        console.log(message);
        if (error) {
          console.log(error);
        }
      }
    });
  }
  
  turnOnLogging();
  console.log('node.js application starting...');
  
var svr = http.createServer(function(req, resp) {
    //const { headers, method, url } = req;
    var headers = req.headers;
    console.log(headers); // in runtime logs all headers value are undefined
	    
});
svr.listen(process.env.PORT || 4000, function() {
  console.log('Node HTTP server is listening');
});

I don't know what the problem is. The following nodejs code works for me.

/* global process */
const http = require('http');
http.globalAgent.maxSockets = Infinity;
process.on('exit', function (code) {
   console.log('Script terminating with code %s', code);
});
process.on('uncaughtException', function (err) {
    console.log(err.stack);
});
const svr = http.createServer(function(req, resp) {
      console.log("%s %s\n", req.method, req.url);
      console.log('headers: ' + JSON.stringify(req.headers));
      resp.end(JSON.stringify({
        date: (new Date()).toISOString(),
        response: 'Hello, World!',
        requestHeaders: req.headers
      }, null, 2));
    });
console.log('node.js application starting...');
svr.listen(process.env.PORT || 4000, function() {
  console.log('Node HTTP server is listening');
});

When I invoke it like this:

curl -i https://$ORG-$ENV.apigee.net/abdulheaders/foo -H "x-novel-header: 72" 

I get this response:

{
  "date": "2019-02-04T21:07:47.585Z",
  "response": "Hello, World!",
  "requestHeaders": {
    "host": "169.254.8.129:9000",
    "connection": "close",
    "x-forwarded-for": "104.154.179.1",
    "x-forwarded-port": "443",
    "x-forwarded-proto": "https",
    "user-agent": "curl/7.61.1",
    "accept": "*/*",
    "x-novel-header": "72",
    "x-appengine-request-log-id": "5c58a9a100ff0e2c31fbb215ed0001737e766169767437667467796d6a71347768666a6c6b7462793837357a346c64000139336236643430333a3238326131633265000100",
    "x-appengine-default-version-hostname": "vaivt7ftgymjq4whfjlktby875z4ld.appspot.com"
  }
}

Maybe you need to simplify the code, and add in one thing at a time. I don't know the adal-node module, and I'm not familiar with the logging thing you've got there. Also it looks like you have no response being sent by your request handler. ?

Anyway, with something as basic as "my code doesn't see request headers", my suggestion is to start with something that is known to work, and then step-by-step add pieces and evolve it to get to where you want to be.