Using session variable in another session grails 2.4.2 - grails

I am using grails 2.4.2 and I want to use session value from another session is this possible ? case is :
i have a user when user is logged in and updates his profile then super admin will get notification for updated profile. For that purpose I have set variable as
String notification = session.count
session.count =Integer.parseInt(notification) + verify
where verify is the value of the updated profile
Now when superadmin is logged in I want to get the session.count variable at the menu page is this possible without using session filters how?

No, the sessions are isolated. If you want to access the state set by one user from the session of another one, you have to use a more or less persistent storage:
You could store your vars in a DB or use a service with a e.g. ConcurrentHashMap:
class CrossContextService {
ConcurrentHashMap cache
}
class SomeController{
def crossContextService
def someAction(){
crossContextService.cache.count = ...
}
}

Related

Grails with Shiro - How to assign specifice permission to perticular user even he has role based permission

i installed shiro plugin in my application.i assigned one complete controller for role:'role_developer'..so if any user comes under role_developer he can access all actions of that controller..but here i want remove two actions of that controller..so please suggest me ..
here my code is:
def shiroRole = new ShiroRole()
shiroRole.name='ROLE_DEVELOPER'// create role as role developer
shiroROle.addToPermission('Person') //assigned permissions Person controller with all actionss
shiro.save()
now iam going create one user of ROLE_DEVELOPER and assigning permission some actions like person controller:create,list only
def shiroUser = new ShiroUser()
shiroUser.username='username'
shiroUser.passwordHash= new Sha256Hash("password").toHex()
shiroUser.addToRoles(ShiroRole.findByName('ROLE_DEVELOPER')
newUser.addToPermissions('person:list,create')
newUser.save()
...so here shiroUser shoud not be access all actions assigned to role_dveloper
Don't know how to do this using pure shiro API, but it can be done using grails filters
Something like this
import org.apache.shiro.SecurityUtils
import org.apache.shiro.subject.Subject
class ProjectFilters {
def filters = {
all(controller: 'Person', action: '*') {
before = {
Subject subject = SecurityUtils.getSubject()
//boolean hasRole = subject.hasRole('ROLE_DEVELOPER')
//boolean hasPermission = subject.isPermitted('Person')
if (/*your logic here*/) {
redirect(uri: '/access-denied')
return false
}
}
}
}
}
you don't need filters. :-)
I never used
shiroRole.addToPermission('Person')
but from your question I guess that's equal to
shiroRole.addToPermission('Person:*')
giving the owner of the role access to all actions of the Person controller.
It seems that you now would like to remove some of the permissions for one of the users by assigning permissions to this special user. But that's not the way it works. AFAIK, there is no way to remove permissions, and that's ok because it is more secure...
Shiro works in the following way:
Permissions like a:b give a user access to controller a and action b. A role is a collection of permissions. Permissions are additive.
So if you create a role
def shiroRole = new ShiroRole()
shiroRole.name='ROLE_USER'// create role as role developer
shiroRole.addToPermission('Person:list,show') //assigned permissions Person controller with all actionss
shiroRole.save()
and a user
def shiroUser = new ShiroUser()
shiroUser.username='username'
shiroUser.passwordHash= new Sha256Hash("password").toHex()
shiroUser.addToRoles(ShiroRole.findByName('ROLE_USER')
shiroUser.addToPermissions('person:create,save')
shiroUser.save()
this user will have access to Person:list and Person:show from the assigned role and Person:create and Person:save from his direct permissions.
As you can see, most of the time it is enough to work with roles and avoid using direct permissions.
I hope this helps...

How to get current user role with spring security plugin?

I am using the spring-security-core plugin in my grails app. I need to know the current user's role in a controller action. How can I retrieve that?
You can inject springSecurityService into your controller:
def springSecurityService
and then in your action, call:
def roles = springSecurityService.getPrincipal().getAuthorities()
See the docs here.
From a controller you can use two methods the plugin adds to the metaclass, getPrincipal and isLoggedIn:
def myAction = {
if (loggedIn) {
// will be a List of String
def roleNames = principal.authorities*.authority
}
}
If the action is secured you can skip the loggedIn/isLoggedIn() check.
If you simply need to check to see if a user is in a specific role then use SpringSecurityUtils.ifAllGranted which takes a single String as an argument which contains a comma-delimited list of roles. It will return true if the current user belongs to all of them. SpringSecurityUtils also has methods like ifAnyGranted, ifNotGranted, etc, so it should work for whatever it is you are trying to accomplish.
To get the user
def springSecurityService
def principal = springSecurityService.principal
String username = principal.username
SecurityContextHolder knows that:
SecurityContextHolder.getContext().getAuthentication().getAuthorities()
You can also use getAuthenticatedUser() by itself. This method is automatically injected in every controller, and thus only available from controllers. You will have to use one of the other methods if you want to access the current logged in user from anywhere else.

Advice on keeping track of users "Last Ip Address"

First of all, this is not a question about how to get the user's IP address, as i know how to do that.
Basically, administrators of my website (ASP.NET MVC 3 Web Application) need the ability to block a certain IP address from submitting user content. So i'm storing the "IP Address" against user in our system. Cool.
My question is:
When (e.g at what times, page lifecycle events) should i be checked the user's current IP address and saving to the database?
At the moment, i'm thinking of using session. That is, when i first create the session (e.g Session_OnStart()), grab the users IP address and stick it in the session. Then when the session ends (e.g Session_OnEnd()), i see if the IP address in session is different to that of the database. If it is, update the DB.
At the moment we're using InProc, but there's a good chance we'll go to StateServer later on - and MSDN states Session_OnEnd is only available to InProc. So that might be a problem.
Any thoughts/alternatives to this approach?
EDIT
So i tried using Session_OnStart() to try and do the following thing:
If user is authenticated, get their IP address, get their last IP from the database, and if they different, update the database.
But the problem seems to be that Session_OnStart runs before Application_AuthenticateRequest - so it's never passing the "is authenticated" check.
A good example is if a user logs into my website - using Forms Auth, which sets a cookie with an expiration date of a week (for example).
Then they come back a few days later - the Session_OnStart is fired - but they're not authenticated yet. Even though the cookie is present - it hasn't been processed into the http context yet.
So the Session_OnStart looks like a no go - any other ideas?
Would there be a problem in just logging the ip at the start of the session rather than the end? Like you say, the ip wont change during a session.
Have accepted #lomaxx's answer - but thought i'd add my own for others and the reasoning as to why this is required.
Solution: Global action filter executing on every request.
(Simplified) code:
public class UserTrackingFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
// If the user isn't authenticated or we have already tracked IP this session, bubble back up to base context.
if (!Authenticated || HaveTrackedIpAddressThisSession)
{
base.OnResultExecuted(filterContext);
return;
}
// Get the users current ip address.
var currentIp = HttpContext.Current.Request.CurrentIpAddress(); // extension method to read server variables, cater for proxy, etc
// Get the users last known ip address from repository.
var userService = ObjectFactory.GetInstance(typeof(IUserService)) as IUserService;
var unitOfWork = ObjectFactory.GetInstance(typeof(IUnitOfWork)) as IUnitOfWork;
if (userService == null || unitOfWork == null) return;
// See if the user's ip has changed.
var currentUser = userService.FindById(CurrentUserId);
if (currentUser == null || (currentUser.LastIpAddress != null && IPAddress.Parse(currentUser.LastIpAddress).Equals(currentIp)))
{
// User cannot be found or IP hasn't changed - set session key and bubble back up to base context.
HaveTrackedIpAddressThisSession = true;
base.OnResultExecuted(filterContext);
return;
}
// User's ip has changed - update ip address.
currentUser.LastIpAddress = currentIp.ToString();
// Save.
userService.Save(currentUser);
// Commit.
unitOfWork.Commit();
// Update session key.
HaveTrackedIpAddressThisSession = true;
}
}
"CurrentUserId" and "HaveTrackedIpAddressThisSession" are private properties to shorten code in that method. Basically they read HttpContext.Current.User.Identity and HttpContext.Current.Session["someKey"] respectively.
Why i need a global action filter over a Global.asax event: because my logic requires a Http principal be present, i can't use Session_OnStart since at that time, the forms authentication cookie has not been decrypted into the principal identity. So although this runs on every page request, the session "flag" mitigates this overhead.
Since it's asp.net MVC and you want it to run against all request, I'd consider looking at using a global action filter like the one described here http://weblogs.asp.net/gunnarpeipman/archive/2010/08/15/asp-net-mvc-3-global-action-filters.aspx
I'm taking a guess you are doing the comparison in the database, reading your question.
My suggestion is keeping the blocklist in web.config for simplicity and compare the incoming id to it whenever you need.
If you need to keep the blocklist in the database I'd say use the caching class to cache the blocklist for a reasonable amount of time and compare the ip to the blocklist in your code instead of in the database.

