I am working on a project developed with Spring Boot using version 8.5.9 of Tomcat.
The application offers RESTfull web services in JAX RS.
In the Prod environment, sometimes I get an error 503 Service not available, but I can not reproduce it because I use my local Mock.
Is there a way to reproduce the error locally? Like putting the TomCat on hold in unavailable for a moment?
According to the MDN, HTTP 503 Service Unavailable server error means :
... response code indicates
that the server is not ready to handle the request.
The common causes are :
a server that is down for maintenance or that is overloaded.
To reproduce this error response in a natural way, you could so overloaded Tomcat.
To do it change the maximum number of simultaneous requests that can be handled by Tomcat.
If you use an embedded tomcat, set the server.tomcat.max-threads Spring Boot property with a weak value easily reachable such as :
server.tomcat.max-threads = 1
Otherwise, if you use our own Tomcat installation, set maxThreads with a weak value in the Connector element of the server.xml configuration file :
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
...
maxThreads="1"/>
You can mock it through WireMock using Java.
public static WireMockServer wireMockServer = new WireMockServer(8089);
wireMockServer.start();
final WireMock wireMock = new WireMock(8089);
wireMock.register(WireMock.get(WireMock.urlEqualTo("/conf"))
.willReturn(WireMock.aResponse()
.withStatus(503)));
Hit localhost:8089/conf to get 503 Service Unavailable
Related
I'm developing project on a Spring Security and everything was going fine until I loaded my project to a production server. I have only http on my local machine but there is https on a production server.
And I faced an error (in case of login error):
Mixed Content: The page at 'https://my.production.com/login' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://my.production.com/api/login?error=bad-credentials'. This request has been blocked; the content must be served over HTTPS.
and (in case of success login):
Mixed Content: The page at 'https://my.production.com/login' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://my.production.com/authorities'. This request has been blocked; the content must be served over HTTPS.
I asked my vendor about this issue but they say that "There is no https between you app and nginx, so this is your app problem"...
I tried this, but this solution looks very weird and doesn't solve problem (It requires adding a lot of configuration classes and I guess it shouldn't be so hard). Actually I'm very confused how can this happen, why isn't it the default behavior to redirect to the schema that the request was made...
Also I tried adding this to my Spring Security config:
.and().requiresChannel().anyRequest().requiresSecure()
but this only causes ERR_TOO_MANY_REDIRECTS on my local machine and on a production server...
This didn't help too:
http.portMapper()
.http(8080).mapsTo(8443);
I'm not using Spring boot, but also tried this, no help.
Success authentication configuration looks like this:
SavedRequestAwareAuthenticationSuccessHandler successHandler = new
SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setDefaultTargetUrl(env.getProperty("app.authenticationSuccessUrl"));
When Apache Tomcat is running behind a HTTPS (reverse) proxy, there may be some configuration required for links and redirects to work properly.
Open conf/server.xml, find the Connector element, add the following attributes if not already present:
proxyName - set to your domain name.
proxyPort - set it to 443 if you are using the standard https port.
scheme - set to "https" if site is accessed with https.
secure - set to "true" for https.
<Connector proxyName="my.production.com" proxyPort="443" scheme="https" secure="true" ...>
Reference: Apache Tomcat 7: The HTTP Connector
I have an application that uses spring to the calling rest services. Specifically, the RestTemplate class. Right before I make the call to:
restTemplate.execute(
url,
method,
new JSONRequestCallback(headerParams),
new JSONResponseExtractor(containerType, cls));
method, I check the value url in the call. I quite literally can copy and paste the value of that url (lets call it http://myHost.net:8081) into a browser in the same network domain as my tomcat 8 (the web container I am using in eclipse), and the service response is successfully returned from the browser. However, the execute method throws an exception upon return:
org.springframework.web.client.ResourceAccessException: I/O error: myHost.net; nested exception is java.net.UnknownHostException: myHost.net
Now, the web service I am calling is on the internet while my dev environment is not. To address, we opened an appropriate port in our firewall and I can successfully access the service endpoint from a browser (as indicated above) by properly configuring the proxy settings on the browser. Similarly, from my Tomcat 8 configuration within eclipse, I have added the following launch configuration VM arguments:
-Dhttp.proxySet=true
-Dhttp.proxyHost=myHost.net
-Dhttp.proxyPort=8080
but as I have indicated above, I still get the unknown host exception.
By the way, I did see a similar issue here (Spring RestTemplate and Proxy Auth) but that required a coding solution in the spring code. I was hoping for a configuration solution as our system will not have the proxy issue in the operational environement.
I am hoping someone might have some ideas as to either what I might be doing wrong, and/or how I might be able to better diagnose my problem. Thank you!
I am facing an intermittent issue on tomcat while making a rest call.
Setup:
ApplicationA running on standalone tomcat on portX
ApplicationB running on another standalone tomcat on portY
both the tomcat installations are on the same machine.
Java version is JRE6
Following parameters are added to the JVM_OPTS in bash profile
-Dhttp.proxyHost=[host] -Dhttp.proxyPort=[port] -Dhttp.nonProxyHosts=localhost
Application A makes a rest call to application B using Spring RestTemplate and gets a 503 error (Service unavailable) response.
The URL being used is http://localhost:portY/ApplicationB/restapipath
I cause is that the requests to localhost are going through the proxy defined in JVM_OPTS, but as per my understanding all localhost urls should be called without using any proxy.
This issue is happening intermittently, but once it starts it continues till I restart the ApplicationA tomcat server.
Also, my understanding is that any calls made through Spring RestTemplate will honour the JAVA_OPTS proxy settings without any additional handling in the code.
Any pointers, help is appreciated.
After hours of frustration I found the solution.
The problem was that my understanding about JVM proxy parameters was incorrect.
Parameters in JVM_OPTS in bash profile -Dhttp.proxyHost=[host] -Dhttp.proxyPort=[port] are actually not used automatically when using Spring RestTemplate. These parameters have to be fetched using System.getProperty('http.proxyHost') and then explicitly set in the DefaultHttpClient
Now the issue in my code was that there was a single httpClient bean defined in the applicationContext.xml which was being used by both the rest calls. The non-proxy rest call worked fine until the with-proxy rest call updated httpClient object with the proxy details.
Solution was to user separate httpClient objects for both rest calls.
Summary: I have an SAAJ Client that calls a remote Web Service over HTTPS. Both Client and Server authentication via certificates is required. I can successfully invoke the service when running a JUnit test in my IDE, but fail to connect when running in JBoss.
Keystore/Truststore Configuration Details: In both the IDE and JBoss, I'm setting the keystore and truststore via system properties: javax.net.ssl.keyStore, javax.net.ssl.keyStorePassword, javax.net.ssl.trustStore, javax.net.ssl.trustStorePassword
Logging Configuration: In JBoss, I've enabled SSL Debug logging via the system property: javax.net.debug=SSL. I've also enabled CXF logging via a logging.properties file.
JBoss SSL Logging Output Summary:
SSL logging shows no WARN or ERROR logs
SSL logging shows a session is established at the time of the call to the remote service
JBoss CXF Logging Output Summary:
CXF logging shows that the POST is sent to the service via Conduit null.http-conduit
CXF logging shows this conduit is "configured for plain http", has "No Trust Decider", and has "No Auth Supplier" (I'm not entirely sure what all of this means, but it sounds relevant)
Stack Trace: Here's the actual stack trace I'm getting
Caused by: javax.xml.soap.SOAPException: JBWS024004: SOAP message could not be sent
at org.jboss.wsf.stack.cxf.saaj.SOAPConnectionImpl.call(SOAPConnectionImpl.java:124)
at my.client.soap.MySAAJClient.invoke(MySAAJClient.java:37) [my-client-0.0.1-SNAPSHOT.jar:]
... 17 more
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '403: Forbidden' when communicating with https://remote.service.url.here/
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1542)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1502)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1309)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:627)
at org.jboss.wsf.stack.cxf.saaj.SOAPConnectionImpl.call(SOAPConnectionImpl.java:120)
... 19 more
Other Information
I don't have direct access to the logs of the remote web service, but I'm told that they "don't show anything"
CXF comes into play because it is used by JBoss. I don't have any CXF dependencies included in my project and it's not in play when I run the code in my IDE.
What I've Tried: I've been focused on CXF because again, this all runs fine when executed in my IDE where CXF is not in play and the CXF log that says the conduit has been "configured for plain http" scares me. I've tried including a jboss-cxf.xml, jbossws-cxf.xml, or cxf.xml configuration file in my WAR that includes the keystore and truststore configuration. This has not worked and I can't even tell that CXF is seeing these files.
My Questions (Updated)
Is there any way to get JBoss/CXF to see that this is a secure connection and use the keystore/truststore configured via system properties?
Is there any way for me to direct JBoss (via jboss-deployment-structur.xml maybe?) to use a different SAAJ implementation for my deployment?
Do you have any thoughts on other things I should be looking into?
Update 1
I believe I've confirmed that the JBoss-CXF integration is the issue. I was able to remove JBoss's SOAPConnectionImpl by modifying the file {JBOSS_HOME}/modules/system/layers/base/org/jboss/ws/saaj-impl/main/module.xml. I commented out the module dependency <module name="org.jboss.ws.jaxws-client" services="import"/>.
After making this change, my application was able to connect to the remote service with no issues.
Although this shows that the JBoss-CXF integration is this issue, I can't modify the deployment environment in this way. I need to identify another solution.
I'd go for system properties (or at least knowing the configuration of the system) as they might override whatever you specify in your deployment.
What version of cxf is used on the deployment environment? Do you have any info on the configuration of cxf on your deployment environment? From the documentation (http://cxf.apache.org/docs/ws-security.html), I can see you need to configure WSS4J interceptors for cxf 2.0.x or earlier, so you could check if this is okay on your deployment environment.
We have a couple of web services (REST+SOAP) running in Apache Camel 2.13.0 based on CXF version 2.7.10 which use SSL and basic authentication all the way, which worked pretty fine.
Due to a version upgrade of Camel to version 2.14.0, which internally uses now CXF 3.0.1, our services now stoped working as of a Protocol mismatch for port x: engine's protocol is http, the url protocol is https - the configuration however was untouched during the version-update.
...
Caused by: java.io.IOException: Protocol mismatch for port 8081: engine's protocol is http, the url protocol is https
at org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory.createJettyHTTPServerEngine(JettyHTTPServerEngineFactory.java:271)
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.retrieveEngine(JettyHTTPDestination.java:121)
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.finalizeConfig(JettyHTTPDestination.java:154)
... 48 more
I therefore created a new eclipse project which simplifies things to its bare minimum (just a simple SOAP service with two endpoints which both use either HTTP or HTTPS).
The configuration of the Jetty server can be seen here
The actual service is configured as bean to later on use this bean within Camel's route:
#Bean(name="endpoint1ServiceSSL")
public CxfSpringEndpoint endpoint1ServiceSSL() throws Exception
{
final CxfSpringEndpoint factoryBean = new CxfSpringEndpoint();
factoryBean.setServiceClass(EnhancedEndpoint1Endpoint.class);
factoryBean.setWsdlURL("classpath:/wsdl/test.wsdl");
factoryBean.setEndpointName(new QName(NAMESPACE, "Endpoint1ServicePort", PREFIX));
factoryBean.setServiceName(new QName(NAMESPACE, "Endpoint1_Service", PREFIX));
factoryBean.setAddress(env.getProperty("services.address.ssl")+"/endpoint1");
factoryBean.setDataFormat(DataFormat.POJO);
final Map<String, Object> properties = new HashMap<>();
properties.put("schema-validation-enabled", "true");
properties.put("allowStreaming", true);
factoryBean.setProperties(properties);
factoryBean.getInInterceptors().add(new LoggingInInterceptor());
factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
return factoryBean;
}
NAMESPACE and PREFIX are just some constants, nothing important for this example. The bean gets certain values like the service's base address from a property file which just contains values like:
services.address = http://0.0.0.0:8080/
services.address.ssl = https://0.0.0.0:8081/
and other ssl keystore related stuff. Note that CXF will use the jetty configuration beans during its initialization process and therefore create a SSL secured connection for HTTPS invoked URLs - at least it did before the version-upgrade.
The route now can access the service using this very simple route:
public class Endpoint1Route extends RouteBuilder
{
#Override
public void configure() throws Exception
{
from("cxf:bean:endpoint1Service")
.to("log:endpoint1Service");
from("cxf:bean:endpoint1ServiceSSL")
.to("log:endpoint1ServiceSSL");
}
}
This worked well with CXF 2.7.10 and Camel 2.13.0 - but as already stated above, after the upgrade there is a protocol mismatch for some reason (as hopefully can be seen from the github-project I've linked; after cloning the project, you need to execute generate-sources and then start ServicesApp as Java standalone application).
I've also created a new branch for the version-upgrade to simplify the switch between both versions.
Anyone has any idea why the configuration of Jetty, which worked before the version upgrade, now returns this protocol mismatch error? Am I missing any updated libraries I haven't figured out yet? Or am I configuring something wrong in first place?
#Edit:
After further testing I am now sure that some API changes inside CXF led to the problems as the bean which configures the SSL secured Jetty server is no longer executed on startup, while with version 2.7.10 the bean gets executed.
This changes the actual question to "How to configure a SSL secured Jetty Server in Apache CXF 3.0.1"
#Edit #2:
I managed to get a SSL secured Jetty server running in Camel 2.14.0/CXF 3.0.1 but only via XML configuration. As we prefer Java config over XML, we are still looking for a method to configure Jetty with SSL in CXF 3.0.1 - The skip of the jettySSLEngineFactory Spring bean, though, seems like a further CXF bug to me.
To clarify, in CXF 2.7.x a jetty server could get configured in Java on creating a Spring bean which returns a JettyHTTPServerEngineFactory instance, as showcased in the master-branch of the github project linked above. This bean was used by CXF while configuring the server instance and therefore set up the SSL secured Jetty server. However, in CXF 3.0.1 this bean no longer is invoked - only JettyDestinationFactory which I have no clue on how to set up a SSL secured server with. Also the XML example prestended in the docs gives no clue on how to set up Jetty with SSL using a destination factory.
As the engine-factory inside the XML example in the docs actually maps to a JettyHTTPServerEngineFactory and Jetty configuration over XML is working fine, this seems to pinpoint a Spring bean injection bug inside CXF 3.0.1 to me.
As the protocol mismatch error was caused due to CXF skipping the bean initialization of the jetty configuration bean. However, it turned out that through the internal Spring version change in CXF extending a Spring configuration class leads to certain issues.
On removing extends SoapSSLConfig in CxfEndpointConfig and injecting this configuration class using #Import(SoapSSLConfig.class) the bean initialization and therefore the Jetty server configuration is executed as before.
The code used to be:
#Configuration
#ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class CxfEndpointConfig extends SoapSSLConfig
{
...
}
which lead to injection failures. Replacing the above code with the below solved the problem.
#Configuration
#ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
#Import(SoapSSLConfig.class)
public class CxfEndpointConfig
{
...
}