springSecurityService.isLoggedIn() returns false inside #MessageMapping function - grails

I'm attempting a simple chat that requires the user to be logged in to use. I've gotten the login working, and can detect it in the controller with springSecurityService.isLoggedIn(). However, when calling that function inside the chat handler, it will always return false. The function in question:
#MessageMapping("/sendchat")
#SendTo("/topic/chats")
protected String sendchat(String getrequest) {
log.info "\n\npre login"
if(springSecurityService.isLoggedIn())
{
log.info "\n\n"+getrequest
//do other things if successful
}
else
{
log.info "\n\nnot logged in"
}
}
It will always execute the else statement, even when the index() function of the controller has correctly detected the user as logged in.

That is because "springSecurityService" is work only for Controller action methods, the "spring-security-core plugin" use filters to setup security-context, then the springSecurityService can retrieve the user login status.
While in your code, the method is "protected" and it is a "websocket plugin" convention, so you should do security according to the plugin document, like this:
class ExampleController {
#ControllerMethod
#MessageMapping("/hello")
#PreAuthorize("hasRole('ROLE_USER')")
#SendTo("/topic/hello")
String hello(String world) {
return "hello from secured controller, ${world}!"
}
#ControllerMethod
#MessageExceptionHandler
#SendToUser(value = "/queue/errors", broadcast = false)
String handleException(Exception e) {
return "caught ${e.message}"
}
}
More details can reference "https://github.com/zyro23/grails-spring-websocket#securing-message-handler-methods".

Related

How to create a login function without using spring security with grails 3 using interceptors

