Authorization based on URL parameters in JAX-RS / Java EE? - rest

We are working on a web application based on JAX-RS. We have multiple parameterized endpoints that access resources by resource ID and query some aspect of them. We restrict access to individual resources only to those users who do have the rights to that particular resource. At the moment we are doing this by programmatically / manually checking for said access at the start of the method. What are the best practices, or even just the possibilities, to do this in a declarative / automated way?
The current endpoints look something like this:
#GET
#Path("/resource/{resourceId}/getWhatever")
#Produces(MediaType.APPLICATION_JSON)
public String getWhatever(#PathParam("resourceId") String resourceId) throws Exception {
checkForResourceAccess(resourceId, userName and security and whatever);
String result = query whatever from resource;
return result;
}
#GET
#Path("/resource/{resourceId}/getAnotherThing")
#Produces(MediaType.APPLICATION_JSON)
public String getAnotherThing(#PathParam("resourceId") String resourceId) throws Exception {
checkForResourceAccess(resourceId, userName and security and whatever);
String result = query another thing from resource;
return result;
}
[...]
So far I was thinking about these solutions:
A custom JAAS LoginModule. No experience in this, not even sure if it possible.
An interceptor specifically to check access to resources. However this is not reusable, it is strongly coupled to resourceId. Feels like a hack really.
JAX-RS filters and interceptors to filter requests.
Separate #Path("resource/{resourceId}") service class for these endpoints. #PathParam("resourceId") field, and some kind of automated check for example in a #PostConstruct method.
Custom <auth-constraint> if possible at all.
The situation is somewhat complicated by the fact that we use SAML 2.0 for Single Sign On authentication.
So, what would be the best practices, or even possibilities, to fulfill this authorization issue, while also conforming to Java EE specifications as much as possible?

Related

How correctly implement a RESTful WS architecture using Spring MVC\Boot?

I am not so into RESTful web service and I have the following doubt about how to correctly implement RESTful style in my servics working on a Spring Boot application (Spring MVC is the same thing).
So basically I have some controller class like this:
#RestController
#RequestMapping("/RoomMedia")
public class RoomMediaController {
private static final Logger log = LoggerFactory.getLogger(RoomMediaController.class);
#Autowired
private RoomMediaService roomMediaService;
public RoomMediaController() {
log.debug("RoomMediaController init");
}
#RequestMapping(value = "getAllImagesByRoomId",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<byte[]>> getAllImagesByRoomId(Long roomId) throws DataAccessException {
log.debug("getAllImagesByRoomId START");
List<byte[]> result = roomMediaService.getRoomImageListById(roomId);
log.debug(result.toString());
log.debug("getAllImagesByRoomId END");
return ResponseEntity.ok(result);
}
}
I think that, also if the base idea is RESTful like, it can't be considered a true RESTful WS.
I think that the main problem is related to the endpoint: the getAllImagesByRoomId() method handle HTTP GET request toward URL like this: /RoomMedia/getAllImagesByRoomId?roomId=7
From what I have understand reading some tutorial this is not RESTful style because I have to access to a resource without passing parameter, I have to do someting like this:
/RoomMedia/Images/7
Is it my reasoning correct?
Moreover I think that the previous method is pretty trivial also in the implementation: this method return the list of all the images associated to a room having id=7(it is an application related to hotels).
From what I have understand also its logic is againts RESTful principles.
Is it better organize in the following way?
Doing a GET request like this:
/RoomMedia/7/Images/: I have to obtain the list of all the images associated to the room having id=7 as URI (or maybe is better handle a path like /7/RoomMedia/Images/ ?).
/RoomMedia/7/Images/1 I obtain the image with the id=1 associated to the room having id=7.
Are al these reasoning correct or am I missing something?
your assumtions are correct. Which of the mapping that you suggest, is deppending totaly on how your model is. Martin Fowler has a nice article about the Richardson Maturity Model which is sum up as:
Level 1 tackles the question of handling complexity by using divide and conquer, breaking a large service endpoint down into multiple resources.
Level 2 introduces a standard set of verbs so that we handle similar situations in the same way, removing unnecessary variation.
Level 3 introduces discoverability, providing a way of making a protocol more self-documenting.
For your project you could use jhipster because its offer you the best of spring with angular under a REST-ful design.
URLs must not contain a verb. The verb is provided by the method, in your case - surprise, surprise - GET.
ByRoomId is pointless as well, because that's what ?roomId= says.
That leaves AllImages, where All is superfluous.
Which results in the URL /RoomMedia/Images?roomId=7. What's unclear is the relationship between RoomMedia and Images, if there is any. If RoomMedia refers to a room, then your suggestion /RoomMedia/7/Images/ would be correct.
/RoomMedia/7/Images/1 is questionable. It should rather be /Images/1. It's irrelevant in which room the image with the id 1 is in.
When you design a REST API, then the first thing to do is to think about all resources you want to expose and their relationships. After that the URLs will reveal themselves automatically, so to speak.

