PingAccess issues with proxying target sites with HTTP/HTTPS mix - ssl

I'm trying to get PingAccess set up as a proxy (let's call the PA host
pagateway) for a couple of applications that share a Web Session. I want all access to come via the PA pagateway and use HTTPS, but the back end systems are not HTTPS.
I have two sites defined, app1:8080 and app2:8080. Both are set to "secure" = no and "use target host header" = yes.
I have listeners defined on ports 5000 and 5001 that are both set to "secure" = yes.
The first problem I found is that when I access either app in this way (e.g. going to https://pagateway:5000), after successfully authenticating with PingFederate I end up getting redirected to the actual underlying host name (e.g. http://app1:8080), meaning any subsequent interactions with the app are not via PingAccess. For users outside the network they wouldn't even be able to do that because the app1 host wouldn't even be visible or accessible.
I thought maybe I needed to turn off "Use target host header" to false but Chrome prompts me to download a file that contains NAK, ETX, ETX, NUL, STX, STX codes, and in the PA logs I get an SSL error:
2015-11-20 11:13:33,718 DEBUG [6a5KYac2dnnY0ZpIl-3GNA] com.pingidentity.pa.core.transport.http.HttpServerHandler:180 - IOException reading sourceSocket
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.InputRecord.handleUnknownRecord(InputRecord.java:710)
...
I'm unsure exactly which part of the process the SSL error is coming from (between browser and pagateway, or pagateway and app1). I'm guessing maybe app1 is having trouble with the unexpected host header...
In another variation I turned off SSL on the PA listener (I also had to change the PingAccess call-back URL in the PingFederate client settings to be http). But when I accessed it via http://pagateway:5000 I got a generic PingFederate error message in the browser and a different error in the PA logs:
2015-11-20 11:37:25,764 DEBUG [DBxHnFjViCgLYgYb-IrfqQ] com.pingidentity.pa.core.interceptor.flow.InterceptorFlowController:148 - Invoking request handler: Scheme Validation for Request to [pagateway:5000] [/]
2015-11-20 11:37:25,764 DEBUG [DBxHnFjViCgLYgYb-IrfqQ] com.pingidentity.pa.core.interceptor.flow.InterceptorFlowController:200 - Exception caught. Invoking abort handlers
com.pingidentity.pa.sdk.policy.AccessException: Invalid request protocol.
at com.pingidentity.pa.core.interceptor.SchemeValidationInterceptor.handleRequest(SchemeValidationInterceptor.java:61)
Does anyone have any idea what I'm doing wrong? I'm kind of surprised about the redirection to the actual server name, to be honest, but after that I'm stumped about where to go from here.
Any help would be appreciated.

Have you contacted our support on this? It's sounding like something that will need to be dug into a bit deeper - but some high level suggestions I can make:
Take a look at a browser trace to determine when the redirect is happening to the backend site. Usually this is because there's a Location header in a redirect from the backend web server that (by nature) is an absolute URL but pointing to it instead of the externally facing hostname.
A common solution to this is setting Target Host Header to False - so it will receive the request unmodified from the browser, and the backend server should know to represent itself as that (if it behaves nicely behind a proxy).
If the backend server can't do that (which it sounds like it can't) - you should look at assigning rewriting rules to that application. More details on them are available here: https://support.pingidentity.com/s/document-item?bundleId=pingaccess-52&topicId=reference%2Fui%2Fpa_c_Rewrite_Rules_Overview.html. The "Rewrite Response Header Rule" in particular will rewrite Location headers in HTTP redirects.
FYI - The "Invalid request protocol." error you're seeing at bottom of your description could be due to a "Require HTTPS" flag on your defined Application.

