How can a JAX-RS REST service have authentication handled by annotations? - java

I have a REST api written with JAX-RS, and I need to add authentication to it. So far all the information I've been able to find about it has suggestions for doing it via spring, which I'm not using. Is there something already existing, or would it be easy to write, something that will let me annotate either a method, or the entire class which would force auth headers to be present?
I'm using tomcat6 and jersey, if that matters.
Something like:
#Path("api")
public class Api {
#GET
#AuthenticationRequired
public Response getInfo(...) {...}
}

I think you want import javax.annotation.Security.RolesAllowed;
The annotation itself looks like this
#Path("/helloworld")
#RolesAllowed({"ADMIN", "ORG1"})
public class helloWorld {
#GET
#Path("sayHello")
#Produces("text/plain")
#RolesAllowed("ADMIN")
public String sayHello() {
return "Hello World!";
}
}

I would manage security at the container level. Here's a good writeup if you happen to be using Apache CXF:
http://cxf.apache.org/docs/secure-jax-rs-services.html
And here's an example for Glassfish:
http://www.butonic.de/2010/06/18/a-simple-jax-rs-security-context-example-in-glassfish/
Here's one more link, which discusses JSR 250 annotations (e.g. #RolesAllowed):
http://www-01.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/twbs_jaxrs_impl_securejaxrs_annotations.html

Related

Camel With Cxf and Routing

I was doing some research on Camel - CXf integration and am confused about the below scenario.
So i implemented a Rest Endpoint
#Path("/authenticate")
public interface Sample {
#GET
#Path("/handshake")
#Produces(MediaType.TEXT_PLAIN)
public Response handshake();
#POST
#Path("/login")
#Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
#Produces(MediaType.APPLICATION_JSON)
public Response login(LoginRequest request) throws JsonGenerationException, JsonMappingException, IOException;
}
And the implementation as below
public class SampleImpl implements Sample{
#Context
private HttpHeaders headers;
#Autowired
CamelContext context;
public Response handshake()
{
System.out.println("HandShake Executed Successfully");
return Response.status(Status.OK).entity("This is a Message after Routing").build();
}
public Response login(LoginRequest request) throws JsonGenerationException, JsonMappingException, IOException {
System.out.println("The Rquest objecr is Received "+request);
return Response.status(Status.OK).entity(mapper.writeValueAsString(request)).build();
}
}
The Route
<camel:from uri="cxfrs:bean:SampleRestEndPoint?bindingStyle=SimpleConsumer"></camel:from>
routes it into the implementation. But since the implementation returns a response object am confused how to build the routes around this.
Once the call comes into the implementation how can I execute the
other routes and sent a response back?.In this case the implementation returns a custom object.
How are the other routes attached to a CXF route?.
Should my CXF Implemenation always return a void type?. As i see
that, to get access to Exchange object camel need the return type to
be void
Do I completely ignore the implementation and go with the "to" steps
and modify it in exchange body for the required response?.
Any pointers will be appreciated.
Dude, take a look at this - http://bushorn.com/camel-cxf-geocoder-example/
The above example is not REST though, but usage of CXF with Camel route is same.
I will do these mandatory steps:
Avoid beans/custom classes - try to use the camel framework capabilities.
Use XML - Spring/Blueprint DSL
Please look at the following thread.
Apache Camel and web services
I have successfully implemented web service consumption using camel and Apache CXF. If you have doubts, I can help you out.
Thanks,
Gautham
#GauthamHonnavara - that is an implementation of a JS webservice with an assosiated processor however it doesnt assosiate any direct route to the endpoint.Also my question was specific to JAX-RS where you cannot generate a service class from wsdl.
Assume this use case that u need a customer to invoke the endpoint and then go through say another 5 steps, reach out to another webservice etc and then sent a response back. The above implementation sents a response back in the webservice implementation bean itself.
So to avoid this create a simple interface with the producer consumer etc, just like in my question and then make each method void if you want to inject the Exchange( if needed. ) and use below configuration
<!-- Created the CXF End Point For the Calls to Come IN -->
<cxf:rsServer id="RestEndPoint" address="/rest"
serviceClass="com.poc.camel.cxf.service.incoming.xxx"
loggingFeatureEnabled="true" loggingSizeLimit="20">
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" >
<!-- <constructor-arg ref="customObjectMapper" type="org.codehaus.jackson.map.ObjectMapper"/> -->
</bean>
</cxf:providers>
</cxf:rsServer>
Trick is to use the service class tag. If the interface is provided there then it doesn't need a concrete implementation from CXF.
Hope this helps. Let me know

