I'm using JBoss to provide a bunch of RESTful services to a Flex-based RIA. Anyway, I managed through some pain to realize a login (using form-based login) but I'm struggeling with providing a RESTful method to log the user out.
In a JSP I can simply call something like:
session.invalidate()
How can I do this with JBoss, Resteasy that uses stateless session beans to implement the RESTful services?
After a bit of googeling I created a solution:
This is the local interface of my RESTful service bean:
#Local
#Path("/Rest")
public interface SessionController {
...
#GET
#Path("/logout/")
#Produces("text/xml")
String logout(#Context HttpServletRequest req);
}
And this is the implementation:
#RolesAllowed({ "TheBoss", "SomeUser", ... })
#SecurityDomain("mysqlLogin")
#Stateless
public class SessionControllerBean implements SessionController {
...
public String logout(#Context HttpServletRequest req) {
...
req.getSession().invalidate();
return "SUCCESS";
}
}
Pretty simple as you can see. As I might have imagined already dependency injection is the trick. With the #Context annotation I can ask JBoss to inject the HTTPServletRequest from which I can get the session and call invalidate.
The bean is being called via resteasy as a RESTful service.
While developing with Java EE I find that I spend more time tracking down how to configure things in all these xml files (maven configuration is pure hell), which API's to use and how and which bean to inject than actually developing functionality.
Related
I am working on a spring web socket app and I am looking to find a way to get hold of the spring web socket session decorator at my controller.
By looking at the spring code I saw that WebSocketSessions by default are decorated with ConcurrentWebSocketSessionDecorator in SubProtocolWebSocketHandler:decorateSession()
Here is how my code looks like
#Controller
public class MyController {
#MessageMapping("/endpoint")
public void method(Request request) {
//logic
// This is where I want to have access to ConcurrentWebSocketSessionDecorator
}
}
Is it possible to get access to the decorator in my controller ?
Thanks
Nikos
I am trying my hands on a simple jersey application for few simple RESTful APIs. I want to try role based securities over my API endpoints, but not sure how?
Should the annotation be declared over WebService class like below?
#Slf4j
#Path("/account")
#Autherization
#DeclareRoles("ADMIN", "STUDENT", "TEACHER")
public class AccountService extends SpringApplication {
private static Logger logger = Logger.getLogger("AuthenticationService");
#Path("/greet")
#GET
#Produces(MediaType.TEXT_PLAIN)
#PermitAll
public Response greet(){
logger.info("Welcome to Tarkshala Scholar Account APIs");
return getBean(AuthenticationServiceHandler.class).greet();
}
}
or should it be declared on Filters?
So Jersey already handles the authorization for you with its RolesAllowedDynamicFeature. Just register it in your Jersey ResourceConfig. There is no need for #DeclareRoles, as that is an EJB mechanism. Jersey has its own separate system for handling roles.
What happens under the hood is that there is a ContainerRequestFilter (annotated with #Priority(Priorities.AUTHORIZATION)) that checks your resource methods to see what roles are allowed, then it gets the SecurityContext from the ContainerRequestContext and called the SecurityContext#isUserInRole(String role) method for each role declared in the #RolesAllowed (should there be any). If the SecurityContext doesn't pass the check, Jersey throws a ForbiddenException.
So with that said, what you need to do for your authentication is create a ContainerRequestFilter (annotated with #Priority(Priorities.AUTHENTICATION), and in that filter do your authentication, then create a SecurityContext with all the roles for Jersey to check. This method separates the concerns; one filter for authentication (which we created) and one filter for authorization (which Jersey provides for us.
You can see an example of an authentication filter that uses Basic Authentication in this post.
Short and sweet:
I want to be able to filter incoming requests to authenticate the user then take the roles defined in my database and use them in the Jersey 2.5.1 Service classes.
e.g.
#RolesAllowed("Custom1", "Custom2")
#Post
.....
Currently I have the following, which seems to work with the basic #PermitAll and #DenyAll annotations, I am just not sure how to overload/what to overload to get some custom code working with Jersey 2.5.1. I've seen examples for Jersey1. Should I just create a request Filter and do it in there and set the securityContext? Any help would be appreciated.
public class TestApi extends ResourceConfig {
public TestApi() {
super(AuthenticateResource.class);
register(RolesAllowedDynamicFeature.class);
}
}
Figured out my problem. Injected Resource Info then pulled out the annotation. This works if it's not pre-matching
#Context
private ResourceInfo resourceInfo;
Annotation[] annotations = resourceInfo.getResourceMethod().getDeclaredAnnotations();
SecurityContext is either set by the underlying container or it's set manually in your application (usually in ContainerRequestFilter). If your container is sophisticated enough to set the correct security context for you (with correct principal) you can go this way. Otherwise create a custom ContainerRequestFilter similar to the one in Jersey example ContainerAuthFilter.
I have a Jersey REST API and am using a ContainerRequestFilter to handle authorization. I'm also using #ManagedAsync on all endpoints so that my API can serve thousands of concurrent requests.
My authorization filter hits a remote service, but when the filter is run, Jersey hasn't yet added the current thread to it's internal ExecutorService, so I'm completely losing the async benefits.
Can I tell Jersey that I want this ContainerRequestFilter to be asynchronous?
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter
{
#Inject
private AuthorizationService authSvc;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
String authToken = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// HITS A REMOTE SERVER
AuthorizationResponse authResponse = authSvc.authorize(authToken);
if (!authResponse.isAuthorized())
{
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
.entity("unauthorized!")
.build());
}
}
}
And here's an example resource:
#Path("/stuff")
#Produces(MediaType.APPLICATION_JSON)
public class StuffResource
{
#GET
#Path("/{id}")
#ManagedAsync
public void getById(#PathParam("id") long id, #Suspended final AsyncResponse ar)
{
Stuff s;
// HIT THE DATABASE FOR STUFF
ar.resume(s);
}
}
UPDATE Just heard back from the Jersey guys, and this is not possible as of 2.7. Only the resource method itself is invoked asynchronously, not filters. Any suggestions for proceeding still welcome.
This is not built in to Jersey as of 2.7.
#ManagedAsync is useless if you have any filters or interceptors that do any serious work (like hit a remote authorization service). They may add the ability to run filters asynchronously in the future, but for now you're on your own.
UPDATE - there are other ways...
After a long and perilous journey, I have found a very hacky solution that I'm using in the short term. Here is a rundown of what I tried and why it failed/worked.
Guice AOP - failed
I use Guice for DI (getting Guice injection to work with Jersey is a feat in itself!), so I figured I could use Guice AOP to get around the issue. Though Guice injection works, it is impossible to get Guice to create resource classes with Jersey 2, so Guice AOP cannot work with resource class methods. If you are trying desperately to get Guice to create resource classes with Jersey 2, don't waste your time because it will not work. This is a well-known problem.
HK2 AOP - RECOMMENDED SOLUTION
HK2 just recently released an AOP feature, see this question for details on how to get it working.
Monitoring - also worked
This is not for the faint of heart, and it is completely discouraged in the Jersey docs. You can register and ApplicationEventListener and override onRequest to return a RequestEventListener that listens for RESOURCE_METHOD_START and calls an authentication/authorization service. This event is triggered from the #ManagedAsync thread, which is the whole goal here. One caveat, the abortWith method is a no-op, so this won't work quite like a normal ContainerRequestFilter. Instead, you can throw an exception if auth fails instead, and register an ExceptionMapper to handle your exception. If someone is bold enough to give this a try, let me know and I'll post code.
I am not sure if this is what you were looking for but, have you looked into Spring's OncePerRequestFilter? I am currently using it for my authorization layer where each request goes through some filter that extends this OncePerRequestFilter depending on how my filters are mapped to the URLs. Here's a quick overview of how I am using it:
Authentication/Authorization of a resource in Dropwizard
I am not very clear on the async dispatch parts of these filters but I hope this link atleast sheds some light to what you are trying to achieve!
We use Spring security for authentication/authorization. I worked around the problem using a sub-resource locator with empty path as shown below:
#Path("/customers")
public class CustomerResource {
#Inject
private CustomerService customerService;
#Path("")
public CustomerSubResource delegate() {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return new CustomerSubResource(auth);
}
public class CustomerSubResource {
private final Authentication auth;
public CustomerSubResource(final Authentication auth) {
this.auth = auth;
}
#POST
#Path("")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ManagedAsync
public void createCustomer(final Customer customer, #Suspended final AsyncResponse response) {
// Stash the Spring security context into the Jersey-managed thread
SecurityContextHolder.getContext().setAuthentication(this.auth);
// Invoke service method requiring pre-authorization
final Customer newCustomer = customerService.createCustomer(customer);
// Resume the response
response.resume(newCustomer);
}
}
}
Environment: JBoss AS 7, RestEasy 3.0.5.
I would like to use a preprocess filter in my application to authenticate a particular user and add this authenticated user to the request scope. I tried the following:
#Provider
public class SecurityFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) {
// authenticate, lookup user code etc...
requestContext.setProperty("User", new User("test"));
}
}
And then access it at the bean level using:
#Stateless
public class TestBean {
#Context HttpServletRequest servletRequest;
#GET
#Path("/hello")
public String hello() {
return "Hello " + servletRequest.getAttribute("User");
}
}
However the Context elements are not injected when the bean is annotated as stateless (stateless is required for EJB logic) due to a 2 year old RestEasy bug.
Can anyone think of a solution to this issue?
Alternatively, is there a more typical solution that prepopulating these objects using a filter?
Kind thanks for reading.
What I have done before is that I have a web application, "facade" if you want, to the EJBs. The JAX-RS layer is implemented in this application. A servlet filter intercepts the request to the JAX-RS resources and calls a CDI service that implements the "authenticate, lookup user code etc" logic. On success, the CDI service exports the current user object to CDI. This user object is #Inject'ed in the EJBs.
If CDI is an option for you (and I don't see why not in this setup), you could do the same (i.e. export the User to CDI) from your SecurityFilter, without having to create a web-app.
Additionally the dependency of the service layer (EJBs) to web-specific APIs (HttpServletRequest) is a bit creepy; I really think dependency injection of the actual User object is the way to go.