System has two grails apps:
the private backoffice which uses springsecurity and an Operator domain object holding the operators username, password, number of failed logins etc.
the public web front end where users signup, login, and use the system. The User domain object holds the users username, password etc.
Because we are using springsecuirty for the backoffice, I assume we cant use it again for the web (the config and db will conflict). Also, the web just needs a very basic auth (all pages require a valid session except register and the login form itself).
Setting up the login form and the interceptor are easy.
The question is, what should the login form actually do in the controller? I can check the username and password match whats in the DB, then I presumably need to create a session, with session timeouts etc. Where do I look for documentation on how to do this? http://docs.grails.org/3.1.1/ref/Servlet%20API/session.html Tells you how to logout, but not login. I presumably need to store sessions in the DB (so that the user can hit any server) etc.
By looking at some of my old java code, I have got some of the way there.
The interceptor looks like this:
class AuthInterceptor {
public AuthInterceptor() {
// allow the login form and register form to work.
matchAll().excludes(controller: 'auth')
}
boolean before() {
if(session.getAttribute("user")== null ) {
// jump to the login form if there is no user attribute.
redirect controller: 'auth', action: 'login'
return false
}
true
}
boolean after() { true }
void afterView() {
// no-op
}
The controller looks like this:
class AuthController {
def index() { }
def login() {
def email = params.email
def password = params.password
if (email != null) {
// It would be better to invalidate the old session
// but if we do, we cant get a new one...
// session.invalidate()
User user = User.findByEmail(email);
if (user != null) {
log.error("user.pass:" + user.password + " pass:" + password)
// #TODO handle password encryption
if (user.password == password) {
session.setAttribute("user", user)
redirect(controller:"dashboard")
}
}
flash.message = "email or password incorrect"
}
render (view:"login")
} // login()
However, I have not found where we can set the session timeout yet.

What is the best way to check if the user is logged in or not in grails Spring Security?

I would like to check if the user is logged in or not.I have integrated interceptor in most of the projects to check if user is logged in . But this does-not work well with AJAX request and matching all the controllers in the interceptor causes filter to be applied for all controllers including /static/** ,where in this case i will have to exclude (.excludes(uri: "/static/**")) .Is this the correct and standard way of doing?
LoginInterceptor() {
matchAll()
.excludes(controller: "login")
.excludes(controller: "signUp")
.excludes(uri: "/static/**")
.excludes(uri: "/assets/**")
}
boolean before() {
if (!springSecurityService.isLoggedIn()) {
flash.message="You need to login to access furthur pages"
redirect( controller: 'login',action: 'auth');
return false
}
true
}
boolean after() { true }
void afterView() {
// no-op
}
The above code doesnot work with the AJAX request . How do i make a generic interceptor which works well with both AJAX and WEB request? And is this a standard way of monitoring request for logged in?
If you use spring security plugin. You can do it by configuring security config. You can find more here
For ajax request you can check return code and if it is == 403, you can redirect user to the login page.
When working on my project, I found the following way to check the log-in status.
def springSecurityService
boolean canEdit() {
boolean isLoggedIn = springSecurityService.isLoggedIn()
if (!isLoggedIn) { return false }
boolean hasAdminOrCuratorRole = userService.isLoggedInUserACurator() || userService.isLoggedInUserAAdmin()
hasAdminOrCuratorRole
}
Hope this helps!

Grails 3 interceptors and controller by example

I am experimenting with Grails 3 and its new concept of interceptors. Given the following interceptor/controller:
class AuthInterceptor {
// ...other stuff in here
boolean before() {
if(FizzBuzz.isFoo()) {
redirect(controller: auth, action: signin)
true
} else {
true
}
}
}
class AuthController {
AuthService authService
def signin() {
String username = params[username]
String password = params[password]
user = authService.authenticate(username, password)
if(user) {
SimpleSecurityUtils.setCurrentUser(user)
redirect(url: ??? INTENDED_DESTINATION ???)
} else {
// Auth failed.
redirect(action: failed)
}
}
}
AuthService is a Grails Service. I would like there to be one instance of AuthService per instance of AuthController. And I would like AuthController to have prototype scope such that I am never storing state, and a controller is created for each request. What do I have to change in both (AuthService/AuthController) to meet these scope requirements?
Assuming AuthController#signin is executed due to a redirect(controller:auth, action: signin) inside an interceptor, how do I redirect (yet again) the user to their intended destination (that is, the URL they wanted to go to prior to the interceptor intercepting the request) from inside the controller action above?
First, if you redirect to another URL, you must return false to cancel the rendering process, e.g.
redirect(controller: auth, action: signin)
false
Second, if you want back to previews intended URL, you must save it, may be, to session, and then you redirect to the saved URL when you finish signin process.

Detect redirect in Grails

At the end of my save action I redirect to the show action like this:
redirect(action: "show", id: exampleInstance.id)
In my show action I want to be able to detect if someone came directly to this action via a url, or if they were redirected here from another action. I tried request.isRedirected() but it always returns false.
How do I detect if I am in an action as the result of a redirect from another action?
I guess you want to display a confirmation message. Grails has a built-in feature for this kind of use-case:
http://www.grails.org/doc/2.1.0/ref/Controllers/flash.html
Have a look at the example:
class BookController {
def save() {
flash.message = "Welcome!"
redirect(action: 'home')
}
}
In the view you can print or check against flash.message.
In theory, isRedirect checks request attributes. It is equivalent to
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
if(request.getAttribute(GrailsApplicationAttributes.REDIRECT_ISSUED) != null){
println "request was redirect"
}
Try it directly and tell me what happens.
It looks like in the Grails source that isRedirected() is only applicable to the save action, as it gets set in the redirect() method logic, and so wouldn't be set in the show action.
Instead, here are some manual options. One is to add a flag to the flash object, which is then tested in the redirect action. Since it is in flash scope it will be cleared at the end of the show action:
def save() {
// Do stuff
flash.redirectFrom = "save"
redirect(action:"show")
}
def show() {
if (flash.redirectFrom) {
// Respond to redirect
}
// Do other stuff
}
Another option is to issue a chain() call instead of a redirect() and test for the implicit chainModel object. The chainModel won't exist when the show action is requested from an external URL:
def save() {
// Do stuff
chain(action:"show",model:[from:'show'])
}
def show() {
if (chainModel) {
// Respond to redirect
}
// Do other stuff
}

inserting audit logging entry for user login

I am using the grails 1.3.7 with audit logging plugin. I want to capture user login event like "user:PSam logged in at .." in the logs and since plugin does not have onLoad event defined, I am adding it to the domain classes and populate my own audit table entry in this event.
So in grails user domain class I do as follows
def onLoad = {
try {
Graaudit aInstance = new Graaudit();
aInstance.eventType= "User Log in"
aInstance.eventDescription = "User logged in"
aInstance.user_id = username
aInstance.save(flush:true);
println "username="+username
println aInstance;
}
catch (e){
println(e.getMessage())
}
}
I am having two issues here...
1) the username property defined in this domain class as an attribute is coming up as null
2) it throws an exception saying: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Is there another approach to be taken here?
and also can use the plugins audi_log table to populated my onLoad() events entries?
Thanks in advance
Wrap yoyr logic in transaction:
def onLoad = {
Graaudit.withTransaction {
try {
Graaudit aInstance = new Graaudit();
aInstance.eventType= "User Log in"
aInstance.eventDescription = "User logged in"
aInstance.user_id = username
aInstance.save();
println "username="+username
println aInstance;
}
catch (e){
println(e.getMessage())
}
}
}

Resources