In my action i'd like to render different views (or maybe only display some other divs) depending on whether a user is authenticated or not.
Should i do something like this:
public static Result index() {
if (Context.current().request().username().equals("")) {
// user is NOT authenticated
return ok(welcome.render());
} else {
// user is authenticated
return ok(dashboard.render());
}
}
And how about checking if a user is authenticated in a view?
I know I can use the #Security.Authenticated(Secured.class) annotation, but how do things conditional?
Depends on what you're trying to achieve. If you only need to decide whether a user is logged in or not, you can use something like you wrote, in your controller classes, eg:
public static boolean loggedIn() {
return (session().get("userId") != null);
}
then in the static controller methods check whether the user is logged in:
if (!loggedIn()) {
return redirect(routes.Application.login());
}
Notice the use of the session() by which you can access the secure session cookie's map, and from there you can get the user id. If you want to implement more complex logic, eg. different actions for different user groups, then it's a different story.
Either use some maps in a cache with the authenticated user id-s and you validate the userId in the session, whether it's in the map, or alternatively you can use some property of the user (eg. a set of userRoles) and set what is visible accordingly. These are the most sensible ways I'm aware of.
(here's how you can use the session() of controller:
Controller,Session)
Related
I'm new to #Filter and I have understood that it takes in parameters when compared to #Where.
I have a use case where I need to filter the results for every end point based on the logged in User.
While searching for how to enable filtering globally, I came across a solution where AOP is used to intercept Session creation and to enable the filter which seems to be working fine.
The problem here is that I need to have the User ID sent in as the parameter while enabling the filter. How do I do it or is there any other alternative for this particular scenario?
#Aspect
#Component
public class EnableFilterAspect {
#AfterReturning(pointcut = "bean(entityManagerFactory) && execution(* createEntityManager(..))",
returning = "retVal")
public void getSessionAfter(JoinPoint joinPoint, Object retVal) {
if (retVal != null && EntityManager.class.isInstance(retVal)) {
Session session = ((EntityManager) retVal).unwrap(Session.class);
session.enableFilter("authorize").setParameter("userId", **USER_ID**);
}
}
}
You will have to store the user id in a thread local variable and use that in the aspect. Not sure what the filter does, but maybe multi-tenancy is more in line with what you want to achieve. The solution doesn't change much though, you will have to somehow publish the user id through a thread local variable.
I'm trying to write my own ServerAuthModule, to use a custom login system.
If I understood everything right, what happens is that the container calls the validateRequest method for every incoming request, and that my SAM will check for credentials, and tell the container the username and groups of the user (if the credentials are right) via the CallbackHandler.
public class MySAM implements ServerAuthModule {
#Override
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException {
// check user credentials
...
// set username and groups
CallerPrincipalCallback cpCallback = new CallerPrincipalCallback(clientSubject, username);
GroupPrincipalCallback gpCallback = new GroupPrincipalCallback(clientSubject, groups);
callbackHandler.handle(new Callback[]{cpCallback, gpCallback}
return AuthStatus.SUCCESS;
}
...
}
My problem now is, that when a user logs in, I don't know to which groups the user belongs. I can only check whether the user is in a given group. Is it somehow possible to give the container a method with which it can check whether a user is in a given group, instead of giving it an array with groups in the validateRequest method?
boolean isInGroup(String username, String group) {
// ask backend system
}
What you're doing looks right indeed.
There's no concept in JASPIC of handing the container a method like you intend. The container creates a set of Principals from the groups array you give it, and there's no room for a method there.
In Java EE, JACC should be able to do this. A JACC policy provider is consulted everytime the isUserInRole question needs to be answered and everytime it needs to be decided whether a user has some permission (eg allowed to access /adminpanel).
At that point you can do a kind of reverse check to see what role is required for a given Permission (using the role to Permission Maps that JACC builds up at startup time). With that role you can then use your own logic to determine if the user indeed has that role or group.
This is a follow up from Java Play! 2 - User management with cookies
from the zentask example
public class Secured extends Security.Authenticator {
#Override
public String getUsername(Context ctx) {
return ctx.session().get("email");
}
#Override
public Result onUnauthorized(Context ctx) {
return redirect(routes.Application.login());
}
// Access rights
public static boolean isMemberOf(Long project) {
return Project.isMember(
project,
Context.current().request().username()
);
}
public static boolean isOwnerOf(Long task) {
return Task.isOwner(
task,
Context.current().request().username()
);
}
}
For me this doesn't really makes sense.
User gets the following cookie. for example "email=test#test.com"
If I go to a "secured" page , zentask only checks if email is not null. How can this be secure?
The reason of sessions are to get load off the db. But with this approach he has to constantly check if the user has the rights to on a secured page.
For me it doesn't really makes sense. Why is there a function getUsername? And why is the return type a string?
I want to do somthing like this:
User logs in and gets a cookie which looks somthing like this "value=randomString"
Safe the user OBJECT in the cache for example Cache.set(randomstring,userObject);
Now if the visitor comes back I check if his randomstring is in my cache, if yes check if the User object in the cash has the rights to be on the secured page.
I was able to achieve this, just without the #Security.Authenticated() annotation.
Is it possible to achieve this with this annotation?
It is just a sample, nothing else. You don't need to store a email in the cookie. You can for an example save some hash to identify logged user, or do some other matching.
Samples are as simple as possible, changing it to more sophisticated scenarios lays on the developers side.
BTW of course all Play's cookies are signed and I really doubt if you'll be able to manually change it.
In Spring 3, is there a method that accepts a comma-separated list of permissions and returns a Boolean of whether the logged in user has any of those permissions? I envision doing something like:
if(loggedInUserHasAnyOfThesePermissions("PERMISSION_READ,PERMISSION_EDIT")){
//do stuff
}
Currently, since don't know of any such built-in method, I'm doing this:
Set<String> permissions = new HashSet();
for (GrantedAuthority auth : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) {
permissions.add(auth.getAuthority());
}
if (permissions.contains("PERMISSION_READ") || permissions.contains("PERMISSION_EDIT")) {
//do stuff
}
I've searched for hours and haven't found a more concise and elegant way of doing this, but one must exist. Thanks for your help!
P.S. I'm already familiar with how to handle permissions in JSP like this: ( how to conditionally show jsp content to logged in users with Spring security ) But what I need now is a way to check within the controller.
The HttpServletRequest has a method isUserInRole, which may be useful. Example:
public String someControllerMethod(HttpServletRequest request, ...) {
boolean read = request.isUserInRole("PERMISSION_READ");
...
}
In Spring 3, is there a method that accepts a comma-separated list of permissions and returns a Boolean of whether the logged in user has any of those permissions?
No there is not.
I ended up defining and implementing my own convenience API to do this kind of thing.
You can use Spring security and than use the Pre and Post Annotations which operates on a method level.
The actual logic behind the pre a post annotations is probably accessible so you can probably accomplish what you want.
In Spring 3, is there a method that accepts a comma-separated list of permissions and returns a Boolean of whether the logged in user has any of those permissions?
Are you talking about ExpressionUtils that can evaluate expressions such as hasAnyRole([role1,role2])?
I ended up coding my own class: MyUserDetails class has various methods including one that iterates over roles and permissions to see all the permissions that a user has, such as:
for (Permission permission : role.getPermissions()) {
permissions.add(new GrantedAuthorityImpl(permission.getName()));
}
It's pretty ugly, but I don't have a better way yet.
I use it by doing something like:
MyUser loggedInUser = myUserDAO.getByUsername(principal.getName());
MyUserDetails loggedInUserUD = new MyUserDetails(loggedInUser);
if (loggedInUserUD.hasAnyPermission("perm1, perm2")){
//do stuff
}
I am facing an issue in handling an object in session.
I store an object in the session like this. Assume object is the name of the object. I do this in my action class:
if(object!=null)
{
session.settAttribute("objectName",object);
return mapping.findForward("success");
}
else
{
return mapping.findForward("failure");
}
I map both success and failure to the same jsp page. I check like
if(session.getAttribute("objectName")!=null)
{
object= (SomeObjectClass)session.getAttribute("objectName");
}
if(object!=null)
{
//Do this
}
else
{
//Do that
}
Now here comes my problem. There is no problem when I set the object in first time in the session. I get a problem when I call this action class from two different browsers at the same time I go to else part for one case and if part for one case. I believe this is because session is not thread safe. Is there any solution?
You mention that you're trying to see the same information between two browsers... if the information you're trying to share is "global" (i.e. it should be the same for ALL users of the application, you should store the information in the application scope, not the session scope. (see http://java.sun.com/developer/onlineTraining/JSPIntro/contents.html#JSPIntro5 for explanation of scopes). For example:
ServletContext servletContext = getServlet().getServletContext(); //"application scope"
SomeObjectClass object = (SomeObjectClass) servletContext.getAttribute("objectName");
if(object !=null){
//Do this
} else {
//Do that
}
If you have accounts and a login mechanism and you're wanting the same login to see the same information in two different browsers, then you have a different issue. In that case the information will need to be stored in a "database" (not necessarily a rdbms, could be the application scope!, depending on your needs for persistence) and the information would need to be retrieved in the action class using the user information that could be stored in the session, cookie, etc.
//get the user info from the session, cookies, whatever
UserInfoObject userInfo = getUserInfo(request);
//get the object from the data store using the user info
SomeObjectClass object = getObjectForUser(userinfo);
if(object !=null){
//Do this
} else {
//Do that
}
When you access action/page from different browser you create a new session. In modern browsers you can share session between tabs or views. The only way to share session with more browsers is to use jSessionid param in URLs.