I am running a Spring Boot application in AWS. The application is running behind an Elastic Load Balancer (ELB). The ELB is configured to use https (port 443) to the outside world, but passes through http (port 8080) to the application. The ELB is configured to pass through the x-forwarded-proto header. I am using Jetty 9.0.0.M0, with Spring Boot 1.1.5 RELEASE.
I appear to be getting incorrect redirects sent back from the application via the ELB where the redirect responses are coming back as http, rather than https. Now, I read here that I should set the "forwarded" header to true using:
<Set name="forwarded">true</Set>
I can't see how to do this with the embedded version of Jetty in Spring Boot because there is no XML configuration file as part of my source.
I have looked at the EmbeddedServletContainerCustomizer infrastructure but I still can't get the right incantation to get this setup to work.
The application is built and tested outside of the AWS https environment, so the application needs to transparently work with http too. Directly hitting the application endpoints without going through the ELB works. It's just that the ELB to application route that's not working.
Any ideas?
Had a similar issue myself and while researching stumbled across your question. I found this was quite easy to to programatically however isn't really explained in the Jetty docs.
The structure of the Jetty xml configuration files are matched by the structure of the java API so you can just replicate it in code.
So following the Jetty guide on how to configure using the XML configuration file here
I was able to configure the embedded server programatically like this:
Server server = new Server( port );
// Create HTTP Config
HttpConfiguration httpConfig = new HttpConfiguration();
// Add support for X-Forwarded headers
httpConfig.addCustomizer( new org.eclipse.jetty.server.ForwardedRequestCustomizer() );
// Create the http connector
HttpConnectionFactory connectionFactory = new HttpConnectionFactory( httpConfig );
ServerConnector connector = new ServerConnector(server, connectionFactory);
// Make sure you set the port on the connector, the port in the Server constructor is overridden by the new connector
connector.setPort( port );
// Add the connector to the server
server.setConnectors( new ServerConnector[] { connector } );
Try setting the following property in your spring boot application:
server.use-forward-headers=true
The will ensure the correct protocol is read from the header. Refer to documentation here:
https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/html/howto-embedded-servlet-containers.html
I found a couple problems with the default Spring Boot Jetty configuration, not the least of which are enabled SSL algorithms which SSLLabs Check doesn't like.
Anyway: The fix I found for this was something like:
#Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory()
{
// Deploy the nuclear option, kill the default Spring Boot factory
// and replace with mine that disables extra crud.
JettyEmbeddedServletContainerFactory fac = new JettyEmbeddedServletContainerFactory();
// This allows ELB to work.
fac.setUseForwardHeaders( true );
return fac;
}
There are also a number of other ELB options that you need to setup if you want SSL end-to-end. I had to use the command line client with some tweaks and change the health checks to TCP:8443 b/c the EC2 instance certificates look invalid to the load balancer.
Here's what just worked for us with a Spring app behind jetty-runner-9.3.6.jar. In our case, our jetty.xml didn't have any addConnector already, and trying to add just the addConnector would error out.
Found it here - https://github.com/george-hawkins/authsite/blob/2c5d61b984a328ef878216a3acfd0ad2593f81b1/src/main/config/etc/jetty.xml
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
</Call>
</New>
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
</New>
</Arg>
</Call>
What this DOES is to modify the Request object that is passed through to make it -look- like it didn't come through a proxy (replacing the details with whatever X-Forwarded headers are available and supported).
See http://archive.eclipse.org/jetty/9.0.0.M4/apidocs/index.html?org/eclipse/jetty/server/ForwardedRequestCustomizer.html
This customizer looks at at HTTP request for headers that indicate it has been forwarded by one or more proxies. Specifically handled are:
X-Forwarded-Host
X-Forwarded-Server
X-Forwarded-For
X-Forwarded-Proto
If these headers are present, then the Request object is updated so that the proxy is not seen as the other end point of the connection on which the request came
I have been unable to find a simple Jetty 9 solution to this question. Other than recommending that I upgrade to a later version of Jetty (which is good advice) I have received no other suggestions (at this time, as you can see)
My solution for the sake of expedience is to abandon Jetty, and instead to use embedded tomcat, where this functionality is a simple matter of configuration in the application.properties file. Simply add the following line to application.properties:
server.tomcat.remote_ip_header=x-forwarded-for
This appears to do the trick using the default embedded tomcat that comes as part of Spring Boot.
Related
Having deployed the activemq-web-console war into a Tomcat embedded application how can one make it connect to an existing broker rather than create a new one?
The war comes with a set of predefined configurations, in particular, the WEB-INF/activemq.xml contains a configuration for the BrokerService
<broker brokerName="web-console" useJmx="true" xmlns="http://activemq.apache.org/schema/core">
<persistenceAdapter><kahaDB directory="target/kahadb"/></persistenceAdapter>
<transportConnectors>
<transportConnector uri="tcp://localhost:12345"/>
</transportConnectors>
</broker>
used from webconsole-embedded.xml in the following manner:
<bean id="brokerService" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="/WEB-INF/activemq.xml"/>
</bean>
This configuration creates a new instance of BrokerService and tries to start the broker.
It is reported that the web console can be used to monitor an existing broker service rather than creating a new one. For this one should set the following properties somewhere:
webconsole.type=properties
webconsole.jms.url=tcp://localhost:61616
webconsole.jmx.url=service:jmx:rmi:///jndi/rmi://localhost:1099/karaf-trun
The questions is, where does one have to set these properties within the Tomcat embedded app and which XML changes in the above have to be performed for them to be used. I cannot find any sensible explanation how to configure it, and a BrokerService instance seems to be required by the remaining spring config.
Any ideas?
Please do not suggest to use hawtio instead!
I had the same problem today. You can start the webconsole in "properties" mode which gives you the oppertunity to connect over jmx.
I added following java arguments to our Jboss 6.1 and it worked immediatley. I didn't change any of the xmls (works out of the box)...
Example:
-Dwebconsole.type=properties -Dwebconsole.jms.url=tcp://<hostname>:61616 -Dwebconsole.jmx.url=service:jmx:rmi:///jndi/rmi://<hostname>:1090/jmxrmi -Dwebconsole.jmx.user=admin -Dwebconsole.jmx.password=123456
Also discussed here: https://svn.apache.org/repos/infra/websites/production/activemq/content/5.7.0/web-console.html
In the Spring definition of a remote resource that is protected via OAuth2 to which the client application wants access, I set use-current-uri to true, in other words, the current URI should be used as a redirect (if available). It looks like:
<oauth:resource id="myResourceId" type="authorization_code"
client-id="${clientId}" client-secret="${clientSecret}"
access-token-uri="${accessTokenUri}"
user-authorization-uri="${userAuthorizationUri}"
use-current-uri="true"
scope="myScope"
pre-established-redirect-uri="${preEstablishedRedirectUri}"/>
Now the problem is, the Spring Security OAuth2 client will pick up the current internal Tomcat URL instead of the public web application's URL. The scenario is Tomcat server sitting behind Apache server, which results in two sets of URLs:
The public web application's URL is http://example.com/users/login
The internal Tomcat URL is http://localhost:8080/myapplication/users/login
Because the redirection URL is for the authorization server (e.g., Twitter, ORCID) to use to send back the authorization code, the public web application's URL should be used, not the internal one.
By the way, I'm using the following version of spring-security-oauth2:
spring-security-oauth2-1.0.5.RELEASE
spring-core-3.1.2.RELEASE
spring-security-core-3.1.3.RELEASE
Wonder if there is a way to tell Spring to use the public URL. Thanks.
Inside your tomcat conf/server.xml's connector element , try setting your public URLs that front tomcat like this:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
proxyName="example.com"
proxyPort="443" (or whatever port you are using, same goes for scheme )
scheme="https" />
This way tomcat's internal getServerName and getServerPort methods will start giving the correct values which hopefully should create the correct URL.
You might also want to configure your webserver to route requests falling at
http://example.com/users/login to http://localhost:8080/myapplication/users/login if not already done.
I have two set of server on different domains using tomcat .
Now I want to forward http post call from one server to another preserving the payload in http entity throughout.
Problem is I donot want to change code and want this to be done on tomcat level anymeans.
I currently is trying to use URLrewriteFilter but not getting through.
any suggestions ?
URLrewriteFilter may help. You can define a proxy type for element.
The request will be proxied to the full url specified. commons-http
and commons-codec must both be in the classpath to use this feature.
Sample:
<rule>
<name>A Rule</name>
<from>^/something$</from>
<to type="proxy">http://anotherserver.com/something</to>
</rule>
How can I turn off session persistence for geronimo? Is this something I should be doing? - I have no use for persisted sessions in my application. (This is because I recieve a not serializable error in my console, but I do not wish to serialize)
It depends upon which web container you're using within Geronimo; both Tomcat and Jetty are supported.
Tomcat
Add a context.xml file to your application or add these nodes:
<Context><Manager className="org.apache.catalina.session.StandardManager"
pathname=""></Manager></Context>
From the tomcat docs for pathname: Restart persistence may be disabled by setting this attribute to an empty string.
The properties are explained at these links:
https://cwiki.apache.org/GMOxDOC22/configuring-session-manager-of-tomcat.html
http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html#Standard_Implementation
Jetty
This container does not persist sessions by default, so there there is nothing to do except to make sure that the SessionHandler is not enabled. Remove the sessionHandler node if it exists in your context configuration.
<Set name="sessionHandler">
<New class="org.eclipse.jetty.servlet.SessionHandler">
<Arg>
<New class="org.eclipse.jetty.servlet.HashSessionManager">
<Set name="storeDirectory">your/chosen/directory/goes/here</Set>
</New>
</Arg>
</New></Set>
Informational link:
http://wiki.eclipse.org/Jetty/Howto/Persisting_Sessions
The solution for tomcat is depicted in http://www.unicon.net/node/608 and it works like a charm for us.
But I don't know if this also applies to geronimo since we are not using it.
The thing is that Apache CXF takes the location attribute from WSDL file and replaces it with the server's URL, including the port. Is there any way to set the port manually to a specific value? If it was possible, I would like to do this from Spring...
The relevant part from WSDL:
...
<port binding="ns:binding" name="someUrl">
<soap:address location="http://localhost/url"/>
</port>
...
I took the basic endpoint configuration from Apache CXF website and added the publishedEndpointUrl="http://newurl:port/..." attribute to jaxws:endpoint element.