Jersey 2: filters and #Context injections

I've the following question:
ContainerRequestFilter is a singleton, but reading this:
Jaxrs-2_0 Oracle Spec
in chapter 9.2, they say:
Context is specific to a particular request but instances of certain JAX-RS components (providers and resource classes with a lifecycle other than per-request) may need to support multiple concurrent requests. When injecting an instance of one of the types listed in Section 9.2, the instance supplied MUST be capable of selecting the correct context for a particular request. Use of a thread-local proxy is a common way to achieve this.
In the chapter 9.2, the HttpServletRequest is not mentioned.
So the question is: is it safe in terms of concurrency to inject the HttpServletRequest inside a custom ContainRequestFilter?
I mean this:
#Provider
#PreMatching
public class AuthenticationFilter implements ContainerRequestFilter {
#Context private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// This is safe because every thread call the method with its requestContext
String path = requestContext.getUriInfo().getPath(true);
// Is this safe? The property request is injected by using #Context annotation (see above)
String toReturn = (String)request.getAttribute(name);
[...]
}
I did some empirical tests on my IDE in debug mode, sending with two different browsers two different and concurrent requests and it seems to work well; I noticed that the filter's instance is ever the same (it's a singleton), but the injected HttpServletRequest is different in the two cases.
I readed even this thread: How to access wicket session from Jersey-2 request filter? and it seems that my tests are confirmed.
But I still have doubts.
Confirm?
Yes it's safe. To understand the problem, you should understand how scopes work. In any framework that deals with scopes (and injection), the feature is implemented similarly. If an object is in a singleton scope and another object in a lesser scope needs to be injected, usually a proxy of the object will be injected instead. When a call is made on the object, it's actually a call on the proxy.
Though the spec may not mention the HttpServletRequest specifically, most JAX-RS implementation have support for this. With Jersey in particular, if this was not possible (meaning the object is not proxiable), then you would get an error message on startup with something like "not within a request scope". The reason is that the ContainerRequestFilter is created on app startup, and all the injections are handled at that time also. If the HttpServletRequest was not proxiable, it would fail to inject because on startup, there is no request scope context.
To confirm that it is not the actual HttpServletRequest and is a proxy, you can log the request.getClass(), and you will see that it is indeed a proxy.
If you are unfamiliar with this pattern, you can see this answer for an idea of how it works.
See Also:
Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey

No event context active - RESTeasy, Seam

