How to pass users actual address to NAM Identity Server when request coming in via Load Balancer or Proxy server



Most NAM setups involve a Load Balancer (LB) fronting either the Access Gateway or Identity Server nodes. When these Load Balancers are set up in SNAT / Proxy mode, the IP address of the incoming request will be that or the LB and not the users IP address. Any NAM decisions that perform an action based on the users IP address are therefor difficult or in some cases not possible.

The Access Gateway has the ability to do Authorization based on the value in the XFF header; the AG automatically appends the users XFF header info into the outgoing request sent to the Web server in case additional checks need to be made there.

The Identity Server has several features that leverage the IP address of the authenticating/authenticated users such as Kerberos challenge exclusion (ability to exclude certain IP addresses from executing contracts as with Kerberos fallback (, logging user IP addresses with audit events, role based evaluations, or even tracking session log files looking for user specific information. The IDP unfortunately does not have any checks to parse the XFF header like the AG does, making it more difficult.

Assuming that the LB can inject the X-Forwarded-For HTTP header into requests forwarded to the Identity Server or Access Gateway, there are some external options that may be possible to retrieve the users IP address. This document will outline how the tomcat remoteip filter can be used to help rewrite the incoming IP address of the user request, to the actual user IP address.


This tomcat remoteip filter ( replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. "X-Forwarded-For").

When enabled, the filter simply scans for the X-Forwarded-For HTTP header in the incoming request and replaces it's internal IP address structures with that IP address and not the actual IP address the request came in from (which would be the LB or Proxy address).

To enable the filter with NAM 4.1 Identity Server, modify the /opt/novell/nids/lib/webapp/WEB-INF/web.xml file and add the following information (replace the LB IP address with your IP address and make sure that the LB can inject the XFF header)

# /opt/novell/nids/lib/webapp/WEB-INF/web.xml
<!-- ================================================= Neil - rewrite XFF header to IP Address - LB IP address is ================================================== -->

The filter does the IP address check before the IDP does, and rewrites the IP address info before passing it to IDP to have tomcat retrieve the client IP address. If the IDP is simply calling request.remoteAddr to retrieve the IP address of the incoming request, then we will have the actual client ip address from the XFF headet returned and not the Load Balancer IP address from where the request came in. In the case of the Kerberos exclude feature above, you could add the users internal subnet to the include list, and anything else outside of that would automatically fallback to another authentication method.

Here's an example of the type of request that would come into the IDP server from the LB when the filter kicks in. To simulate the setup, one could install the 'Modify Headers' Firefox add on, and add the XFF header as shown below.


When accessing my IDP server from this Firefox instance for testing purposes, the XFF header gets added so that the complete headers seen in the incoming request are shows below (can see XFF header - users actual IP address - added with the value that I added into the Modify Headers plugin:

GET /nidp/ HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0
Accept: text/html,application/xhtml xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive

The actual page that gets rendered is identical ie. users will see no difference. For the sake of testing and validating the users IP address, I added the following two lines to the default login.jsp page

String sIPAddress = (String)request.getRemoteAddr();
out.println("************************ LOGIN.JSP Source IP Address: " sIPAddress);

The resulting login page shows the users IP address in red box below, along with the series of HTTP requests generated


Looking at this incoming HTTP request on the IDP server logs (/var/opt/novell/nam/logs/idp/tomcat/catalina.out) in debug mode, we can see that the 'Remote Client IP Address' is rewritten to be ie. the actual users IP address behind the LB.

<amLogEntry> 2015-08-24T17:48:22Z DEBUG NIDS Application:
Method: NIDPProxyableServlet.myDoGetWithProxy
Thread: ajp-bio-
****** HttpServletRequest Information:
Method: POST
Scheme: https
Context Path: /nidp
Servlet Path: /app
Query String: sid=0&sid=0
Path Info: /login
Server Name:
Server Port: 443
Content Length: 57
Content Type: application/x-www-form-urlencoded
Auth Type: null
Request URL:
Host IP Address:
Remote Client IP Address:
Cookie: (0 of 21): JSESSIONID, E16877A3EDE276C80F4E0249FDC8F2C9
Cookie: (1 of 21): __utma, 47136440.1622976940.1409914128.1438695959.1439985824.15
Cookie: (2 of 21): __utmz, 47136440.1409914128.1.1.utmcsr
Header: Name: x-forwarded-for, Value:
Header: Name: connection, Value: keep-alive
Session Id: 39B02761296FF6AFECC92824FA74403F
<amLogEntry> 2015-08-24T17:48:23Z INFO NIDS Application: Event Id: 3014666, Target: cn=basti,ou=sa,o=system, Sub-Target: 39B02761296FF6AFECC92824FA74403F, Note 1: Local, Note 2: Secure Name/Password - Form, Note 3: secure/name/password/uri, Numeric 1: 0, Data: </amLogEntry>

Assuming that we are auditing the user login events, the event triggered with this login is the following, again confirming the users actual IP address is logged.

[Tue, 24 Aug 2015 17:48:24  0000]  [Novell Access Manager\nidp]: AMDEVICEID#DB7471BE99DE2C40: AMAUTHID#6749352DD9BA4274EEE5ADFFA687E8DD: User session was authenticated: [cn=basti,o=novell]. Authentication Type: [Local] Authenticating Entity Name: [Secure Name/Password - Form] Contract Class or Method Name: [secure/name/password/uri] Source IP Address: []


How To-Best Practice
Comment List
  •   in reply to MigrationDeletedUser
    thanks for sharing this Dan!
  •   in reply to MigrationDeletedUser
    Apache requires this to be set and you cannot disable it by default. With NAM 4.1 SP2 (and in upcoming 4.2 SP1), we have an advanced option to disable it. When the advanced option "NAGAddProxyHeader off" is set the X-Forwarded headers are not sent to the backend web server.

    The value should always be forwarded, and the easiest way to check is to enable the following advanced options on the AG (to dunmp the httpheaders from browser to AG and AG to web server)

    DumpHeaders on
    DumpResponseHeaders on
    DumpHeadersFacility local6
    DumpResponseHeadersFacility local6

    and then look at contents of /var/log/novell-apache2/httpheaders file.
    On the access gateway appliance the Enable X-Forwarded-For option appears to be forced on as it is checked and you cannot uncheck it. However it appears that the value is not forwarded. Is there additional configuration required to enable this on the MAG? Looking at the live-http-headers trace I don't see the value in the header at all.
    Just as a FYI for those having issues, I had a TCP load balancer in front of my Identity Servers, which doesn't have the capability to manipulate the header to include an XFF header.

    I had to change the configuration to a HTTPS load balancer and use SSL termination to get this working.
    I got you. Not sure how the double filter close got in there but will work with the publisher to clear that up.

    Thanks a lot, Neil
  •   in reply to burlandp01
    good to hear it's of use ... can you be more specific on the strings you had to remove to get it working? I wonder whether you were testing on another version, and that is why you had to make changes?
  •   in reply to MigrationDeletedUser
    Sorry, the tags removed the string I put between 'extra' and 'in' on my first post.
    The code section above contains 2 lines with the close - 'slash filter'.
    Fantastic. I've wanted this for ages !

    Note. I had to remove the spurious extra in the example to get it to work.