I am working on grails application, where I have a Profile domain for every User. There are two ways to view and edit profile of a user -
The user clicks on the header link called Profile, so he can view his profile and edit it if needed.
The admin can view profile of any user by clicking a user link from the list of all users.
So in the first case if a user himself is checking his profile then on the controller side I am checking the user using spring security method "springSecurityService.currentUser".
While in second case, if the admin is checking the profile of a user then userInstance is passed to the controller action.
Problem arises when I am using it for the first case, i.e. User himself is checking his profile. Here when I check for null of userInstance parameter using if/else condition, the userInstance passes null check even though it is null. And when I print it on console it gives me a null pointer exception.
Code is-
def show(User userInstance){
println("Inside show action of profileController")
println("userInstance: " + userInstance) //Output- userInstance: null
if(userInstance != null){
println("userInstance: " + userInstance) //Output- userInstance: null
}else{
println("userInstance is null") //It never prints even though userInstance is null
userInstance = springSecurityService.currentUser
}
//More functionality to come
}
So basically its very basic thing but I am not able to figure it out, why is it not checking for null but sill printing as null.
when I check for null of userInstance parameter using if/else condition, the userInstance passes null check even though it is null.
This implies a pretty fundamental bug in the Groovy compiler, which I doubt. Try this instead:
def show(User userInstance){
userInstance = userInstance ?: springSecurityService.currentUser
}
Presumably when an admin is viewing a user's profile, the ID of the user is passed as a request parameter? If so, what's to stop a malicious user who knows (or guesses) the ID of another user, from accessing their profile?
Use this approach : Forget about isNull function but , and also forget about userIntance == null statement and try this !userInstance ,it works as follow!!!
Example
var user = User.get(10);
According to you :
def show(User userInstance){
println("Inside show action of profileController")
println("userInstance: " + userInstance) //Output- userInstance: null
if(!userInstance){
println("userInstance: " + userInstance) //Output- userInstance: null
}else{
println("userInstance is null") //It never prints even though userInstance is null
userInstance = springSecurityService.currentUser
}
//More functionality to come
}
Check this groovy script example on groovy Console Here
Related
I have this service class:
class UserService {
def springSecurityService
#Listener(topic = 'currentUser', namespace = 'auth')
public User getCurrentUser(){
return springSecurityService.currentUser
}
def authenticate(OAuthToken oAuthToken){
SecurityContextHolder.context.authentication = oAuthToken
return springSecurityService.currentUser
}
}
If I use the authenticate method, springSecurityService.currentUser returns the current user. But if I am already logged in I want to get a current user with getCurrentUser method and it returns null. I debugged the Springsecurityservice.getCurrentUser method and the method "isLoggedIn" returns false.
But if I try this in my view it works:
<sec:ifLoggedIn>Yeeees</sec:ifLoggedIn>
UPDATE:
When I run UserService.getCurrentUser the SCH.context.authentication in SecurityService returns null. After that call, the view is being rendered and SCH.context.authentication returns a right authentication.
UPDATE 2:
I analysed it and it seems to happen only if I use it with event bus. If I call getCurrentUser directly from controller, it works fine, but if I use event bus it doesn't.
I use Event Bus from platform-core plugin. Is there another SCH.context for Event Bus?
I found a solution. The problem was that Event Bus works within a thread and spring context will not be delivered to threads by default.
The option 'context holder strategy' in config solve this:
grails.plugin.springsecurity.sch.strategyName = org.springframework.security.core.context.SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
http://grails-plugins.github.io/grails-spring-security-core/latest/#miscProperties
You can get the principal and then search the user, in mycase the domain is AppUser
def user = springSecurityService.getPrincipal()
def testUser =AppUser.findByUsername(user.username)
I am modifying the AccountController to use a separate class that queries Active Directory for information and stores that info in the Login Model. In my account controller I have this:
try{
LDAPAuth.LDAPQuery(model);
return RedirectToAction("Homepage", "HomePage");
}
catch (Exception e)
{
throw new Exception(e.message);
}
I am surrounding it in a try/catch becasue if the DirectorySearcher did not find the user it will tell them that the username or passwrod is wrong and I am just trying to pass the exception on the view. What is happening is that when it gets inside the try block the model is set perfectly fine with the attributes I want but the redirection takes me to
http://localhost:7606/Account/Login?ReturnUrl=%2fHomePage%2fHomepage
LDAPAuth class is implemented according to this solution, I also surrounded this in try/catch to catch invalid users which I am trying to pass to the View
http://stackoverflow.com/questions/1295157/how-do-i-query-activedirectory-using-ldap-with-a-username-not-a-cn
I am not sure what is the problem and debugging it is not helping either.
I hope somebody can help! Thanks
Before you redirect to action, issue a FormsAuthentication.SetAuthCookie. This should override the default behaviour of the return URL:
Its also worth noting that the bool in SetAuthCookie(string username, bool createPersistantCookie) can be used to remember the user. For this example I have set it to false.
try{
LDAPAuth.LDAPQuery(model);
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("Homepage", "HomePage");
}
In my grails application I want to know when it is the first login after a user successfully register.
I'm using the spring security core plugin.
What is the best way to perform this ?
Unless you're automatically logging the user in after registering, or know that the user will manually login right after a registration, you'll probably have to persist something like "lastLoginDate" with each user. Then just check if that value is empty (which is their first time logging in), otherwise just update the login date each time they login.
You can put this code in one of the events that is fired after a successful login.
UPDATED based on comments
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
// fired after successful authentication
// and AFTER user info provided to SpringSecurityService
// to get currentUser, you can use the following
def springSecurityService = appCtx.getBean("springSecurityService")
def user = springSecurityService.currentUser
...
}
or
grails.plugins.springsecurity.onAuthenticationSuccessEvent = { e, appCtx ->
// fired after successful authentication
// and BEFORE user info provided to SpringSecurityService
// (e.g. springSecurityService.currentUser == null)
}
More info can be found on the SpringSecurity documentation under events.
I've added an onAuthenticationSuccessEvent to my config.groovy in order to try add a Login model to a list within the users User model. The problem i'm having, is that the event listener is a closure, and as such has no HibernateSession or access to state outside of the closure.
I know its possible to bind a HibernateSession by doing something like this:
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
Login.withTransaction{
login = new Login()
}
}
The problem is that the Login belongs to a User, and needs to have the User defined in its constructor. How do I pass the User into the closure?
I want to do something like:
def user = grails.admin.User.read(appCtx.springSecurityService.currentUser.id)
Login.withTransaction{ user ->
login = new Login(user: user)
}
but dont know how to pass the specific user in.
You can't do Login.withTransaction{ user -> since the parameter of the closure you pass to the withTransaction method takes an argument which is the TransactionStatus - you don't get to specify the type, just the name.
But I'm not sure why you're seeing what you're seeing with regard to closure scope. The cool thing about closures is that they enclose their scope, hence the name. So variables outside of the closure are always available inside the closure.
You would want the User to be loaded inside the withTransaction block though so it's in the same Hibernate session as the transaction's, otherwise the Login save will fail since the User will be disconnected. And use load(), not read() since you're just setting the foreign key in the Login, so load() works best since it just creates a proxy and doesn't hit the database, but makes the id available for the Login save. For the same reason you'd want to avoid using the currentUser method since it's just a shortcut for User.get().
Having said all that, this worked for me:
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
Login.withTransaction { status ->
new Login(user: appCtx.springSecurityService.currentUser).save()
}
}
but since the e variable is an InteractiveAuthenticationSuccessEvent you're better off using this:
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx ->
Login.withTransaction { status ->
def user = User.load(e.authentication.principal.id)
new Login(user: user).save()
}
}
Why Can't you do some thing like below, Just fetch the user inside the closure.
Login.withNewSession {
def user = grails.admin.User.read(appCtx.springSecurityService.currentUser.id)
login = new Login(user: user)
}
OR
Login.withTransaction{
def user = grails.admin.User.read(appCtx.springSecurityService.currentUser.id)
login = new Login(user: user)
}
I am trying to do relatively simple thing: log in user manually. I am using FacebookGraph plugin to connect to facebook. If user logs in via Facebook, i get his ID and I want to authenticate him in ShiroSecurity. Of course such trivial thing like
session.user = user
does not work.
I have found the code in the wiki, which should do the trick:
Object userIdentity = user.email
String realmName = "username";
PrincipalCollection principals = new SimplePrincipalCollection(userIdentity, realmName);
Subject subject = new Subject.Builder().principals(principals).buildSubject();
However it does not work. I still get redirected to auth/login with log.debug message that ShiroSubject is null. Maybe it be because I invoke this code in a service.
Any ideas how to make this work?
UPDATE:
def authenticate(authToken) {
log.info "Attempting to authenticate ${authToken.username} in DB realm..."+authToken.encodeAsJSON()
def username = authToken.username
// Null username is invalid
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm.")
}
// Get the user with the given username. If the user is not
// found, then they don't have an account and we throw an
// exception.
log.debug "reached this point2"
def user = ShiroUser.findByUsername(username)
log.debug "reached this point"
if (!user) {
throw new UnknownAccountException("No account found for user [${username}]")
}
log.info "Found user '${user.username}' in DB"
// Now check the user's password against the hashed value stored
// in the database.
def account = new SimpleAccount(username, user.passwordHash, "ShiroDbRealm")
if (!credentialMatcher.doCredentialsMatch(authToken, account)) {
log.info "Invalid password (DB realm)"
throw new IncorrectCredentialsException("Invalid password for user '${username}'")
}
return account
}
Take a look at the AuthController.groovy -> the signIn action.
This is exactly the code you need to login. The Main Step is
SecurityUtils.subject.login(new UsernamePasswordToken(username,password))
Hope that helps...
ok. This is only the starting point... take a look at your Realm-Code on /Realms . There you'll find an authenticate(authToken) closure. It seems that this gets called through SecurityUtils.subject.login() and handles the credentials check...
This should solve your problem with the hashed password....
According to the Javadoc, Subject.Builder() does not automatically bind the subject to the current application thread. Try adding this after building your Subject instance:
ThreadContext.bind(subject)