Overwrite HTTP Header in CXF (JAX-RS) - java

I would like to change the value of the HTTP Header "Connection" before sending a reply from the Server to the Client.
My Use Case: I have a JAX-RS Web Service that sits behind a Load Balancer. The Web Service Client sends requests with "Connection: Keep-Alive". Result: The connection is kept open, the Load Balancer does not balance :-)
So I would like my Web Service to reply every few hundred requests with a "Connection: close" to force the Client to open a new connection.
How can I do this with CXF?

You can use a ContainerResponseFilter to add your desired header to the response sent.
An example:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
#Provider
public class ResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.putSingle("Connection", "close");
}
}
Declare this class as a Provider in your javax.ws.rs.core.Application.

Related

Spring boot #PostMapping for login

I need to send an email every time a user logs into an account, but since SpringBoot is used I don't have a #PostMapping method for /login. What should I do?
From what you wrote, I assume that you want to send email only when user performs a successful login. You could write your implementation of AuthenticationSuccessHandler to send an email when user logs in succesfully.
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
#Component
public class MyNotifyingAuthSuccessHandler implements AuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
//send email (do it asynchronously if you can)
//redirect to your homepage (page where user should land after login)
}
}
Sending an email sometimes takes a lot of time, so consider doing that async not to block the login operation for too long, if your business requirements allow you to do that.

JAX-RS HTTP multipart request

How to implement multipart/form-data request (file upload) handler with JAX-RS without vendor specific libraries? So far I haven't found other way than to inject the HttpServletRequest and use the Servlet API to access the form data.
Yet HttpServletRequest#getParts() returns an empty list even the request is well formed (confirmed with Wireshark). I read I have to enable multipart configuration for the Jersey Servlet in the web.xml. However, I'm using #ApplicationPath annotation to automatically configure JAX-RS. So what is the correct way to handle multipart requests?
This code may inspire you
1) JAXRS App setup
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
#ApplicationPath("demo")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
packages("com.mycompany.demo").register(MultiPartFeature.class); // <= here!
}
}
2) JAXRS service
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadImage(
#FormDataParam("file") InputStream data,
#FormDataParam("file") FormDataContentDisposition fileInfo) {
...
}

Is there any Spring Security extension for REST services?

I am building REST API with Spring Boot and I use Spring Security. I started here but found some other tutorials and blog posts with this issue and managed to get it work after implementing custom stuff. This and this SO posts answer some of my questions, but I have one more:
Is there any extension that implements some of the things like REST AuthenticationEntryPoint that returns 401 instead of redirect, or JWT generating and verifying or I should just implement same things for every REST service?
Thank you for your answers.
I also use Springboot but for the security I rely on Apache Shiro project which fundamentally, depending how you store the users accounts (mines are in a MongoDb instance),
takes care of the login - currentUser.login(token);
If fails throws an exception so you can handle the response
If succeed inject the authentication cookie in the response
For any other request, decode the cookie and inject the user with the proper authorizations
In few words Shiro does not redirect the HTTPRequest because it just care for the security leaving further decision, redirect in your case, to your controller logic.
You can add it to your project with a simple Maven dependence.
#brownies.....
try this one....
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
#Component
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
#Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.cors().and().exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint).and().authorizeRequests()......
add above RESTAuthenticationEntryPoint and config in your security configuration class then it will return 401 if auth fails.

Grizzly Jersey swallowing exceptions

