A HTML5 UI is connected to the backend (REST Jersey to business logic to Hibernate and DB).
I need to create and maintain a session for each user login until the user logs out.
Can you please guide me on what technologies/ APIs can be used.
Does something need to be handled at the REST Client end also..
Using JAX-RS for RESTful web services is fairly straightforward. Here are the basics. You usually define one or more service classes/interfaces that define your REST operations via JAX-RS annotations, like this one:
#Path("/user")
public class UserService {
// ...
}
You can have your objects automagically injected in your methods via these annotations:
// Note: you could even inject this as a method parameter
#Context private HttpServletRequest request;
#POST
#Path("/authenticate")
public String authenticate(#FormParam("username") String username,
#FormParam("password") String password) {
// Implementation of your authentication logic
if (authenticate(username, password)) {
request.getSession(true);
// Set the session attributes as you wish
}
}
HTTP Sessions are accessible from the HTTP Request object via getSession() and getSession(boolean) as usual. Other useful annotations are #RequestParam, #CookieParam or even #MatrixParam among many others.
For further info you may want to read the RESTEasy User Guide or the Jersey User Guide since both are excellent resources.
Related
I have an EJB application that consists of two beans, ServiceEJB (web tier) and BusinessEJB (business tier), where BusinessEJBis injected in ServiceEJB.
ServiceEJBreceives HTTP requests from the browser, calls a method in BusinessEJB, gets the result, and sends the HTTP response.
Also, ServiceEJB has access to the HttpSession object, where the userId of the user that logged in is stored. BusinessEJBdoes NOT have access to the HttpSession object.
The application needs to log messages (using sl4j/logback, for example). It could log the message in ServiceEJBor BusinessEJB methods, and when it logs a message, it has to include the userId of the session in the log entry.
Since BusinessEJB doesn't have the userId, it needs to get it from ServiceEJB. The question is what is the best way to achieve that. What I DON'T want to do is to add a userId field to each method in BusinessEJB as a parameter, as there are many ServiceEJBs and BusinessEJBs in the application (and other beans called by BusinessEJB that also generate log entries), and I don't want to pollute the application with the userId field. Instead, I could have a userId field at the EJB level, but how to populate them? Is there a way to achieve this with annotations? Any suggestions will be welcome.
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
#Stateless
public class ServiceEJB {
#Context
HttpServletRequest httpRequest;
#Inject
private BusinessEJB bean;
private String userId;
#Path("someurl")
public Response someMethod1() {
final HttpSession session = httpRequest.getSession();
// get the userId from the session
String s = bean.someMethod2();
// return Response
}
}
#Stateless
public class BusinessEJB {
private String userId;
public String someMethod2() {
// .... log an entry with userId
return "something";
}
}
A few pointers/comments:
If you integrate with application server security, then the user name is available at any component. EJBs can get it by calling getCallerPrincipal() on the injected variant of the EJBContext, here the javax.ejb.SessionContext:
#Resource
private SessionContext sessionCtx;
Servlets can retrieve the principal from the HttpServletRequest.getUserPrincipal(). JAX-RS components (the ServiceEJB) can retrieve it from the javax.ws.rs.core.SecurityContext.getUserPrincipal().
Is there any reason why you are NOT integrating with the application server security?
If you have a good reason NOT to integrate with application server security, I would propose a variation of the solution from the previous answer. The variation is to set the user data from a filter applied to all resources (either servlet filter or JAX-RS ContainerRequestFilter), so that you do not have to worry about setting it in multiple places.
If you ONLY NEED THE USER ID FOR LOGGING, I'd suggest you take a look at the concept of Mapped Diagnostic Contexts (MDC) in slf4j. With it you can set the user id early at the beginning of the request and make it available to all logging statements thereafter.
Create a request scoped CDI bean i.e. UserContext.
Inject it into both EJBs.
In ServiceEJB set user's id and in BusinessEJB read it.
in my spring application I have some aspects for controller methods where I do some security checks. beacause of I need several checks more often I wrapped them into static helper methods of a "sercurityUtil" class.:
public abstract class SecurityUtils {
public static Authentication getCurrentAuthentication(){
return SecurityContextHolder.getContext().getAuthentication();
}
public static ChroniosUser getAuthenticatedUser(){
return (ChroniosUser) getCurrentAuthentication().getPrincipal();
}
public static boolean authenticationHasRole(Authentication authentication, Role role){
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleIdentifier());
return authentication.getAuthorities().contains(grantedAuthority);
}
public static boolean authenticatedUserIsAdmin(){
Authentication authentication = getCurrentAuthentication();
return authenticationHasRole(authentication, ADMIN);
}
...
}
is this a valid and good approach?
or shut I wrap these helper functions into a spring service?
thank you.
PS: I know that I can use #PreAuthorize ... but my aspects are more complex.
The short answer is :
Yes it seems to be a valid and good approach.
The long answer is :
It's up to you.
Spring Security documentation states that its infrastructure is based entirely on standard servlet filters and has no strong links to any particuler web technology, including Spring MVC
Spring Security’s web infrastructure is based entirely on standard
servlet filters. It doesn’t use servlets or any other servlet-based
frameworks (such as Spring MVC) internally, so it has no strong links
to any particular web technology. It deals in HttpServletRequest s and
HttpServletResponse s and doesn’t care whether the requests come from
a browser, a web service client, an HttpInvoker or an AJAX application
[Spring Security Reference - 1. The Security Filter Chain]
Its use is based nearly entirely on the SecurityContextHolder. The examples provided are through static methods :
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
As you can see, it's not a Spring Bean/Service/Component. SecurityContextHolder itself looks like a utility class.
Now you can create a Spring Service to expose it or you can use it through a classic Util class depending on what is more practical to you and for your application.
I am using spring & jersey2 to serve some rest-requests like:
#GET
#Path("/someservice")
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public String getSomeStuff(...) {
login(...);
// ...
}
During a rest-request, I get an authorized user of the rest-request.
Now I need this user while updating or creating entities like:
#MappedSuperclass
public abstract class PersistentObject {
#PrePersist
#PreUpdate
public void onSaveOrUpdate() {
setCreationUser(...); // How to get the user of this session?
}
// ...
}
How can I get the current user of the rest-request there?
You can try to perform your login operation (for appropriate resource methods) in a ContainerRequestFilter and set SecurityContext:
#Provider
public class SecurityFilter implements ContainerRequestFilter {
#Override
public void filter(final ContainerRequestContext context) throws IOException {
final Principal user = login(...);
context.setSecurityContext(new SecurityContext() {
public Principal getUserPrincipal() {
return user;
}
// Other methods omitted.
});
}
}
Make sure you have jersey-spring3 module on your class-path and the Jersey-Spring integration allows you to inject SecurityContext into a Spring service:
#Service
public MySpringService implements MyService {
#Context
private SecurityContext context;
public String doStuff() {
final Principal user = context.getUserPrincipal();
// ...
}
}
You can't do this if the service, you want to use user principal in, is neither managed by Jersey nor Spring.
Spring Security might be useful to you in two ways:
It can manage authentication, (you would not need to do that login(...) call yourself, it would be done automatically by Spring Security filter chain. But you can still do it manually if you want.
Once a request has been authenticated, as long as the request is alive you can access the authenticated user from anywhere just by doing:
Authentication auth = SecurityContextHolder.getSecurityContext().getAuthentication();
// auth is an object that holds the authenticated user's data
I think you need some sort of authentication by the fact that you make a login(...) and you want to audit the user afterwards. You might not nedd an authentication form, but you do need authentication. Spring Security is not only for interactive applications, you can set up an authentication filter that does authentication based on cookies, request parameters, client certificates or whatever, all of that without user interaction.
Furthermore, Spring Security is very extensible, if you have your authentication method already implemented, integrating with Spring Security is easy. And it is also flexible: you don't need to use the security filter chain if it is too heavyweight for your use case. You can do most things manually and use just a little bit of Spring Security if you want.
I really suggest you take a deeper look at Spring docs about:
Spring Security core components overview and Spring Security authentication overview
I think with just that you will be able to get something working.
In PHP when a user logs into her account, I do the following in order to remember the user as she navigates through the site:
session_start();
...
$_SESSION['username'] = $username;
On any other page that may require sensitive data, I check that $_SESSION['username'] is valid.
When a use logs out, I do the following
unset($_SESSION['username']
session_destroy();
How do I do the same thing in Java? I have a REST API which uses Jersey and EJB. In case the following is important, I am persisting with JPA, Hibernate, Glassfish, and mysql.
UPDATED FOR VERIFICATON:
Is this correct?
#Path("login")
public class UserLoginResource {
#EJB
private LoginDao loginDao;
#Context
HttpServletRequest request;
#POST
public Response login(JAXBElement<Login> jaxbLogin){
Login login = jaxbLogin.getValue();
loginDao.authenticateUserLogin(login);
HttpSession session = request.getSession();
session.setAttribute("username", login.getUsername());
return Response.ok().build();
}
}
Java is very different from php, so in java You will get session from only HttpRequest 's getSession() method, In php it is all time assumed, your code is run by some server(ie apache), In java, you will obtain it from ServletContainer(ie Apache Tomcat).
You do not have to start session in java unlike php, As long as you are in servlet container and giving request, for this client servlet container is responsible to start if there is not session for it
So for above actions:
reqest.getSession().setAttribute("udername","Elbek");
//later
reqest.getSession().removeAttribute("udername");
//destroy it
reqest.getSession().invalidate();
Here request is object of HttpRequest class
You may have a look to this HttpSession
I strongly recommend you to have a look java scopes
There is not this kind of thing in php, I wish there is, BUT there is NO
Here is how you get request object into your jersey action(method), ie by injecting #Context HttpServletRequest httpRequest
EDIT:
You do not create HttpRequest object by yourself, Instead you will get it from servlet container, Your server creates it from clients request and gives for your.
+elbek describes plain servlet situation - however, nowadays almost nobody writes plain servlet. It sickes soo much back then, that a lot of web frameworks evolved. There is a sh*tload of them, but good ones will utilize dependency injection techniques like spring
( for example , struts 2 ) and there are distinct scopes - application / session / request - containing plain java beans, which can in turn have authentication data.
J2EE also provides own authentication semantics with servlet container and JAAS - it also uses session tracking and useful when you need to access some backend resources like datasources or queues or EJBs - but most web application do not bother wth it.
I'm fairly new to writing web services. I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
One way I've seen to do this is to use cookies and access the HTTP layer from my web service. However, this puts a dependency on using HTTP as the transport layer (I'm aware HTTP is almost always the transport layer but I'm a purist).
Is there a better approach which keeps the service layer unaware of the transport layer? Is there some way I can accomplish this with servlet filters? I'd like the answer to be as framework agnostic as possible.
I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
Conventional Web services are stateless in nature, there is no session handling in web services (which has by the say nothing to do with identifying the caller).
If you want to require your users to be authenticated to call a service, the traditional approach is to:
Expose an "authentication" web service (passing user credentials) that returns an authentication token.
Have the users call this authentication first.
Have the users pass the token in a custom header on subsequent calls of "business" web services.
On the server side:
Reject any call that doesn't contain a valid token.
Invalidate tokens after some time of inactivity
You can implement a custom solution for this approach (this is a highly interoperable solution). Or you can use WS-Security/UsernameTokens that provides something similar out of the box. WS-Security is a standard (Metro implements it), it isn't "framework" specific.
As you mention, servlet filters can provide the basis of solution. Use a filter to store the current session details (e.g. the session context Map) in a threadLocal storage. This is implemented as your application class, so is transport agnostic. Your service simply uses a static method to fetch the current context, unaware of where it came from.
E.g.
class ServiceSessionContext
{
static ThreadLocal<Map> local = new ThreadLocal<Map>();
// context set by the transport layer, e.g. servlet filter
static public void setContext(Map map)
{
local.put(map);
}
// called when request is complete
static public void clearContext()
{
local.put(null);
}
// context fetched by the service
static public Map getContext()
{
return local.get();
}
}