keycloak redirect url for reverse proxy - spring-security

i have keycloak running in one VM with
keycloak.domain.com
i have client app which is running on another VM which is running on tomcat like
app.domain.com
Which is using Spring Security so i done the configuration as below in keycloak.json
{
"realm": "demo",
"auth-server-url": "http://keycloak.domain.com:8080/auth",
"ssl-required": "external",
"resource": "app-client",
"verify-token-audience": true,
"credentials": {
"secret": "9503a597-4c83-44ca-884e-e285891a2d32"
},
"use-resource-role-mappings": true,
"confidential-port": 0
}
and we have some other service so we have configured Apache reverse Proxy like
main.domain.com
when i access the main.domain.com/app we are doing proxy as below
ProxyPass /app http://app.domain.com/app nocanon
ProxyPassReverse /app http://app.domain.com/app
we are able to redirect to keycloak but redirect_uri is http://app.domain.com/app/sso/login it should go though proxy
Where to configure this? or i am doing it in wrong way? is their anyother way of achiveing OAuth for the my app?

We've managed to solve the issue by setting ProxyPreserveHost On in the apache configuration:
<VirtualHost *:80>
ProxyPreserveHost On
This set's the Host header in the request and the adapter takes care of the rest.
We're using the Servlet Keycloak adapter, but I guess it should work for other adapters as well.

Related

Forwarding http to https in AWS Load Balancers