I'm building a Jersey Moxy service using the quickstart archetype at the end. My code works fine and I can get some JSON returned. However as I'm developing, if I make a mistake, say the request handler has an unsupported type, I will get an empty 500 response, which makes debugging difficult. For example, if I decorate an attribute incorrectly with #XmlElementRef, I will get a response like:
$ curl -i http://localhost:8080/myapp/test
HTTP/1.1 500 Internal Server Error
Date: Thu, 05 Sep 2013 10:27:55 GMT
Connection: close
Content-Length: 0
The server will act as if nothing is wrong:
Sep 5, 2013 11:27:46 AM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
Jersey app started with WADL available at http://localhost:8080/application.wadl
Hit enter to stop it...
I tried using a log config file with:
-Djava.util.logging.config.file=log.conf
This produces plenty of output, but still doesn't show any kind of exception.
I've tried looking into Grizzly config but I can't find a way turn off graceful error handling. Ideally I would like the server to throw an exception. Any suggestions on what I'm missing?
Here's my main code:
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.moxy.json.MoxyJsonConfig;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.net.URI;
import java.util.*;
public class Main {
// Base URI the Grizzly HTTP server will listen on
public static final String BASE_URI = "http://localhost:8080/";
/**
* Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
* #return Grizzly HTTP server.
*/
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
// in com.myapp package
final ResourceConfig rc = new ResourceConfig().packages("com.myapp").registerInstances(new JsonMoxyConfigurationContextResolver());
// create and start a new instance of grizzly http server
// exposing the Jersey application at BASE_URI
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
/**
* Main method.
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
final HttpServer server = startServer();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
#Provider
final static class JsonMoxyConfigurationContextResolver implements ContextResolver<MoxyJsonConfig> {
#Override
public MoxyJsonConfig getContext(Class<?> objectType) {
final MoxyJsonConfig configuration = new MoxyJsonConfig();
Map<String, String> namespacePrefixMapper = new HashMap<String, String>(1);
namespacePrefixMapper.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
configuration.setNamespacePrefixMapper(namespacePrefixMapper);
configuration.setNamespaceSeparator(':');
return configuration;
}
}
}
The code is almost identical to the example here:
https://github.com/jersey/jersey/tree/2.2/examples/json-moxy/src/main/java/org/glassfish/jersey/examples/jsonmoxy
Full archetype generation I used:
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.myapp -DartifactId=yarese-service -Dpackage=com.myapp \
-DarchetypeVersion=2.2
Suggestions gratefully received.
The exception is not getting propagated to the Grizzly layer, so it should be logged by Jersey. I haven't found what kind of Logger you have to enable, but looks like custom ExceptionMapper could help.
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.glassfish.grizzly.utils.Exceptions;
#Provider
public class MyExceptionMapper implements
ExceptionMapper<WebApplicationException> {
#Override
public Response toResponse(WebApplicationException ex) {
return Response.status(500).entity(Exceptions.getStackTraceAsString(ex)).type("text/plain")
.build();
}
}
As you've seen, Grizzly uses java.util.logging. If you'd like to see the stacktrace, you need to make sure the levels are correctly set in your log.conf file.
Here are settings that have worked for me in the past:
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=ALL
.level=ALL
org.glassfish.level=CONFIG

Jersey: Print the actual request

How can I view the actual request that Jersey generates and sends to the server? I am having issues with a particular request and the fellow running the webserver asked to see the full request (with headers and the such).
If you're just using Jersey Client API, LoggingFilter (client filter) should help you:
Client client = Client.create();
client.addFilter(new LoggingFilter(System.out));
WebResource webResource = client.resource("http://localhost:9998/");
ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON)
.get(ClientResponse.class);
Otherwise, you can again log both request and response on server using other LoggingFilter (container filter).
Since Jersey 2.23, there's a LoggingFeature you could use. The following is a bit simplified example, please note that you can register the feature on WebTarget as well.
Logger logger = Logger.getLogger(getClass().getName());
Feature feature = new LoggingFeature(logger, Level.INFO, null, null);
Client client = ClientBuilder.newBuilder()
.register(feature)
.build();
Response response = client.target("https://www.google.com")
.queryParam("q", "Hello, World!")
.request().get();
JavaDoc of LoggingFeature says that the request "and/or" the response is logged lol. On my machine, both are logged.
#ivan.cikic's answer is for Jersey 1.x. Here's how you do it in Jersey 2.x:
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.filter.LoggingFilter;
import org.json.JSONException;
import org.json.JSONObject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
...
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
client.register(new LoggingFilter());
This is irrelevant but I just have to complain: The new LoggingFilter is really annoying because it forces you to use Java Util Logging. It would be better if it gave me control over the logger. Seems like a step backwards in design.
All these answers are pretty close but they lack the setting to log the request and response body. At least with Jersey 2.30.1 this is how I accomplish logging the request and response including their respective bodies:
import javax.ws.rs.client.ClientBuilder;
import org.glassfish.jersey.logging.LoggingFeature;
import java.util.logging.Level;
import java.util.logging.Logger;
Logger logger = Logger.getLogger("LoggingFeature");
logger.setLevel(Level.ALL);
ClientBuilder.newClient()
.target("https://www.example.com")
.register(new LoggingFeature(
logger,
Level.ALL,
LoggingFeature.Verbosity.PAYLOAD_ANY,
8192))
.request()
.get();
Technically the Level.All and 8192 values could be null. I just provide them here to be concise.

Categories