I'm trying to add a RESTful web service with RESTeasy to our application running on JBoss 7.x, using Seam2.
I wanted to use as little Seam as possible, but I need it for Dependancy Injection.
My REST endpoints are as follows:
#Name("myEndpoint")
#Stateless
#Path("/path")
#Produces(MediaType.APPLICATION_JSON+"; charset=UTF-8")
public class MyEndpoint {
#In private FooService fooService;
#GET
#Path("/foo/{bar}")
public Response foobar(#CookieParam("sessionId") String sessionId,
#PathParam("bar") String bar)
{ ... }
}
I'm using a class extending Application. There is no XML config.
I can use the web service methods and they work, but I always get an IllegalStateException:
Exception processing transaction Synchronization after completion: java.lang.IllegalStateException: No event context active
Complete StackTrace
I did try everything in the documentation, but I can't get it away. If I leave out the #Stateless annotation, I don't get any Injection done. Adding #Scope doesn't do jack. Accessing the service via seam/resource/ doesn't even work (even without the Application class with #ApplicationPath).
It goes away if I don't use Dep. Injection, but instead add to each and every method
fooService = Component.getInstance("fooService");
Lifecycle.beginCall();
...
Lifecycle.endCall();
which isn't really a good solution. Nah, doesn't work either...
I have resolved the issue. For some reason (still not sure why, maybe because I tried to use Annotations and code exclusivly and no XML config), my REST service was availiable under a "non-standard" URL.
Usually it'd be something like "/seam/resources/rest".
Anyway, if you have a "custom" path, Seam doesn't know it should inject a context. You need to add <web:context-filter url-pattern="something" /> to your component.xml.
Specifically we already had this tag, but with the attribute regex-url-pattern and I extended it to match the REST URL.

How to Route non-CRUD actions in a RESTful ASP.NET Web API?

I am trying to design a RESTful web API for our service using ASP.NET Web API. I'm running into trouble with figuring out how to route non-CRUD actions to the proper controller action. Let's assume my resource is a door. I can do all of the familiar CRUD things with my door. Let's say that model for my door is:
public class Door
{
public long Id { get; set; }
public string InsideRoomName { get; set; }
public string OutsideRoomName { get; set; }
}
I can do all of my standard CRUD operations via my web api:
POST: http://api.contoso.com/v1/doors
GET: http://api.contoso.com/v1/doors
GET: http://api.contoso.com/v1/doors/1234
GET: http://api.contoso.com/v1/doors?InsideRoomName=Cafeteria
PUT: http://api.contoso.com/v1/doors/1234
DELETE: http://api.contoso.com/v1/doors/1234
and so on. Where I run into trouble is when I need to model the non-CRUD actions against my door. I want to model a Lock and Unlock verb against my resource. Reading through the ASP.NET articles the guidance seems to be to switch to an RPC style call when using custom actions. This gives me a path:
PUT: http://api.contoso.com/v1/doors/1234/lock
PUT: http://api.contoso.com/v1/doors/1234/unlock
This seems to conflict with the spirit of REST which aims for the path to indicate a resource. I suppose I could model the verb as a resource:
POST: http://api.contoso.com/v1/doors/1234/lockrequests
POST: http://api.contoso.com/v1/doors/1234/unlockrequests
In this case I could still use the recommend {controller}/{id}/{action} but it seems like I'm still creating a mixed RPC / REST API. Is it possible, or even recommended as far as REST interfaces go, to put the custom action in the list of parameters?
PUT: http://api.contoso.com/v1/doors/1234?lock
PUT: http://api.contoso.com/v1/doors/1234?unlock
I could foresee a need to have this call supported with query parameters as well, such as:
PUT: http://api.contoso.com/v1/doors?lock&InsideRoomName=Cafeteria
How would I create the route to map this request to my DoorsController?
public class DoorsController : ApiController
{
public IEnumerable<Doord> Get();
public Door Get(long id);
public void Put(long id, Door door);
public void Post(Door door);
public void Delete(long id);
public void Lock(long id);
public void Unlock(long id);
public void Lock(string InsideRoomName);
}
I may be making some false assumptions here regarding what is and is not best practices with respect to REST API design, so any guidance there is appreciated as well.
From RESTful principle, maybe it's best to introduce a 'status' property to manage those non-CURD actions. But I don't think it meets the real production development.
Every answer to this kind of question, looks like you must have to use a work-around to enforce your API design meets RESTful. But my concern is, is that really making convenience to both user and developer?
let's take a look on the API3.0 design of Google bloger: https://developers.google.com/blogger/docs/3.0/reference, it's using lot URL for non-CURD actions.
And this is interesting,
POST /blogs/blogId/posts/postId/comments/commentId/spam
and the description is
Marks a comment as spam. This will set the status of the comment to spam, and hide it in the default comment rendering.
You can see, a comment has a status to indicate whether it's a spam or not, but it was not designed like the answer mentioned above by JoannaTurban.
I think from user point of view, it's more convenient. Don't need to care the structure and the enum value of the "status". And actually you can put lot of attributes into the definition of "status", like "isItSpam", "isItReplied", "isItPublic" etc. The design will becomes unfriendly if the status has many things.
On some business logic requirement, to use an easy to understand verb, instead of trying to make it completely a "real" RESTful, it's more productive, for both user and developer. This is my opinion.
To handle the lock/unlock scenario you could consider adding a State property to the Door object:
public State State { get; set; }
where State is an enum of available values, e.g.
{
LockedFromOutsideRoom,
LockedFromInsideRoom,
Open
}
To clarify: That you're adding a state to the object is not against restful principles as the state is passed over the api every time you make a call to do something with the Door.
Then via the api you would send a PUT/POST request to change the state of the Door on each lock/unlock. Post would probably be better as it's only one property that gets updated:
POST: http://api.contoso.com/v1/doors/1234/state
body: {"State":"LockedFromInsideRoom"}
From a REST perspective you probably want to be treating the lock as a resource in and of itself. This way you create and delete the lock independently of the door (although presumably locate the lock endpoint from the door representation). The URL of the resource is probably going to be related to the URL of the door, however from a RESTful perspective this is irrelevant. REST is about relationships between resources, so the important part is that the url of the lock is discoverable from the representation of the door.

Combining URL and POST variables in ServiceStack

I am trying to convert an existing wcf rest api to ServiceStack, and having issues right out of the gate:
[Route("foo/{userId}","POST")]
public class MyInputModel : IReturnVoid
{
public string userId { get; set; }
public SomeOtherObject properties { get; set; }
}
The intention here is that I would provide the userId in the url, and an instance of SomeOtherObject in the post body. The error I get is
<Message>Could not deserialize 'application/xml' request using MyInputModel'
Error: System.Runtime.Serialization.SerializationException:
Error in line 1 position 42. Expecting element 'MyInputModel'
from namespace 'blahblahblah'.. Encountered 'Element' with name
'SomeOtherObject', namespace 'http://blahblahblah'.
The only things I can think of are to wrap my xml in a MyInputModel to make the serializer happy. This is not really an option for backwards compatibility.
I could also modify SomeOtherObject to be the top level input model, and put a UserId property in there, but this also feels suboptimal since it is an object used throughout the api, and is really not tied to a user id. It is also already published independently, so it would be painful to make changes there.
Is there any way to indicate that the root element of the posted data will be a SomeOtherObject insted of a MyInputModel? In WebApi this would be with the [FromBody] attributes and whatnot. Does servicestack have anything similar?
The purpose of a DTO is to auto-generate the wire format which is why ServiceStack requires the Request DTO to match the shape of the incoming request. Part of what makes ServiceStack so productive is that it's a code-first web service framework which encourages starting from C# and projecting out, i.e. your clients should bind to your web service outputs and not the other way round of mapping code-first models to existing schema inputs.
Having said that, the Serialization / Deserialization wiki page lists the different ways to override ServiceStack's default request binding with your own.
Access HTTP Request variables in any Service or Filter
Not everything needs to be mapped to a DTO as any HTTP Variable can still be accessed from the IHttpRequest available from any service or filter, i.e:
base.Request.QueryString
base.Request.FormData
base.Request.Headers[name]
base.Request.PathInfo
base.Request.AbsoluteUri