is it possible to use the CAS 4.x Server with Spring Security without SSL?
I already tried to edit the CAS Server settings.
I added
<bean id="ticketGrantingTicketCookieGenerator"
class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="TGC"
p:cookiePath="/cas" />
to the ticketGrantingTicketCookieGenerator.xml
and I also added
<bean id="warnCookieGenerator"
class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="CASPRIVACY"
p:cookiePath="/cas" />
to the warnCookieGenerator.xml
I still get the following error from CAS:
Authentication failed because url was not secure.
Is there any other configuration which can make CAS without SSL possible or isn't it possible the current version?
Thanks in advance...
CAS Server were made to be a secure channel to do authentication. So the CAS Server does not work with HTTP. You can change the source of CAS to do it for you, but this does make sense for me.
<bean id="proxyAuthenticationHandler"
class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" p:requireSecure="false"/>
Related
We are moving an old java / spring app into AWS, so it is behind an AWS Application Load Balancer. Tomcat is running directly behind the load balancers on port 8080, and we are using HTTP between the load balancer and tomcat.
The problem is under this scenario the spring security module doesn't recognize that the connection is secure.
I can resolve this issue by configuring the Connection:
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
proxyName="single-host.example.com"
secure="true"
scheme="https"
redirectPort="443"
proxyPort="443" />
Which works for a single host name. However, I need this to work across multiple host names.
I have tried skipping the proxy and adding:
server.tomcat.remote_ip_header=X-Forwarded-For
server.tomcat.protocol_header=X-Forwarded-Proto
But this doesn't seem to make any difference.
Is there a way to support multiple hostnames in this scenario?
AWS LoadBalancer sends X-Forwarded-Proto header when proxying request.
On Tomcat configure RemoteIpValve to have request.secure and other request variable interpreted from those headers.
<Valve className="org.apache.catalina.valves.RemoteIpValve"/>
You should also omit setting proxyName on Connector conifiguration since it should come automatically from valve.
I am got some solution procedure. So I have provided 2 suggestion. First one is step by step pictorial view to solve your issue. If not, then go to the second one.
Second one is using X-Forwarded-Proto and related configuration to solve the issue. Hope it will help you.
Suggestion#1:
Amazon cloud environment with load balance support process is pretty straight-forward. A step by step tutorial is given here:Elastic Load Balancing (ELB) with a Java Web Application + Tomcat + Session Stickiness
Suggestion#2:
phillipuniverse has given a solution.
Configuring the following valve in Tomcat will make request.isSecure() function properly with the X-Forwarded-Proto header:
<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" />
This can be added to Tomcat's server.xml under the <Host> element.
And of course, after all that, there is a very, VERY simple solution that fixes this problem from the very beginning. All that really needed to happen was to modify the proto channel filters from this:
if ("https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(), invocation.getResponse());
}
to:
if (invocation.getHttpRequest().isSecure() ||
"https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(), invocation.getResponse());
}
The final configuration here should be this:
<bean class="org.broadleafcommerce.common.security.channel.ProtoChannelBeanPostProcessor">
<property name="channelProcessorOverrides">
<list>
<bean class="org.broadleafcommerce.common.security.channel.ProtoInsecureChannelProcessor" />
<bean class="org.broadleafcommerce.common.security.channel.ProtoSecureChannelProcessor" />
</list>
</property>
</bean>
After that,
Some prefer to terminate SSL at the load balancer, and to not use Apache web server. In that case, you often accept traffic at the LB on 80 / 443, and then route traffic to Tomcat on 8080.
If you are using Spring's port mapping:
<sec:port-mappings>
<sec:port-mapping http="8080" https="443"/>
</sec:port-mappings>
This will not work as it does not override the port mapping in the new Channel Processors. Here is a configuration that will work, though:
<bean class="org.broadleafcommerce.common.security.channel.ProtoChannelBeanPostProcessor">
<property name="channelProcessorOverrides">
<list>
<bean class="org.broadleafcommerce.common.security.channel.ProtoInsecureChannelProcessor" >
<property name="entryPoint">
<bean class="org.springframework.security.web.access.channel.RetryWithHttpEntryPoint">
<property name="portMapper" ref="portMapper"/>
</bean>
</property>
</bean>
<bean class="org.broadleafcommerce.common.security.channel.ProtoSecureChannelProcessor" >
<property name="entryPoint">
<bean class="org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint">
<property name="portMapper" ref="portMapper"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
Resource Link: HTTPS/SSL/Spring Security doesn't work in both a load balancer and non-load balancer environment #424
You should setup HTTPS connection on the LB, then you'll have a proper TLS connection between the LB and the tomcat so spring will stop crying. You'll just have to provide a self-signed certificate to the LB and setup your spring security module with the private key that have generated this self signed certificate.
(a more complex option: setup properly the tomcat proxy, to force it to encapsulate the HTTP stream of the LB in an HTTPS stream. Setup all TLS requirements in the proxy: certificate, private key...)
Did you try to put LB address as proxyName? It might work on your case.
I have a Spring MVC application secured with Spring Security. The majority of the application uses simple HTTP to save resources, but a small part processes more confidential information and requires an HTTPS channel.
Extract from the security-config.xml :
<sec:http authentication-manager-ref="authenticationManager" ... >
...
<sec:intercept-url pattern="/sec/**" requires-channel="https"/>
<sec:intercept-url pattern="/**" requires-channel="http"/>
</sec:http>
All worked fine until we decided to migrate it to the main server, where the application servers run behind reverse proxies. And as now HTTPS is processed by the reverse proxies the application server only sees HTTP requests, and disallows access to the /sec/** hierarchy.
After some research, I found that the proxies add a X-Forwarded-Proto: https header (*), but in Spring Security HttpServletRequest.isSecure() is used to determine the channel security offered (extract from SecureChannelProcessor javadoc).
How can I tell Spring Security that a X-Forwarded-Proto: https header is enough for a secure request?
I know I could report that part on proxies configuration, but the proxies administrator really does not like that solution, because there are many application behind the proxies and the configuration could grow to a non manageable state.
I an currently using Spring Security 3.2 with XML config, but I'm ready to accept answers based on Java config and/or more recent version.
(*) Of course, the proxies remove the header if it was present in incoming request, so the application can be confident in it.
Kind of a followup to NeilMcGuigan's answer that showed that the solution was servlet container side.
Tomcat is even better. There is a valve dedicated to masking the side effects of a reverse proxy. Extract from Tomcat documentation for Remote IP Valve:
Another feature of this valve is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").
Example of the valve configuration :
<Valve className="org.apache.catalina.valves.RemoteIpValve"
internalProxies="192\.168\.0\.10|192\.168\.0\.11"
remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by"
protocolHeader="x-forwarded-proto" />
That way with no other configuration of the application itself, the call to Request.isSecure() will return true if the request contains a header field of X-Forwarded-Proto=https.
I had thought of two other possibilities, but definitively prefere that one :
use a filter active before Spring Security ChannelProcessingFilter to wrap the request with a HttpServletRequestWrapper overriding isSecure() to process a X-Forwarded-Proto header - need writing and testing the filter and the wrapper
use a Spring BeanPostProcessor to look for a ChannelProcessingFilter and manually inject a ChannelDecisionManager able to consider the X-Forwarded-Proto header - really too low level
Spring Boot makes it dead simple (at least with embedded Tomcat).
1. Add the following lines to your application.properties:
server.forward-headers-strategy=native
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
2. Do the following trick with your HttpSecurity configuration.
// final HttpSecurity http = ...
// Probably it will be in your `WebSecurityConfigurerAdapter.configure()`
http.requiresChannel()
.anyRequest().requiresSecure()
Source is Spring Boot reference guide
84.3 Enable HTTPS When Running behind a Proxy Server
Please also check the answer below for a specifics related to Spring Boot 2.2
If your site is HTTPS and you're running Apache Tomcat behind another system that's handling TLS termination, you can tell Tomcat to "pretend" that it's handling the TLS termination.
This makes request.isSecure() return true;
To do so, you need to add secure="true" to your Connector config in server.xml.
https://tomcat.apache.org/tomcat-7.0-doc/config/http.html
See also the scheme attribute.
Setting up an HTTP proxy for Java JVM 6.x isn't working for me; I'm hoping someone can spot what I'm missing.
I have a Java application deployed on JBOSS 5.1.2 that makes several calls to external web services. I'd like to be able to intercept these calls using a proxy: Fiddler version 4.4.8.0.
After doing an SO search I added the following flags to my JBOSS VM parameters at startup:
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8888
I'm running JBOSS in IntelliJ 14.
I can see traffic from the browser to the application if I start JBOSS, Fiddler, and open the UI in Chrome. I do not see any calls from JBOSS to external services being intercepted. I thought I would see all the calls from JBOSS to external services in addition to those from the browser to JBOSS.
Update:
I tried adding these to properties-service.xml per this SO answer - no joy.
I'm running Spring 3, using Apache HttpClient as my web service client. I'm going to look into configuring proxy just for it.
Thanks to bmargulies and anyone else who looked at this. I have a solution that I hope will help someone else.
Adding -Dhttp.proxyHost parameters to my JVM startup options did nothing.
Adding those same parameters to JBOSS 5.1.2 configuration in my deployment properties-services.xml did nothing.
I believe that using Spring 3.x is a factor in explaining this behavior. I had to tell the Spring web service clients to use a proxy.
I added some Spring beans to wire in a Fiddler proxy HttpClient and injected that into the web service client, replacing the non-proxied version.
It failed the first time I tried it. It took me a while to figure out that the Apache Commons HttpConfiguration class didn’t follow the Java bean standard, so Spring blew up when it tried to wire it. I had to use the Spring MethodInvokingFactoryBean to get around it.
Here's the pertinent Spring configuration XML:
<!-- New beans for Fiddler proxy -->
<bean id="fiddlerProxyHost" class="org.apache.commons.httpclient.ProxyHost">
<constructor-arg name="hostname" value="localhost"/>
<constructor-arg name="port" value="8888"/>
</bean>
<bean id="fiddlerProxyHostConfiguration" class="org.apache.commons.httpclient.HostConfiguration"/>
<bean id="fiddlerProxyHostSetter" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="fiddlerProxyHostConfiguration"/>
<property name="targetMethod" value="setProxyHost"/>
<property name="arguments" ref="fiddlerProxyHost"/>
</bean>
<bean id="fiddlerProxyClient" class="org.apache.commons.httpclient.HttpClient">
<property name="hostConfiguration" ref="fiddlerProxyHostConfiguration"/>
</bean>
Now I can see the calls from the application to the web service in Fiddler. Joy!
Those parameters, first and foremost, are read by HttpURLConnection. They are specific to HTTP, of course, and so any other means of connecting to the outside world will necessarily ignore them.
There are many good reasons for code to avoid HttpURLConnection and just open a TCP connection through a plain old socket, even if that code plans to talk HTTP. HttpURLConnection has several 'browser emulation features' that get in the way. For example, it's broken for CORS and rejects some legitimate HTTP verbs.
Code that does that and in turn happens to do HTTP might choose to respect those parameters, and it might not. For example, I'm reasonably sure that the Apache Commons HTTP library gives the caller a choice.
If you put JBoss in a debugger and break on the socket connection primitives, I think you'll find out what's happening to you pretty quick in this respect.
I have a java application that is using hibernate to do a JNDI lookup for the datasource in Websphere Application Server which then talks to a MSSQL database.
The security team has recently patched the Websphere server 8.5.5.4 to disable SSLv3.
As such I'm getting a com.ibm.websphere.ce.cm.StaleConnectionException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encyption. Error: "SSLv3 SSLContext not available".
Before this, I could access the data without any issues.
What can I do to overcome this issue? Do I need to configure the application to use TLS?
I'm using Hibernate 4.3.7.
The hibernate config looks like this.
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<property name="connection.datasource">jdbc/testing</property>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<mapping resource="myApplication.hbm.xml" />
</session-factory>
</hibernate-configuration>
Any help would be greatly appreciated.
I have this issue yesterday.
I solved it by using sqljdbc4.jar instead of sqljdbc4.1 and it works fine.
Maybe you should look at the MSSQL side to check whether TLS (at least 1.0 version) is supported. If not try to enable it.
Otherwise a (not recommended from security view) fix is to enable SSLv3 temporarily by using the following JVM argument until you find a way to communicate through TLS:
-Dcom.ibm.jsse2.disableSSLv3=false
I found a solution. Try updating your sqljdbc4.jar file - it turns out mine was outdated. Alternatively, I also got it running with the solution by #trikelef that enables SSLv3 - but this opens security issues.
I am trying to figure out how to use axis2 over https.
The axis2 guide says:
CommonsHTTPTransportSender can be also
used to communicate over https.
also:
Please note that by default HTTPS
works only when the server does not
expect to authenticate the clients
(1-way SSL only) and where the server
has the clients' public keys in its
trust store. If you want to perform
SSL client authentication (2-way SSL),
you may use the
Protocol.registerProtocol feature of
HttpClient.
So my question is are there are 2 approaches for HTTPS for axis?
1) To use CommonsHTTPTransportSender
2) Uncomment the https connector on apache configuration ??
Or only (1) is the standard approach??
Also what is the problem with client authentication? I know that for apache connector I just need to set the clientAuth. This does not work for axis?
Any input is welcome!
Thanks
Reference: http://axis.apache.org/axis2/java/core/docs/servlet-transport.html
For each protocol (HTTP and/or HTTPS), an AxisServletListener instance must be declared in axis2.xml. If only a single protocol is used, no further configuration is required. For example, if only HTTP is used, the following declaration must be present in axis2.xml:
<transportReceiver name="http" class="org.apache.axis2.transport.http.AxisServletListener"/>
If both HTTP and HTTPS are used, then things become a bit more complicated. The reason is that in order to expose WSDLs with correct endpoint URIs, AxisServlet must know the ports used by HTTP and HTTPS. Unfortunately the servlet API doesn't allow a Web application to discover all configured protocols. It only provides information about the protocol, host name and port for the current request. If only a single AxisServletListener is configured, then this information is enough to let AxisServlet auto-detect the port number. If both HTTP and HTTPS are used (or if WSDLs are retrieved through transports other than AxisServlet), then AxisServlet has no way of knowing the port numbers until it has processed at least one request for each protocol. To make WSDL generation predictable in this scenario, it is necessary to explicitly configure the port numbers in axis2.xml, such as in the following example:
<transportReceiver name="http" class="org.apache.axis2.transport.http.AxisServletListener">
<parameter name="port">8080</parameter>
</transportReceiver>
<transportReceiver name="https" class="org.apache.axis2.transport.http.AxisServletListener">
<parameter name="port">8443</parameter>
</transportReceiver>
Here's what I am using in my axis.xml configuration for the https connector approach (Axis 1.4.1).
<transportReceiver name="https" class="org.apache.axis2.transport.nhttp.HttpCoreNIOSSLListener">
<parameter name="port" locked="false">9002</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>.keystore</Location>
<Type>JKS</Type>
<Password>changeme</Password>
<KeyPassword>changeme2</KeyPassword>
</KeyStore>
</parameter>
</transportReceiver>
I dumped my keystore under axis2-1.4.1/lib to avoid adding a dedicated classpath.