ResourceAccessException received instead HttpServerErrorException - rest

I have invoked rest Api in my microservice using RestTemplate. However incase of exceptions i have returned error data with HTTP response code as 500. But when i receive this response in my microservice , it is received as ResourceAccessException instead of HttpServerErrorException. Hence i lose the response body which i returned in my rest API. Spring web is of version 5.2.5

Add below component
import java.io.IOException;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResponseErrorHandler;
#Component
public class RestTemplateResponseErrorHandler implements ResponseErrorHandler {
#Override
public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
return (httpResponse.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
|| httpResponse.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR);
}
#Override
public void handleError(ClientHttpResponse httpResponse) throws IOException {
if (httpResponse.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR) {
throw new HttpServerErrorException(HttpStatus.SERVICE_UNAVAILABLE);
} else if (httpResponse.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR) {
throw new HttpClientErrorException(HttpStatus.UNAUTHORIZED);
}
}
}
And handle exception like below while calling API
ResponseEntity<Object> res = null;
try {
res = restTemplate.exchange(completeUrl, HttpMethod.GET, null, Object.class);
if (res.getStatusCodeValue() == HttpStatus.OK.value()) {
}
} catch (HttpServerErrorException e) {
} catch (HttpClientErrorException e) {
}

The reason why you are getting this ResourceAccessException may be because you are using BufferingClientHttpRequestFactory. Without a full stack trace, I cannot be sure.
Look here for more details:
Throwing ResourceAccessException vs HttpClientErrorException for RestTemplate client in Spring

Related

Vertx JWKS/JWT verification throws a 500 with no errors logged

I have a very basic Vertx demo I'm trying to create that fetches a JWK from an endpoint and creates an RSAPublicKey for verifying a JWT signature:
package example;
import com.auth0.jwk.JwkException;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpServer;
import io.vertx.ext.web.Router;
import com.auth0.jwk.UrlJwkProvider;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.interfaces.RSAPublicKey;
import com.auth0.jwt.interfaces.RSAKeyProvider;
import java.security.interfaces.RSAPrivateKey;
public class MainVerticle extends AbstractVerticle {
#Override
public void start(Promise<Void> startPromise) throws Exception {
HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
router.route().handler(routingContext -> {
String authHeader = routingContext.request().getHeader("Authorization");
// pull token from header
String token = authHeader.split(" ")[1];
URL jwksEndpoint = null;
try {
jwksEndpoint = new URL("http://localhost:1080/jwks");
} catch (MalformedURLException e) {
e.printStackTrace();
}
JwkProvider jwkProvider = new UrlJwkProvider(jwksEndpoint);
RSAKeyProvider keyProvider = new RSAKeyProvider() {
#Override
public RSAPublicKey getPublicKeyById(String kid) {
//Received 'kid' value might be null if it wasn't defined in the Token's header
RSAPublicKey publicKey = null;
try {
publicKey = (RSAPublicKey) jwkProvider.get(kid).getPublicKey();
} catch (JwkException e) {
e.printStackTrace();
}
return publicKey;
}
#Override
public RSAPrivateKey getPrivateKey() {
return null;
}
#Override
public String getPrivateKeyId() {
return null;
}
};
Algorithm algorithm = Algorithm.RSA256(keyProvider);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("auth0")
.build();
DecodedJWT jwt = verifier.verify(token);
System.out.println(jwt);
routingContext.next();
});
router.route("/hello").handler(ctx -> {
ctx.response()
.putHeader("content-type", "text/html")
.end("<h1>Hello from non-clustered messenger example!</h1>");
});
server.requestHandler(router).listen(8888, http -> {
if(http.succeeded()) {
startPromise.complete();
System.out.println("HTTP server started on port 8888");
} else {
startPromise.fail(http.cause());
}
});
}
}
The problem is that when I make request to the /hello endpoint, the application immediately returns a 500. But nothing appears in the logs (even at debug level).
I've tried manually specifying the kid property to rule out the jwkProvider not returning properly
I'm at a loss at how to gain any more insight into what is failing.
Turns out to completely be my oversight. Wrapping that verifier.verify() call in a try/catch showed me that I was expecting an issuer. This is the same problem I was having while trying to achieve this in Quarkus! I was able to remove that from the builder and now this works perfectly.

Vertx instance variable is null when trying to access it from it's method

