Sharing the same access path between end users and clients
About this task
The first problem which needs to be addressed is how to distinguish end users from third-party clients and get both parties authenticated as required. Perhaps the simplest option is to extend a CXF OAuth2 filter (JAX-RS or servlet one), check Authorization header, if it is OAuth2 then delegate to the superclass, alternatively - proceed with authenticating the end users:
public class SecurityFilter
extends org.apache.cxf.rs.security.oauth2.filters.OAuthRequestFilter {
@Context
private HttpHeaders headers;
public Response handleRequest(ClassResourceInfo cri, Message message) {
String header = headers.getRequestHeaders().
getFirst("Authorization");
if (header.startsWith("Bearer ")) {
return super.handleRequest(cri, message);
} else {
// authenticate the end user
}
}
}
The next issue is how to enforce that the end users can only access the resources they've been authorized to access. For example, consider the following JAX-RS resource class:
@Path("calendar")
public class CalendarResource {
@GET
@Path("{id}")
public Calendar getPublicCalendar(@PathParam("id") long id) {
// return the calendar for a user identified by 'id'
}
@GET
@Path("{id}/private")
public Calendar getPrivateCalendar(@PathParam("id") long id) {
// return the calendar for a user identified by 'id'
}
@PUT
@Path("{id}")
public void updateCalendar(@PathParam("id") long id, Calendar c) {
// update the calendar for a user identified by 'id'
}
}
Let's assume that the 3rd party client has been allowed to read the public user Calendars at "/calendar/\{id}" only, how to make sure that the client won't try to:
Procedure
- update the calendar available at the same path
- read the private Calendars available at "/calendar/\{id}/private"
Results
As noted above, OAuthPermission has an optional URIs property. Thus one way to solve the problem with the private calendar is to add, say, a uri "/calendar/\{id}" or "/calendar/1" (etc) property to OAuthPermission (representing a scope like "readCalendar") and the OAuth filter will make sure no subresources beyond "/calendar/\{id}" can be accessed. Note, adding a "\*" at the end of a given URI property, for example, "/a*" will let the client access "/a", "/a/b", etc.
Solving the problem with preventing the update can be easily solved by adding an httpVerb property to a given OAuthPermission.
One more option is to rely on the role-based access control and have @RolesAllowed allocated such that only users in roles like "client" or "enduser" can invoke the getCalendar() method and let only those in the "enduser" role access getPrivateCalendar() and updateCalendar(). OAuthPermission can help here too as described in the section on using OAuth fiters.