Using PATCH with Jersey Client API for unit testing

I am working on a REST API implementation using Jersey. For PATCH (partial updates), I have implemented my own custom implementation of PATCH since Jersey does not support it.
Now I am trying to figure out how to write functional tests around that implementation. I am using jersey test framework for other methods (PUT, POST, GET, DELETE) that has that support available in that framework.
Is there a way where in I can extend jersey test framework implementation to write my functional tests for PATCH?
If not, are there any other test frameworks available that I can use to test my Jersey PATCH implementation?
If anyone can provide any examples, that would be great.
Assuming your implementation consists of a custom annotation like this
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
#HttpMethod("PATCH")
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface PATCH {}
Trying to do something like this with the Client
String response = target.request().method("PATCH", Entity.text("Hello"), String.class);
by default is not supported, and will an exception like
java.net.ProtocolException: Invalid HTTP method: PATCH
This is not a problem with the Client API directly, but with the lower level Java APIs. Seems to be some security restriction.
With the Client API we can override this by setting a property
HttpUrlConnectionProvider.SET_METHOD_WORKAROUND to true
In the JerseyTest, one way to configure the Client is to override configureClient, and set the property with the ClientConfig. You could just as easily set the property on the Client itself, but staying in the spirit of the JerseyTest framework (where we don't need to explicitly access the Client, the example below will just just override the method
public class PatchTest extends JerseyTest {
#Path("patch")
public static class PatchResource {
#PATCH
#Produces(MediaType.TEXT_PLAIN)
public String getPatch(String request) {
return "Patched " + request;
}
}
#Override
protected void configureClient(final ClientConfig config) {
config.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
}
#Override
public Application configure() {
return new ResourceConfig(PatchResource.class);
}
#Test
public void doPatchTest() {
WebTarget target = target("patch");
String response = target.request().method("PATCH", Entity.text("Hello"), String.class);
Assert.assertEquals("Patched Hello", response);
System.out.println(response);
}
}
To send the HTTP PATCH via JAX RS Client API without any extra configuration:
client.target("$baseUrl$restUsersUrl/$userId")
.request("application/json")
.build("PATCH", Entity.entity(json2Update, MediaType.APPLICATION_JSON))
.invoke()
Annotation #PATCH is now available in JAX-RS 2.1. You can implement this HTTP method on the server side like:
#PATCH
public Response updateResource() { ... }
As for the client side, you can do something like:
Response r = ClientBuilder.newClient()
.target("http://localhost:8080/patch")
.request()
.build("PATCH", Entity.text("patch"))
.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true)
.invoke();
Where SET_METHOD_WORKAROUND is used to avoid the protocol exception, as indicated by #peeskillet:
java.net.ProtocolException: Invalid HTTP method: PATCH
With simple Strings this works for me. But does anyone know how to do this when the Patch method does not accept and return a simple String? See my example below.
The return type in the Response differs from the type of the passed argument. Both of which are not simple types.
Instead of a 200, I always get a 400 and/or the message that it cannot construct the ObjectPatch instance. And I understand that, since it is an interface with only an apply method. But somehow on runtime it manages to construct an AttentionPatchResource object from it anyway. Unfortunately not when using the JerseyTest framework.
#PATCH
#Path("/something")
#Produces(MediaType.APPLICATION_JSON)
#Consumes({ PatchMediaTypes.APPLICATION_MERGE_PATCH_JSON, PatchMediaTypes.APPLICATION_JSON_PATCH })
public Response updateAttention( //
#Parameter(schema = #Schema(implementation = AttentionPatchResource.class)) ObjectPatch patch) {
Attention attention = attentionService.find();
AttentionPatchResource patchResource = attentionAdapter.toPatchResource(attention);
AttentionPatchResource patchedResource = patch.apply(patchResource);
Attention patchedAttention = attentionAdapter.fromPatchResource(attention, patchedResource);
AttentionResource resource = attentionAdapter.toResource(patchedAttention);
return Response.status(Status.OK).entity(resource).build();
}