Below is verticle
package com.api.redis.gateway.verticle;
import java.util.UUID;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.redis.RedisClient;
import io.vertx.redis.RedisOptions;
public class SimpleRestChild extends SimpleRestServer{
RedisClient client;
#Override
public void start() {
// TODO Auto-generated method stub
super.start();
client = RedisClient.create(vertx, new RedisOptions().setHost("127.0.0.1").setPort(6379));
client.subscribe("channelForServiceToPublish", handler -> {
if(handler.succeeded())
System.out.println("SimpleRestServer subscibed to the channel successfully");
});
}
public void handleSubscription(RoutingContext routingContext) {
JsonObject requestAsJson = routingContext.getBodyAsJson();
requestAsJson.put("uuid", getUUID());
// this client object is null.
client.set("request", requestAsJson.toString(), handler ->{
System.out.println("Simple server is setting value to redis client");
if(handler.succeeded()) {
System.out.println("Key and value is stored in Redis Server");
}else if(handler.failed()) {
System.out.println("Key and value is failed to be stored on Redis Server with cause : "+ handler.cause().getMessage());
}
});
client.publish("channelForServerToPublish", "ServiceOne", handler -> {
if(handler.succeeded()) {
System.out.println("Simple Server published message successfully");
}else if(handler.failed()) {
System.out.println("Simple Server failed to published message");
}
});
routingContext.vertx().eventBus().consumer("io.vertx.redis.channelForServiceToPublish", handler -> {
client.get("response", res ->{
if(res.succeeded()) {
JsonObject responseAsJson = new JsonObject(res.result());
if(responseAsJson.getString("uuid").equalsIgnoreCase(requestAsJson.getString("uuid"))) {
routingContext.response().setStatusCode(200).end(res.result());
}
}else if(res.failed()) {
System.out.println("Failed to get message from Redis Server");
routingContext.response().setStatusCode(500).end("Server Error ");
}
});
});
}
private String getUUID() {
UUID uid = UUID.randomUUID();
return uid.toString();
}
}
And below is the main verticle from where the above verticle is getting deployed and on any request to httpserver it's hanlder method is getting called.
package com.api.redis.gateway.verticle;
import io.vertx.core.AbstractVerticle;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.redis.RedisClient;
import io.vertx.redis.RedisOptions;
public class SimpleRestServer extends AbstractVerticle{
#Override
public void start(){
int http_port = 9001;
vertx.deployVerticle("com.api.redis.gateway.verticle.SimpleRestChild", handler -> {
if(handler.succeeded()) {
System.out.println(" SimpleRestChild deployed successfully");
}
});
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
SimpleRestChild child = null;
try {
child = (SimpleRestChild) Class.forName("com.api.redis.gateway.verticle.SimpleRestChild").newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
router.route("/subscription").handler(child::handleSubscription);
vertx.createHttpServer().requestHandler(router::accept).listen(http_port);
System.out.println("Server started at port : " + http_port);
}
}
When handleSubscription is getting called for any "/subscription" request. client object is coming as null.
As per my understanding two objects are getting created here. One with start() and other not having start().
I want to initialize Redisclient once.And use this object when handleSubscription() will get called for any request to "/subscription".
How to achieve this ?
How to fix this problem.
the requests may be coming in before the client initialization is actually complete.
AbstractVerticle has two variations of start():
start(), and
start(Future<Void> startFuture)
the overloaded version with the Future parameter should be used to perform potentially long-running initializations that are necessary to do before the Verticle can be considered deployed and ready. (there's a section dedicated to this topic in the docs).
so you might try changing your code as follows:
public class SimpleRestChild extends SimpleRestServer {
RedisClient client;
#Override
public void start(Future<Void> startFuture) {
client = ...
// important point below is that this Verticle's
// deployment status depends on whether or not
// the client initialization succeeds
client.subscribe("...", handler -> {
if(handler.succeeded()) {
startFuture.complete();
} else {
startFuture.fail(handler.cause());
}
);
}
}
and:
public class SimpleRestServer extends AbstractVerticle {
#Override
public void start(Future<Void> startFuture) {
int http_port = 9001;
vertx.deployVerticle("...", handler -> {
// if the child Verticle is successfully deployed
// then move on to completing this Verticle's
// initialization
if(handler.succeeded()) {
Router router = ...
...
// if the server is successfully installed then
// invoke the Future to signal this Verticle
// is deployed
vertx.createHttpServer()
.requestHandler(router::accept)
.listen(http_port, handler -> {
if(handler.succeeded()) {
startFuture.complete();
} else {
startFuture.fail(handler.cause());
}
});
} else {
startFuture.fail(handler.cause());
}
}
using this type of approach, your Verticles will only service requests when all their dependent resources are fully initialized.

Californium Framework CoAP and PUT request

I am trying to do a request to coap server (er-rest-example) using Californium.
I succesfully do a POST request.
But with PUT I am getting a BAD REQUEST, I try using this URLs in url:
coap://[aaaa::c30c:0000:0000:0002]:5683/actuators/leds
coap://[aaaa::c30c:0000:0000:0002]:5683/actuators/leds?
coap://[aaaa::c30c:0000:0000:0002]:5683/actuators/leds?color=r
But with no one get success.
What I am doing wrong?.
This is my simple script:
package coap_client;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
public class cliente {
public static void main(String[] args) throws Exception {
Timer timer;
timer = new Timer();
TimerTask task = new TimerTask(){
#Override
public void run(){
String url="coap://[aaaa::c30c:0000:0000:0002]:5683/actuators/leds";
URI uri= null;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
e.printStackTrace();
}
CoapClient client = new CoapClient(uri);
CoapResponse response = client.put("color=r",MediaTypeRegistry.TEXT_PLAIN);
System.out.println(response.isSuccess());
if (response!=null) {
byte[] myreponse=response.getPayload();
String respuesta2 = new String(myreponse);
System.out.println(respuesta2);
}
}
};
timer.schedule(task, 10,10*1000);
}
}
In Contiki er-rest-example, see the POST/PUT handler(1) for the LED CoAP resource. It expects a mode param without which you will get a BAD_REQUEST as response. I assume that has to go in the request body.

How to verify digital signature of SOAP call?

I wrote an interceptor in Apache CXF and get a SoapMessage. How do I get the raw XML from the SOAP message without changing the data to hurt the verification of the digital signature?
I refer to org.apache.cxf.binding.soap.SoapMessage:
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.binding.soap.interceptor.EndpointSelectionInterceptor;
import org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class XmlSignatureVerifyInInterceptor extends AbstractSoapInterceptor {
private static final Logger log = LogManager.getLogger(XmlSignatureVerifyInInterceptor.class);
public XmlSignatureVerifyInInterceptor() {
super(Phase.READ);
log.entry();
addAfter(ReadHeadersInterceptor.class.getName());
addAfter(EndpointSelectionInterceptor.class.getName());
}
#Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
log.entry(soapMessage);
}
}
Cheers and thank you in advance!
Fireball
If you are refering a javax.xml.soap.SOAPMessage, and you want a String result of XML, use ByteArrayOutputStream:
SOAPMessage message;
ByteArrayOutputStream out = new ByteArrayOutputStream();
String msg = "";
try {
message.writeTo(out);
msg = out.toString("UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
I use UTF-8 as encoding, you can change it to any others.

SSL "Peer not Authenticated" error with HttpClient 4 - works in some case but not others

I have a wildcard cert for *.mydomain.com (the names have been changed to protect the innocent...that is NOT the real domain :) )
When using a correctly implemented Java HttpClient 4 (the issue is not seen in FF), Service calls made via HTTPS to api.mydomain.com are successful where as identical service calls made to non-production subdomains of mydomain.com (developer.mydomain.com, api-beta.mydomain.com, api-uat.mydomain.com) generate this Exception with the Test harness code below:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.mydomain.httpclientexample.HttpClientTestv2.main(HttpClientTestv2.java:54)
While the SLL cert on developer.mydomain.com, api-beta.mydomain.com & api-uat.mydomain.com appears to be the same WC cert as api.mydomain.com, the exception is not seen on api.mydomain.com but it is on the other sub-domains. The code works on api-na.mydomain.com and should work on the non-production subdomains.
Any ideas?
Client code: As you can see, I can easily change the ADDRESS_VALIDATION_SERVICE_URI I want to call. The api.mydomain.com one works without the SSLPeerUnverifiedException; the other three URIs throw the exception...
package com.mydomain.httpclientexample;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class HttpClientTestv2 {
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://developer.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-beta.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-uat.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String APIKEY_ATTRIBUTE_NAME = "apikey";
public final static String APIKEY_ATTRIBUTE_VALUE = "2c90bc83e821364ffa557486c3e2a44e";
/**
* #param args
*/
public static void main(String[] args) {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ADDRESS_VALIDATION_SERVICE_URI);
System.out.println("executing request" + httpPost.getRequestLine());
//set a request header
httpPost.setHeader(APIKEY_ATTRIBUTE_NAME , APIKEY_ATTRIBUTE_VALUE);
//add the xml body
StringEntity postBody = null;
try {
postBody = new StringEntity(getXMLDoc(),"UTF-8");
} catch (UnsupportedEncodingException uee) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in UnsupportedEncodingException catch block");
System.out.println("----------------------------------------");
uee.printStackTrace();
}
httpPost.setEntity(postBody);
HttpResponse response;
try {
response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println("Content:" + EntityUtils.toString(entity));
EntityUtils.consume(entity);
// entity.consumeContent();
}
} catch (ClientProtocolException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
} catch (IOException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
private static String getXMLDoc() {
StringBuffer XMLDoc = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?><AddressValidationRequest xmlns=\"http://api.mydomain.com/schema/checkout/1.0\">")
.append("<Header><MaxAddressSuggestions>5</MaxAddressSuggestions></Header>")
.append("<Address><Line1>17243 S. Mill Ln</Line1><Line2/><City>Ocean View</City><MainDivision>DE</MainDivision><CountryCode>US</CountryCode><PostalCode>19970</PostalCode></Address>")
.append("</AddressValidationRequest>");
return XMLDoc.toString();
}
}