I'm using Elastic Beanstalk, and I installed my SSL certificate in my EB load balancer. Every time the server is not healthy, the load balancer delete the instance and creates a new one, which means I'm gonna lose my redirection codes and SSL set up that I installed inside the instance.
That's why I installed my SSL on the load balancer. However, how can I redirect HTTP to HTTPS on the load balancer?
I used to redirect by putting the below codes inside the instance, but if I keep doing this way, when the load balancer removes an unhealthy instance, I'm gonna lose my redirection from HTTP to HTTPS.
What should I do?
<VirtualHost _default_:80>
ServerName (domain).com
ServerAlias www.(domain).com
RedirectPermanent / https://www.(domain).com/
</VirtualHost>
<VirtualHost _default_:443>
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*) https://www.%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
</VirtualHost>
UPDATE
Here's my listeners on Load Balancers in EC2
When using a load balancer in AWS, the common use case is to install the SSL certificate on the load balancer. This is commonly called SSL offloading or Layer 7 load balancing. Traffic from the load balancer to the EC2 instance is not encrypted and typically over port 80 (sometimes 8080) (HTTP). Traffic from the client to your load balancer is defined by the listeners that you created.
Layer 4 load balancing uses TCP to talk to your EC2 instance and you install the SSL certificate on your web server. Your web server then knows what port the client is connecting on and the following DOES NOT APPLY.
Your code running your website needs to check if the client connected to the load balancer using HTTPS. If true, don't redirect the client. If the client connected to the load balancer using HTTP, then redirect the client.
The following PHP code shows how to read the Load Balancer headers that are sent to your EC2 instance to determine if the client connected over HTTPS. If you are not using a language such as PHP or Nodes.js, you can also create Apache configurations that know how to read the correct headers (example at the bottom).
function require_ssl()
{
global $config_require_ssl;
if ($config_require_ssl == FALSE)
{
return;
}
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']))
{
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
{
$_SERVER['HTTPS']='on';
}
}
if(empty($_SERVER['HTTPS']) || $_SERVER["HTTPS"] != "on")
{
header("Location: https://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
exit();
}
}
This is the code for Apache:
<VirtualHost *:80>
RequestHeader set X-Forwarded-Proto "http"
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
…
</VirtualHost>
You'll need to set up the application that you've got running in Elastic Beanstalk to configure Http to Https redirection.
Then when setting up the Load Balancer through Elastic Beanstalk create 2 listeners one for port 80 and one for 433, which both forward on.
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/environments-cfg-alb.html
You can offload the SSL traffic at the Application Load Balancer(ALB) and the communication between ALB and you can configure the redirection from http to https using EC2 web server configuration.
You are right that if there no running servers the redirection won't work. Infact the response will be a different error where the resource is not accessible. If you configure the autoscaling and load balancing with more than one instance, for most of the cases at least one healthy instance should be able to do the redirection.

Using apache SSL reverse proxy with a rails application

I have a rails application running on a private subnet, using port 8080, without SSL enabled.
I also have an Apache SSL server on a DMZ, which I use as a reverse proxy to the rails application I mention first.
The problem is, rails include some absolute url in the generated code, with adresses beginning with http://...
If i use config.force_ssl = true as I read here or there, there is a infinite redirection, because rails sees the requests coming as plain HTTP and issues a redirect to HTTPS, but as the client already is.
The solution was simple enough: put this line in the reverse proxy configuration file :
RequestHeader set X-Forwarded-Proto "https"

Apache Reverse Proxy Unix Socket

I am trying to setup ProxyPass in Apache 2.4.7 using unix sockets to a puma server for a rails application. I keep receiving a 500 Internal Error. When I check the apache logs I receive this message:
No protocol handler was valid for the URL /. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
This is my proxy config in apache
ProxyPass / unix:///home/rails/rp/tmp/sockets/puma.sock|http://127.0.0.1/
ProxyPassReverse / unix:///home/rails/rp/tmp/sockets/puma.sock|http://127.0.0.1/
If I setup a Proxy Pass on a regular tcp port like this, it works fine.
ProxyPass / http://127.0.0.1:9292
ProxyPassReverse / http://127.0.0.1:9292
Any help is appreciated, let me know if you need anymore information.
In general, there is some point for checking for reverse proxy an http server app over unix socket:
Check if Apache already loaded required modules (proxy & http_proxy) using apachectl -M command
Make sure that socket path is accessible for www-data user (it is default apache user)
Check correctness of running app on unix socket using following command:
curl --unix-socket /var/www/app/socket/path -XGET http:/someMethod
Check that ProxyPreserveHost On already present in your virtual host file and set socket address correctly (as unix:/var/www/path/to/your/socket) and after pipe mark path correctly (as |http://127.0.0.1/what/ever)
Make sure both ProxyPassReverse and ProxyPass is set correctly
I am not sure which proxy handler should handle sockets, so you could try loading them all then see which one does the job for you:
https://httpd.apache.org/docs/trunk/mod/mod_proxy.html
Note that you can also use SetHandler to specify the module you want to handle your connections
Ok, I spent a while to find the solution on one of my old server.
When you have this mod_proxy error, it's because Apache doesn't recognize the proxy module to use behind the unix socket.
Assuming that you obviously already have :
a2enmod proxy
a2enmod proxy_http
service apache2 restart
There's a good chance that your apache config file located at /etc/apache2/mods-available/proxy_http.load is empty
Add theses lines to this file :
# Depends: proxy
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
then
service apache2 restart

jelastic grails redirects http to https

I have one domain app.mydomain.com which is mapped with A record to public IP (from tomcat server that belongs to mysub.jelastic.dogado.eu)
I've configured SSL custom certificates and all HTTPS requests works very well.
All i need is that my app to use just HTTPS, all HTTP requests to be redirected to HTTPS,
Acordingly with spring security plugin (1.2.7.4 that i have on my app) i configured in this way:
grails.plugins.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
grails.plugins.springsecurity.portMapper.httpPort = 8080
grails.plugins.springsecurity.portMapper.httpsPort = 8443
grails.plugins.springsecurity.secureChannel.secureHeaderName = 'X-Forwarded-Proto'
grails.plugins.springsecurity.secureChannel.secureHeaderValue = 'http'
grails.plugins.springsecurity.secureChannel.insecureHeaderName = 'X-Forwarded-Proto'
grails.plugins.springsecurity.secureChannel.insecureHeaderValue = 'https'
grails.plugins.springsecurity.auth.forceHttps = true
grails.plugins.springsecurity.secureChannel.definition = [
'/**': 'REQUIRES_SECURE_CHANNEL'
]
On localhost it is working very good, all http requests were redirected to https but in jelastic nothig happend. I tried many configuration, replacing https port to 8743/443, but the same results. Any help will be apreciated.
Thanks a lot,
Catalin
The X-Forwarded-Proto header is only set if you have a load balancer in your environment (or using the shared resolver, but since you're using a custom SSL certificate that cannot apply in this case).
If you don't have a load balancer in your environment, that is why the check does not work - since those headers are simply not set.
If you do have a load balancer, all requests to your Tomcat are directed to port 80 (redirected via port forwarding to 8080); that includes requests sent to https (because the load balancer performs 'SSL offload' in this case. Therefore you are seeking an impossible combination in your grails rules (8743 and X-Forwarded-Proto). Depending on your environment topology you will have one of these cases or the other, but not both.
EDIT: You should also double-check your server.xml to make sure you have this:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" />
Note the redirectPort value; it should be 443 because this is the port that will be sent to the browser for a redirect - with a load balancer (or Jelastic Shared Resolver) proxying the requests, the browser needs to request on port 443 (even though the Tomcat SSL connector is configured on 8743 - if applicable), because the proxy uses standard port numbering (i.e. https:// without any port number = 443).
Even if you are working with a standalone Tomcat (no load balancer, and not via the Jelastic Shared Resolver), those requests to 443 will be automatically forwarded to 8743 for you.
Thanks Damien, your answer solved the issue. For anyone interested this is the configuration(Config.groovy):
production {
grails.app.context = "/"
grails.serverURL = "https://yourdomain.com"
grails.plugins.springsecurity.portMapper.httpPort = 80
grails.plugins.springsecurity.portMapper.httpsPort = 443
grails.plugins.springsecurity.auth.forceHttps = true
grails.plugins.springsecurity.secureChannel.definition = [
'/**': 'REQUIRES_SECURE_CHANNEL'
]
}
Put this in server.xml:
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="443" />
I suppose 8080 also works.
Make war, deploy.

CAS proxy configuration

I have a setup of the following:
Proxy server: https://proxy-server.com
application server: https://app-server.com
and a CAS (sso) server: https://sso-server.com
I can get the following working:
https://proxy-server.com/cas/login?service=https://app-server.com/app
But the problem for this URL is it exposes the actual app-server, which is behind the proxy server.
Ideally, I want the following:
https://proxy-server.com/cas/login?service=https://proxy-server.com/app
My question is:
Is there a way to hide (use post, encrypt targetService part, callback on proxy side, or...) the app-server.com in the URL? since I have a proxy server in front, I don't want to expose the actual app server name.
thanks
If you're running something like Apache mod_proxy on https://proxy-server.com then you should be able to hide your app behind it. Based on your example it looks like you're already doing that with your cas server since your stated your cas login url as https://proxy-server.com/cas/login
Following the same idea your app can be reached using https://proxy-server.com/app
ProxyPass /cas https://sso-server.com/cas
ProxyPassReverse /cas https://sso-server.com/cas
ProxyPass /app https://app-server.com/app
ProxyPassReverse /app https://app-server.com/app
You'd probably have to modify your serviceUrls so they are relate to proxy-server.com
ProxyPass And ProxyPassReverse Configuration
Proxy HOW-TO

Resources