Do you have the same issue if you add a trailing slash at the end (https://pagateway:5000/webapp/)? Your application server will rewrite the URL based on what it thinks is the true host. This is to get around some security related issues around directory listing.
Which application server are you using? All app servers are unique, but I'll provide instructions on how to resolve this with Tomcat.
Add a global rule that forces the application server to use the external facing host name. Here is a sample Groovy script:
def header = exc?.request?.header;
header?.setHost("pf.pingdemo.com:443");
anything();
In Tomcat's server.xml, add scheme="https" to the connection:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" scheme="https" />
Cheers,
Tam

Related

How to fix SimpleSAMLphp "url not allowed" error

Folks,
sometimes our users get an exception presented by SimpleSAMLphp about "URL not allowed". The error is not reproducable for me. Wetherthe in development-environment or in production-environment I can force the system into this error. But it happens.
Investigating, I found in our syslog:
Feb 01 19:55:51 pweb simplesamlphp[25416]: 3 [061b91b3c6] Caused by: SimpleSAML\Error\Exception: URL not allowed: https://10.1.2.102/
Feb 01 22:22:53 pweb simplesamlphp[26347]: 3 [be1715d03f] Caused by: SimpleSAML\Error\Exception: URL not allowed: https://10.1.2.102/
The IP 10.1.2.102 is the IP of the webserver.
In front of our webserver we have a reverse proxy (apache2), which passes all request from the internet to https://10.1.2.102 .
All I found about this error was to put the IP into config.php "trusted.url.domains". But this doesn't look correct to me. "trusted.url.domains" is for IDP-addresses only, I think.
Do you have a hint for me?
trusted.url.domains is for any redirects that SimpleSAML may perform. So it's really indeed about URL domains, not limited e.g. to IdPs.
The question is whether it works fine in your setup if SimpleSAML would redirect the user to https://10.1.2.102/ - that private IP will not work for them. But maybe your reverse proxy translates it back? If that is the case, you should be fine with adding the IP to trusted.url.domains.

HaProxy Transparent Proxy To AWS S3 Static Website Page

I am using haproxy to balance a cluster of servers. I am attempting to add a maintenance page to the haproxy configuration. I believe I can do this by defining a server declaration in the backend with the 'backup' modifier. Question I have is, how can I use a maintenance page hosted remotely on AWS S3 bucket (static website) without actually redirecting the user to that page (i.e. the haproxy server 'redir' definition).
If I have servers: a, b, c. All servers go down for maintenance then I want all requests to be resolved by server definition d (which is labeled with 'backup') to a static address on S3. Note, that I don't want paths to carry over and be evaluated on s3, it should always render the static maintenance page.
This is definitely possible.
First, declare a backup server, which will only be used if the non-backup servers are down.
server s3-fallback example.com.s3-website-us-east-1.amazonaws.com:80 backup
The following configuration entries are used to modify the request or the response only if we're using the alternate path. We're using two tests in the following examples:
# { nbsrv le 1 } -- if the number of servers in this backend is <= 1
# (and)
# { srv_is_up(s3-fallback) } -- if the server named "s3-fallback" is up; "server name" is the arbitrary name we gave the server in the config file
# (which would mean it's the "1" server that is up for this backend)
So, now that we have a backup back-end, we need a couple of other directives.
Force the path to / regardless of the request path.
http-request set-path / if { nbsrv le 1 } { srv_is_up(s3-fallback) }
If you're using an essentially empty bucket with an error document, then this isn't really needed, since any request path would generate the same error.
Next, we need to set the Host: header in the outgoing request to match the name of the bucket. This isn't technically needed if the bucket is named the same as the Host: header that's already present in the request we received from the browser, but probably still a good idea. If the bucket name is different, it needs to go here.
http-request set-header host example.com if { nbsrv le 1 } { srv_is_up(s3-fallback) }
If the bucket name is not a valid DNS name, then you should include the entire web site endpoint here. For a bucket called "example" --
http-request set-header host example.s3-website-us-east-1.amazonaws.com if { nbsrv le 1 } { srv_is_up(s3-fallback) }
If your clients are sending you their cookies, there's no need to relay these to S3. If the clients are HTTPS and the S3 connection is HTTP, you definitely wat to strip these.
http-request del-header cookie if { nbsrv le 1 } { srv_is_up(s3-fallback) }
Now, handling the response...
You probably don't want browsers to cache the responses from this alternate back-end.
http-response set-header cache-control no-cache if { nbsrv le 1 } { srv_is_up(s3-fallback) }
You also probably don't want to return "200 OK" for these responses, since technically, you are displaying an error page, and you don't want search engines to try to index this stuff. Here, I've chosen "503 Service Unavailable" but any valid response code would work... 500 or 502, for example.
http-response set-status 503 if { nbsrv le 1 } { srv_is_up(s3-fallback) }
And, there you have it -- using an S3 bucket website endpoint as a backup backend, behaving no differently than any other backend. No browser redirect.
You could also configure the request to S3 to use HTTPS, but since you're just fetching static content, that seems unnecessary. If the browser is connecting to the proxy with HTTPS, that section of the connection will still be secure, although you do need to scrub anything sensitive from the browser's request, since it will be forwarded to S3 unencrypted (see "cookie," above).
This solution is tested on HAProxy 1.6.4.
Note that by default, the DNS lookup for the S3 endpoint will only be done when HAProxy is restarted. If that IP address changes, HAProxy will not see the change, without additional configuration -- which is outside the scope of this question, but see the resolvers section of the configuration manual.
I do use S3 as a back-end server behind HAProxy in several different systems, and I find this to be an excellent solution to a number of different issues.
However, there is a simpler way to have a custom error page for use when all the backends are down, if that's what you want.
errorfile 503 /etc/haproxy/errors/503.http
This directive is usually found in global configuration, but it's also valid in a backend -- so this raw file will be automatically returned by the proxy for any request that tries to use this back-end, if all of the servers in this back-end are unhealthy.
The file is a raw HTTP response. It's essentially just written out to the client as it exists on the disk, with zero processing, so you have to include the desired response headers, including Connection: close. Each line of the headers and the line after the headers must end with \r\n to be a valid HTTP response. You can also just copy one of the others, and modify it as needed.
These files are limited by the size of a response buffer, which I believe is tune.bufsize, which defaults to 16,384 bytes... so it's only really good for small files.
HTTP/1.0 503 Service Unavailable\r\n
Cache-Control: no-cache\r\n
Connection: close\r\n
Content-Type: text/plain\r\n
\r\n
This site is offline.
Finally, note that in spite of the fact that you're wanting to "transparently proxy a request," I don't think the phrase "transparent proxy" is the correct one for what you're trying to do, because a "transparent proxy" implies that either the client or the server or both would see each other's IP addresses on the connection and think they were communicating directly, with no proxy in between, because of some skullduggery done by the proxy and/or network infrastructure to conceal the proxy's existence in the path. This is not what you're looking for.

Failure to login to an Orbeon Forms application when using HTTPS

I have an Orbeon Forms v3.7.1 based application that fails when I try to login using HTTPS instead of HTTP.
I am using Apache as a proxy server connecting requests to a an application running on WebLogic 12.1.3. For various reasons, we recently had to migrate the Apache plugin module from mod_proxy to mod_weblogic.
For both modules, we have configured the module to map the incoming HTTPS requests to HTTP going to the WebLogic server. The main difference we noticed that seems to be causing the error is that the Referer header changed. When using the mod_proxy module, the Referer is listed as the Apache server using HTTP. When using the mod_weblogic module, the Referer is listed as the incoming Apache URL using HTTPS.
When using the mod_weblogic module, we get the following error in the Orbeon log when we try to login to the application. It seems to be failing while parsing the URL. Any ideas how to fix this problem?
Here is the exception listed in the orbeon log file:
2015-03-19 22:28:40,340 ERROR ProcessorService - Exception at line 20, column 46 of https://baseqa20151.delphi-tech.com:443/wl1213-test/baseqa20151/oasis2Portal/owsPortal/phs/get-navigation
org.orbeon.oxf.common.ValidationException: line 20, column 46 of https://baseqa20151.delphi-tech.com:443/wl1213-test/baseqa20151/oasis2Portal/owsPortal/phs/get-navigation: Fatal error: The entity name must immediately follow the '&' in the entity reference.
https://baseqa20151.delphi-tech.com:443/wl1213-test/baseqa20151/oasis2Portal/owsPortal/phs/get-navigation, line 20, column 46: Fatal error: The entity name must immediately follow the '&' in the entity reference.
at org.orbeon.oxf.xml.XMLUtils$ErrorHandler.fatalError(XMLUtils.java:306)
at orbeon.apache.xerces.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
at orbeon.apache.xerces.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:351)
at orbeon.apache.xerces.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:281)
at orbeon.apache.xerces.impl.XMLScanner.reportFatalError(XMLScanner.java:1459)
at orbeon.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEntityReference(XMLDocumentFragmentScannerImpl.java:1252)
at orbeon.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(XMLDocumentFragmentScannerImpl.java:1717)
at orbeon.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:324)
at orbeon.apache.xerces.parsers.XML11Configuration.parse(XML11Configuration.java:845)
at orbeon.apache.xerces.parsers.XML11Configuration.parse(XML11Configuration.java:768)
at orbeon.apache.xerces.parsers.XMLParser.parse(XMLParser.java:108)
at orbeon.apache.xerces.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1201)
at org.orbeon.oxf.xml.XMLUtils.inputSourceToSAX(XMLUtils.java:350)
at org.orbeon.oxf.xml.XMLUtils.inputStreamToSAX(XMLUtils.java:335)
at org.orbeon.oxf.processor.URIProcessorOutputImpl.readURLToStateIfNeeded(URIProcessorOutputImpl.java:394)
at org.orbeon.oxf.xforms.processor.XFormsURIResolver.resolve(XFormsURIResolver.java:86)
at org.orbeon.oxf.xforms.processor.XFormsURIResolver.readURLAsDocument(XFormsURIResolver.java:117)
at org.orbeon.oxf.xforms.XFormsModel.performDefaultAction(XFormsModel.java:660)
at org.orbeon.oxf.xforms.XFormsContainingDocument.dispatchEvent(XFormsContainingDocument.java:1283)
at org.orbeon.oxf.xforms.XFormsContainer.initializeModels(XFormsContainer.java:173)
at org.orbeon.oxf.xforms.XFormsContainingDocument.initialize(XFormsContainingDocument.java:1525)
at org.orbeon.oxf.xforms.XFormsContainingDocument.<init>(XFormsContainingDocument.java:181)
at org.orbeon.oxf.xforms.processor.XFormsToXHTML.createCacheContainingDocument(XFormsToXHTML.java:326)
at org.orbeon.oxf.xforms.processor.XFormsToXHTML.access$200(XFormsToXHTML.java:50)
at org.orbeon.oxf.xforms.processor.XFormsToXHTML$2.read(XFormsToXHTML.java:152)
at org.orbeon.oxf.processor.ProcessorImpl.readCacheInputAsObject(ProcessorImpl.java:453)
at org.orbeon.oxf.xforms.processor.XFormsToXHTML.doIt(XFormsToXHTML.java:121)
at org.orbeon.oxf.xforms.processor.XFormsToXHTML.access$000(XFormsToXHTML.java:50)
at org.orbeon.oxf.xforms.processor.XFormsToXHTML$1.readImpl(XFormsToXHTML.java:80)
at org.orbeon.oxf.processor.ProcessorImpl$6.read(ProcessorImpl.java:995)
at org.orbeon.oxf.processor.ProcessorImpl$ProcessorOutputImpl.read(ProcessorImpl.java:1178)
at org.orbeon.oxf.processor.ProcessorImpl.readInputAsSAX(ProcessorImpl.java:350)
at org.orbeon.oxf.processor.ProcessorImpl.readInputAsSAX(ProcessorImpl.java:355)
at org.orbeon.oxf.processor.xinclude.XIncludeProcessor.access$100(XIncludeProcessor.java:41)
...
and here is the log record from the HTTP access.log file for this request:
10.192.16.82 - baseqa20151x [19/Mar/2015:22:28:40 -0400] "GET /wl1213-test/baseqa20151/oasis2Portal/owsPortal/phs/billing-account-policy-inquiry-admin HTTP/1.1" 500 215530
Thanks for your help.