How to access User object in grails controller

I'm using spring security, and I need to get the User domain object in a controller.
If I call SpringSecurityService.getPrincipal(), I get back an object of type org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser. However, what I'm looking for is the User domain object I've defined in my Config.groovy like so:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'project.auth.User'
How can I best get at the User domain object?
Load the user instance using the cached id in the GrailsUser instance:
def user = User.get(SpringSecurityService.principal.id)

Using ASP .NET Membership and Profile with MVC, how can I create a user and set it to HttpContext.Current.User?

I implemented a custom Profile object in code as described by Joel here:
How to assign Profile values?
I can't get it to work when I'm creating a new user, however. When I do this:
Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyRole");
the user is created and added to a role in the database, but HttpContext.Current.User is still empty, and Membership.GetUser() returns null, so this (from Joel's code) doesn't work:
static public AccountProfile CurrentUser
{
get { return (AccountProfile)
(ProfileBase.Create(Membership.GetUser().UserName)); }
}
AccountProfile.CurrentUser.FullName = "Snoopy";
I've tried calling Membership.GetUser(userName) and setting Profile properties that way, but the set properties remain empty, and calling AccountProfile.CurrentUser(userName).Save() doesn't put anything in the database. I've also tried indicating that the user is valid & logged in, by calling Membership.ValidateUser, FormsAuthentication.SetAuthCookie, etc., but the current user is still null or anonymous (depending on the state of my browser cookies).
SOLVED (EDITED FURTHER, SEE BELOW): Based on Franci Penov's explanation and some more experimentation, I figured out the issue. Joel's code and the variations I tried will only work with an existing Profile. If no Profile exists, ProfileBase.Create(userName) will return a new empty object every time it's called; you can set properties, but they won't "stick" because a new instance is returned every time you access it. Setting HttpContext.Current.User to a new GenericPrincipal will give you a User object, but not a Profile object, and ProfileBase.Create(userName) and HttpContext.Current.Profile will still point to new, empty objects.
If you want to create a Profile for a newly-created User in the same request, you need to call HttpContext.Current.Profile.Initialize(userName, true). You can then populate the initialized profile and save it, and it will be accessible on future requests by name, so Joel's code will work. I am only using HttpContext.Current.Profile internally, when I need to create/access the Profile immediately upon creation. On any other requests, I use ProfileBase.Create(userName), and I've exposed only that version as public.
Note that Franci is correct: If you are willing to create the User (and Roles) and set it as Authenticated on the first round-trip, and ask the user to then log in, you will be able to access the Profile much more simply via Joel's code on the subsequent request. What threw me is that Roles is immediately accessible upon user creation without any initialization, but Profile is not.
My new AccountProfile code:
public static AccountProfile CurrentUser
{
get
{
if (Membership.GetUser() != null)
return ProfileBase.Create(Membership.GetUser().UserName) as AccountProfile;
else
return null;
}
}
internal static AccountProfile NewUser
{
get { return System.Web.HttpContext.Current.Profile as AccountProfile; }
}
New user creation:
MembershipUser user = Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyBasicUserRole");
AccountProfile.NewUser.Initialize(userName, true);
AccountProfile.NewUser.FullName = "Snoopy";
AccountProfile.NewUser.Save();
Subsequent access:
if (Membership.ValidateUser(userName, password))
{
string name = AccountProfile.CurrentUser.FullName;
}
Further thanks to Franci for explaining the Authentication life cycle - I'm calling FormsAuthentication.SetAuthCookie in my validation function, but I'm returning a bool to indicate success, because User.Identity.IsAuthenticated will not be true until the subsequent request.
REVISED: I'm an idiot. The above explanation works in the narrow case, but doesn't resolve the core problem: Calling CurrentUser returns a new instance of the object each time, whether it's an existing Profile or not. Because it's defined as a property, I wasn't thinking about this, and wrote:
AccountProfile.CurrentUser.FullName = "Snoopy";
AccountProfile.CurrentUser.OtherProperty = "ABC";
AccountProfile.CurrentUser.Save();
which (of course) doesn't work. It should be:
AccountProfile currentProfile = AccountProfile.CurrentUser;
currentProfile.FullName = "Snoopy";
currentProfile.OtherProperty = "ABC";
currentProfile.Save();
It's my own fault for completely overlooking this basic point, but I do think declaring CurrentUser as a property implies that it's an object that can be manipulated. Instead, it should be declared as GetCurrentUser().
Creating a user just adds it to the list of users. However, this does not authenticate or authorize the new user for the current request. You also need to authenticate the user in the current request context or for subsequent requests.
Membership.ValidateUser will only validate the credentials, but it's not authenticating the user for the current or subsequent requests. FormsAuthentication.SetAuthCookie will set the authentication ticket in the response stream, so the next request will be authenticated, but it does not affect the state of the current request.
The easiest way to authenticate the user would be to call FormsAuthentication.RedirectFromLoginPage (assuming you are using forms authentication in your app). However, this one would actually cause a new HTTP request, which will authenticate the user.
Alternatively, if you need to continue your logic for processing the current request, but want the user to be authenticated, you can create a GenericPrincipal, assign it the identity of the new user and set the HttpContext.User to that principal.
You are going to run into problems with this approach if you enable anonymousIdentification. Rather than Membership.GetUser().UserName, I would suggest using HttpContext.Profile.UserName.
Like this...
private UserProfile _profile;
private UserProfile Profile
{
get { return _profile ?? (_profile = (UserProfile)ProfileBase.Create(HttpContext.Profile.UserName)); }
}
Hat tip: SqlProfileProvider - can you use Profile.GetProfile() in a project?
First of all, thanks #Jeremy for sharing your findings. You helped me get going in the right direction. Secondly, sorry for bumping this old post. Hopefully this will help someone connect the dots.
The way I finally got this working was to use the following static method inside my profile class:
internal static void InitializeNewMerchant(string username, Merchant merchant)
{
var profile = System.Web.HttpContext.Current.Profile as MerchantProfile;
profile.Initialize(username, true);
profile.MerchantId = merchant.MerchantId;
profile.Save();
}

Resources