Apache to Tomcat Cookie issue when using SSL termination through nginx - apache

I'm testing our app on a kubernetes cluster. So we have Nginx Controller which handles SSL termination and passes HTTP traffic to Apache server. Apache server handles static content and forwards all JSP related to tomcat.
For some reason the webapp doesn't work on the first try (website works fine though) when doing SSL termination but if I reload the page and try to use the app again then during this second attempt everything works fine (means it doesn't load some of the automatic functions on first attempt and can be reproduced by clearing the cache and logging in).
I spoke to dev they mentioned it could be cookie issues.
Current setup which is not working:
Nginx controller (SSL termination) -> Apache (HTTP port 80 ) -> Tomcat (HTTP port 8080).
Setup which works fine:
Nginx controller (SSL passthrough) -> Apache (HTTPS port 443) -> Tomcat (HTTPS port 8080).
I can't get rid of Apache in between and it is really needed for the app temporarily.
What settings are required to make this work? I've tired the following:
Disable port 443 on apache
Disable 8443 ports and all redirects to port 8443 and listen only 8080
Modified web.xml to set http-only to true and secure bit to true on tomcat server.
<session-config>
<session-timeout>60</session-timeout>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
Anything else that needs to be done? I've spent a day trying to troubleshooting this and couldn't figure it out yet.
Server.xml contains only these enabled lines, rest of them are commented out or defaults:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" />
<Connector port="8009" maxThreads="2000"
enableLookups="false" redirectPort="80" protocol="AJP/1.3"/>
<Engine name="Catalina" defaultHost="localhost" jvmRoute="server001">
# Removed cluster config since they're all default
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<Context path="" docBase="/usr/local/tomcat/webapps/ROOT.war" debug="0" distributable="true">
</Context>
http.conf - has nothing but default since SSL is disabled. So no virtual host. Only thing that's added to http.conf is
JkMount /* ajp13
Worker.properties is the following.
# - An ajp13 worker that connects to localhost:8009
worker.list=ajp13
#------ DEFAULT ajp13 WORKER DEFINITION ------------------------------
# Defining a worker named ajp13 and of type ajp13
worker.ajp13.port=8009
worker.ajp13.host=$(TOMCAT_SERVER)
worker.ajp13.type=ajp13
worker.ajp13.reply_timeout=15000
worker.ajp13.lbfactor=1
#worker.ajp13.cachesize
worker.loadbalancer.balanced_workers=ajp13
The webapp needs to communicate with Java TCP server through websocket so we have a webSocket server written in nodejs. It just forwards traffic from websocket to Java server TCP connection.
But it has its own SSL certs setup. Since by default Nginx controller on GCP doesn't deal with ssl termination for TCP services, I have configured NodeJS backend service to accept SSL traffic directly on port 1234 for example. This service runs on the tomcat server. Don't know if this is creating a conflict since they all connect to same domain name.

Your problem probably arises, because the application does not understand that the request came from a secure channel.
Servlet API applications understand that a request was sent through a secure channel based on the result of ServletRequest#isSecure(). For requests that came through HTTP, this value depends on whether SSL was enabled or not.
When you use the AJP connector, this information and many more are trasmitted by the Apache server. This works perfectly well in the "SSL passthrough" configuration. However when the SSL connection terminates at NGINX you are in the situation described by the Reverse Proxy HOW-TO:
In some situations this is not enough though. Assume there is another less clever reverse proxy in front of your web server, for instance an HTTP load balancer or similar device which also serves as an SSL accelerator.
Then you are sure that all your clients use HTTPS, but your web server doesn't know about that. All it can see is requests coming from the accelerator using plain HTTP.
If you wanted to keep this configuration for a long time, I would suggest following the aforementioned HOW-TO. For short-term usage there is a simpler solution: you need to hardcode in Tomcat's configuration that all AJP requests are secure:
<Connector port="8009"
maxThreads="2000"
enableLookups="false"
protocol="AJP/1.3"
secure="true"
scheme="https"/>
The scheme attribute tells Tomcat which scheme was used by the original client, the connector will still use AJP.

Related

Cannot log into GeoServer 2.19 with SSL

I am able to reach the GeoServer log-in form on a new server instance using a URL like this: https://sub.domain.tld/geoserver.
However, entering the correct username and password causes Cannot POST /geoserver/j_spring_security_check to be displayed in plain text in the browser window and "http://localhost:8080/geoserver/j_spring_security_check" to appear on the address line (Chrome and Firefox). Logging-in works just fine from http://sub.domain.tld:8080/geoserver and, while logged in that way, the SSL URL will skip the log-in form entirely and open the full GUI -- but none of the example layer previews will work (Cannot GET /geoserver/tiger/wms ...or whatever layer).
I have 3 similar servers set up with earlier software versions that all work perfectly:
CentOS Linux release 7.5.1804 (Core)
Apache 2.4.6
Tomcat 9.0.4.0
JVM 1.8.0_171-b10 (Oracle)
GeoServer 2.15.1 (also 2.14.1)
This latest server is:
CentOS Linux release 7.9.2009 (Core)
Apache 2.4.6
Tomcat 9.0.48.0
JVM 1.8.0_292-b10 (Red Hat)
GeoServer 2.19.1
I closely followed the GeoServer install procedure found here. Apache was already installed and working with a virtual host configuration using certbot and a Let's Encrypt certificate. I added the following to the <VirtualHost *:443> section of the /etc/httpd/sites-available/sub.domain.tld.conf file:
ProxyRequests Off
ProxyPass /geoserver http://localhost:8080/geoserver
ProxyPassReverse /geoserver http://localhost:8080/geoserver
<Location "/geoserver">
Order allow,deny
Allow from all
Header set Access-Control-Allow-Origin "*"
</Location>
I also set "https://sub.domain.tld/geoserver/" as the Proxy Base URL in GeoServer. This is exactly how my working instances are set up.
The newest /opt/tomcat/webapps/geoserver/WEB-INF/web.xml file is slightly different in that it has separate CORS sections to be uncommented for Jetty vs. Tomcat. The Tomcat section and the cross-origin filter-mapping are uncommented. Unlike before, I had to enable the SELinux httpd_can_network_connect process in order to get to the GeoServer log-in form via SSL. Disabling SELinux enforcement, however, does not solve the j_spring_security_check problem.
Sensitive WMS and WFS content must be served via SSL. I am now spinning my wheels on research so any help in resolving this would be greatly appreciated!
I was running into a similar problem trying to reverse proxy a Geoserver docker container using Apache.
After bashing my head for a few days, I found I needed a couple of changes on both ends of the setup.
Apache:
<Location "/geoserver">
ProxyPreserveHost On
ProxyPass http://localhost:8080/geoserver
ProxyPassReverse http://localhost:8080/geoserver
</Location>
The ProxyPreserveHost directive should ensure that sub.domain.tld is what's used rather than localhost.
However, at this point I hit another problem, no matter what I did the login & logout URLs were using http:// and not https://
This required adjusting the server config of Tomcat, specifically the scheme used by the connector.
Tomcat:
<Connector
port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
scheme="https"
/>
Note the value of scheme is https, normally it's http because it's the http connector. This connector doesn't SSL/TLS encrypt the traffic so it would, under normal circumstances (appropriately), set the protocol to http.
Since we're using a proxy for SSL/TLS encryption we don't need Tomcat to do that work but we still need to tell Tomcat to describe the server name using https instead of the usual http.
Alternatively, you could also look at using the AJP connector which is an entirely different protocol but gets around some of these issues rather neatly and can be more performant.
The issue with this approach is that it requires more Apache mods to be enabled to work as well as some security concerns given how much more powerful AJP can be VS the http connector.
Also, there are some other proxy settings that can be used in Tomcat to possibly remove the need for ProxyPreserveHost in Apache, but this should get you where you're going.
Additional reading:
Tomcat HTTP Connector docs: https://tomcat.apache.org/tomcat-9.0-doc/config/http.html
Tomcat AJP docs: https://tomcat.apache.org/tomcat-9.0-doc/config/ajp.html

302 redirect, Tomcat behind Apache for hybris

I've configured hybris and apache,mod_jk using below blog article.
www.facebook.com/permalink.php?id=317609748375071&story_fbid=680730588729650
hybris is completely running fine on tomcat ports http on 9001 and https on 9002.
one of developer has also configured redirection at hybris level
so any request comes in for http://hot.local:9001/ it gets automatically
redirect to https://hot.local:9002/abc/en.
Now I'm stuck at apache and mod_jk configuration point of view.
I'm not able to setup URL redirection in apache with mod_jk configuration.
Getting below error
[22993:22208] [debug] jk_handler::mod_jk.c
(2047): Service finished with status=302 for worker=tss1
I'm configuring above stuff on UBUNTU.
1) Opened Port 443 exclusively in ubuntu
2) Include redirectPort="8443" in tomcat siemap.xml
3) Include below tag in apache2 ssl config
JkMountCopy On

How to override scheme and is_ssl in apache HTTP Server for mod_proxy_ajp

We are running Tomcat 7 behind a load balancer that works also as SSL terminator, and an Apache HTTP Server 2.4. The Apache connects to the Tomcat via mod_proxy_ajp.
For the application it is important that Tomcat is aware that the request is coming in via HTTPS and is thus secure. As e.g. this article recommends, it is common to configure this on the Tomcat's Connector using the attributes secure="true" and possibly scheme="https" proxyPort="443". While this works, it is inconvenient since we are using HTTP for some purposes as well, and thus we would need to set up two Tomcat connectors for this purpose. And it has a smell, since this way we basically tell Tomcat to override the wrong information it gets from the Apache HTTP Server that the request is HTTPS instead of HTTP, instead of telling the Apache that it should send the correct information on the protocol and secure status.
So my question: is it somehow possible to configure the Apache HTTP Server itself that it passes the correct information via the AJP protocol: that the request is received via HTTPS and is secure? The problem is that it doesn't know it's HTTPS, since there is a SSL terminator before it and the requests arrives via HTTP, as far as it is concerned. Can I tell the Apache somehow that it's actually HTTPS?
A partial solution seems to be to set the protocol on a ServerName directive in the virtual host in the Apache HTTP server:
ServerName https://whatever
This way any Location: headers in redirects seem to be rewritten to https in the Apache, but the Tomcat is still passed the wrong information via AJP.
I always thought that AJP transfers this information automagically - but I'm not using mod_proxy_ajp, rather mod_jk. It's one of the reasons why I much prefer AJP over HTTP (and proxying).
Might be worth to change the module/connection

apache reverse proxy - how to hide internal network

my scenario is this: I have a machine with Apache 2.2 configured as reverse proxy
and another machine on which there is Apache Tomcat7 listening on port 8080.
My objective is to make internet users accessing a resource "am" (deployed on Tomcat)
WITHOUT using IP address of the Tomcat machine but only contacting the reverse proxy.
So far I set httpd.conf of the reverse proxy:
ProxyPass /am http://tomcat_server.com:8080/am
ProxyPassReverse /am http://tomcat_server.com:8080/am
But the problem is that the reverse proxy tells the users to contact tomcat_server
but of course tomcat_server is a private IP and cannot be accessed by internet users.
In your Tomcat server.xml config file,
edit the http Connector to include attributes: proxyPort, proxyName - such that it resembles:
<Connector
port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
proxyPort="80"
proxyName="url.domain.clients.use.for.your.webapp"
/>
proxyPort="80" -- makes Tomcat return data to your Apache proxy
proxyName="url.domain.clients.use.for.your.webapp" -- makes Tomcat return the url to Apache proxy that your user clients should process, instead of tomcat_server.com which they can't access
Here are some older Tomcat docs that mention it:
proxyName
If this Connector is being used in a proxy configuration, configure
this attribute to specify the server name to be returned for calls to
request.getServerName(). See Proxy Support for more information.
Proxy Support
The proxyName and proxyPort attributes can be used when Tomcat is run
behind a proxy server. These attributes modify the values returned to
web applications that call the request.getServerName() and
request.getServerPort() methods, which are often used to construct
absolute URLs for redirects. Without configuring these attributes, the
values returned would reflect the server name and port on which the
connection from the proxy server was received, rather than the server
name and port to whom the client directed the original request.
I worked through a similar need, with having Tomcat listen only on its localhost:
How can Tomcat 9 Connector listening 127.0.0.1 reverse proxy to Win. Apache 2.4 with private ServerName
If your problem is references to the origin server in HTML, check out mod_proxy_html or mod_substitute.

Apache & JBoss use port 80 at the same time

I have both Apache 2 and JBoss 4.2.3 on the same machine and would like both of them to use port 80. There are several ways I see people doing this mod_jk, mod_proxy, but I'm not sure which one is the best.
I don't need any load balancing, but I do need HTTPS.
You can't have two applications listening to the same tcp port (80) at the same time. You can use mod_jk to have http requests on port 80 routed from Apache server to the JBoss server. This is the method I am most familiar with and prefer. mod_proxy should also work, but I find that method a little more complicated.
Configuring https on Apache is probably best dealt with as a separate topic. There are issues with purchasing a ssl certificate, creating a self-signed certificate, etc.
There are two steps to accomplish configure mod_jk to route requests from the Apache server to the JBoss server:
Configure the Apache web server to forward some requests to the JBoss server.
The Apache configuration will vary depending on the distribution of Apache that you are using (windows, RHEL, debian, built from source, etc.) but the concepts should be similar for any Apache installation.
You need to download mod_jk for your platform from the tomcat web site:
http://tomcat.apache.org/download-connectors.cgi
Your OS vendor may provide a binary for you, so check there first. You may also compile mod_jk yourself if you prefer.
Copy the mod_jk binary (mod_jk.so for Linux/UNIX system, not sure about windows) into your Apache servers modules directory (this depends on the Apache distribution you are using).
Add the equivalent directive to your Apache configuration:
LoadModule jk\_module /usr/lib/apache2/modules/mod\_jk.so
You should add two configuration files to the Apache configuration directory: mod_jk.conf and workers.properties. You should include mod_jk.conf from the main Apache configuration file:
Include /etc/apache2/mod\_jk.conf
The workers.properties file is included by mod_jk.conf with the JkWorkersFile directive.
More detailed settings for mod_jk.conf can be found at the tomcat documentation page:
http://tomcat.apache.org/connectors-doc/reference/apache.html
The important directives are:
JkWorkersFile (specifies where the workers.properties file lives)
JkMount (mount point for mapping of URI to tomcat worker)
An example:
JkWorkersFile /etc/apache2/workers.properties<br>
JkMount /examples/* myworker<br>
JkMount /examples myworker
These directives map the /examples and /examples/ URI to the myworker tomcat worker.
Conceptually you can think of a worker as representing a tomcat or JBoss instance and the mount as a way of mapping a URI to a worker. This way of representing things allows one Apache server to be the front end for several tomcat or JBoss servers. This can be handy if you have only one IP address you can use but wish to run several application servers behind one Apache server.
The workers.properties files describes the tomcat or JBoss server(s) that the Apache server will connect to. Important entries in this file are:
worker.list=myworker<br>
worker.tomcat.type=ajp13<br>
worker.tomcat.host=localhost<br>
worker.tomcat.port=8009
There are other worker properties that can be found in the tomcat documentation page for the workers.properties file:
http://tomcat.apache.org/connectors-doc/reference/workers.html
Configure the JBoss server to accept connections from the Apache server
The JBoss server is configured to accept mod_jk connections on port 8009 (the default ajp port) out of the box, but it is good to know where to configure this in case you want to change any of this in the future.
The configuration is in the tomcat based portion of the JBoss server located in ${JBOSS_SERVER_CONFIGURATION}/deploy/jbossweb.sar/server.xml. This is for JBoss AS 5.1.0.GA, previous versions are in a similar location. The mod_jk connector is configured in the Connector section for the AJP 1.3 protocol and looks like:
<Connector protocol="AJP/1.3" port="8009" address="${jboss.bind.address}" redirectPort="8443" />
The most common reason to modify this section is if you have multiple tomcat or JBoss servers connecting to apache via the AJP protocol, you can adjust the port number that the AJP connector will listens on so there are no conflicts.