How to avoid class level #path in web service to handle all web service calls

I am writing a web service like
#Path("/pathName")
public class LoginServiceComponent {
#GET
#Path("/methodPathName/{param}")
#Produces(MediaType.TEXT_HTML)
public String getVoterByVoterId( #PathParam("param") String param)
{
.................
}
}
Here my url to access web service is http://www.abc.com/pathName/methodPathName/1
Here i have 10 methods.Is there any possibility to remove class level #Path means i have only one web service class in my project.So i dont want to use class level #Param repeatedly.
Thanks in advance...
If you want to avoid the #Path on the class so your URL's don't have the "pathName" in the path, I don't think you can remove the #Path on the class entirely. But I have used the #Path class annotation of #Path("/") and was able to get just URL to be just http://www.abc.com/methodPathName/1 (if that's what you're trying to do).

Jax-rs Regex path

I have this Jax-rs service interface:
#GET
#Path("{id: ^((?!_ah).)*$}")
#Produces(MediaType.TEXT_HTML)
public Response getStuff(#PathParam("id") String id, #Context HttpHeaders headers,
#Context UriInfo uriInfo, #Context SecurityContext securityContext);
The goal of this interface is to catch all character sequence except for:
_ah/foo
_ah/foo/bar
Or anything start starts with _ah
I tried the regex in: http://rubular.com/
And from what it seems it works as expected. However my problem now is that when I access a the supposedly bypassed path I get this:
Could not find resource for relative : /_ah/admin of full path: http://127.0.0.1:8888/_ah/admin
My app runs on GAE, so when running on dev mode, this _ah path is used for management servlets on the SDK runtime.
What am I missing? Isn't it that when the #Path filter does not match it will bypass it? So why do I get Cannot find resource problem?
If I don't put: #Path("{id: ^((?!_ah).)*$}") the servlets under _ah path works fine. Isn't it that the _ah path is already bypassed and should be accessible again?
I ran into this problem while upgrading RestEasy to 3.0.10. I had a #Path("{id}") and #Path("jobs") conflict that came from legacy code. Because of 3rd party apps, I couldn't change my rest endpoints without a lengthy process. Fortunately the regex solution did work for me. Though I can't say why it didn't work for the original poster.
This caused me a few days of headache both figuring out where my problem was and how to solve it. I share this in case you are in a similar situation and changing your rest endpoint isn't a viable option.
Original class:
#Path("device")
public class DeviceApi
{
#PUT
#Path("{id}")
public Device deviceAction(..., Device device) {...}
}
Conflicting regex class:
#Path("device")
public class JobsDeviceApi
{
#PUT
#Path("jobs")
public void moveJobs(..., Jobs jobs)
}
Modified DeviceApi class that works:
#Path("device")
public class DeviceApi
{
#PUT
#Path("{id: ^(jobs)}")
public Device deviceAction(..., Device device) {...}
}
Obviously you can put whatever regex you want in there. I only need it to ignore that single path so I used the KISS principle (Keep it simple stupid).

JAX-RS: case-insensitive paths

I have anchored REST services/methods to URI template by #Path annotation. It looks like as usual:
#GET
#Path("/message")
#Produces("application/json")
public Response getMessage() { ... }
But my REST service has to be case-insensitive. Now I'm using regular expression in #Path in all my code like that:
#GET
#Path("/{message:[mM][eE][sS][aA][gG][eE]}")
#Produces("application/json")
public Response getMessage() { ... }
This looks weird. Is there something I overlooked in specification (I hope not, see this) or has any of JAX-RS implementations special feature for that? Now I'm using JBoss RESTeasy.
Thanks.
i don't know resteasy, but if it supports all java regex syntax, you could use (?i:message) instead of your pattern.
If you really need to make the api case-insensitive and you're using Apache on the front-end of your site, consider doing it outside of code: define your API with the urls all lowercase and use Mod-Rewrite to change the urls to lowercase when they hit the web server no matter what the client actually sent. This blog post describes how to do this.
Also, the next pattern is working for me:
#Path("/{externalorders: (?i)externalorders}")

Categories