Integrate http apache with kaazing gateway

I am running an app on http apache 2.4 through which I am trying to connect to a kaazing gateway. I have followed the
instructions that are found in kaazing site at "setup-guide.html#webserver_integrate" section, but the connection keeps failing: the Mozilla console prints:
TypeError: this._socket is undefined, 4146 XmppClient.js
I changed the <allow origin> with an *. I would like to ask whether I should make any changes on the configuration file of apache.
Finally, I managed it to work. I made a new install of kaazing gateway. In gateway-config.xml at the GATEWAY_HOME/conf/ I changed the value of the gateway.hostname with my internal ip and set the
*
at
<cross-site-constraint>
<allow-origin>*</allow-origin>
</cross-site-constraint>
in service with type: xmpp.proxy and this time worked! Also I changed '
*
with the
http://localhost:80
(http apache) and also worked. I don't know why didn 't it work before.
Thanks for trying to help!

remove server header tomcat

I am able to rename the value of org.apache.coyote.http11.Http11Protocol.SERVER to anything else, so the HTTP-Response-Header contains something like:
Server:Apache
instead of the default
Server:Apache-Coyote/1.1
Using a empty value for org.apache.coyote.http11.Http11Protocol.SERVER does not remove the Server-Header.
How can I remove the Server-Header from my responses?
You can modify your tomcat server.xml and add a "server" option and set it to whatever you want. The server option should be set for any http or ssl connectors that you have running. For example, below is a sample HTTP Connector configuration from an example server.xml file
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" enableLookups="false" xpoweredby="false" server="Web"/>
Short answer - you can't remove the header, but you should modify it (see other answers).
The server header is defined in the RFC and it is mandatory. (not defined as optional in the spec)
Taken from http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38
14.38 Server
The Server response-header field contains information about the software used by the origin server to handle the request.
The field can contain multiple product tokens (section 3.8) and
comments identifying the server and any significant subproducts. The
product tokens are listed in order of their significance for
identifying the application.
If the response is being forwarded through a proxy, the proxy application MUST NOT modify the Server
response-header. Instead, it SHOULD include a Via field (as described
in section 14.45).
Note: Revealing the specific software version of the server might
allow the server machine to become more vulnerable to attacks
against software that is known to contain security holes. Server
implementors are encouraged to make this field a configurable
option.
It should be possible since Tomcat 5.5. Check out this discussion: https://mail-archives.apache.org/mod_mbox/tomcat-users/200508.mbox/%3C42FBE8AA.1060401#joedog.org%3E
and this link:
https://tomcat.apache.org/tomcat-4.1-doc/config/coyote.html
Accordingly the following should set the server header to TEST. Empty should make it empty.
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector" port="8180" inProcessors="5" maxProcessors="75" enableLookups="true" acceptCount="10" debug="0" connectionTimeout="20000" useURIValidationHack="false" server="TEST"/>
Setting the Server header to Apache should security-wise be good enough in most cases. Just from that it won't be possible to infer which OS nor which exact version with which modules and the versions of the modules running.
if you are using embedded tomcat then you can try below code.
import org.apache.catalina.startup.Tomcat;
final Tomcat server = new Tomcat();
server.getConnector().setXpoweredBy(false);
server.getConnector().setAttribute("server", "");
For Web application.
Set Server header from the code.
It worked for me in Java Spring boot project.
response.setHeader("Server", "none");
Try adding from code if it is deployed in tomcat.