I use spring security core plugin. I want to put an object in session just after user has logged in. What I've discovered so far is that there is grails.plugin.springsecurity.LoginController in the plugin. And it has method which is called ajaxSuccess which seems to be invoked just after successfull authentication. So I decided to create another LoginController which extends default one and overrides this method:
#Secured('permitAll')
class LoginController extends grails.plugin.springsecurity.LoginController {
def ajaxSuccess() {
session['somevproperty'] = someValue
super.ajaxSuccess()
}
}
but debugging shows that this method is never invoked. What is going wrong? May there is another way to do what I want? Thank you!
Spring security has it own event listeners. I prefer you use that.
http://grails-plugins.github.io/grails-spring-security-core/guide/events.html
Sample code from above link for success login.
package com.foo.bar
import org.springframework.context.ApplicationListener
import org.springframework.security.authentication.event. AuthenticationSuccessEvent
class MySecurityEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
void onApplicationEvent(AuthenticationSuccessEvent event) {
// handle the event
}
}
Related
I am trying to implement a Spring security filter as follows:
#Configuration
#EnableWebSecurity
open class OpenApiConfigurer : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http.addFilter(object : FilterSecurityInterceptor() {
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain?) {
super.doFilter(request, response, chain)
}
})
}
...
}
I can confirm the #Configuration is loaded because, the configure method is invoked and the filter is added. However the method doFilter is never invoked – I can call whichever requests, but it never does anything inside of it.
What might be wrong? Do I need to do something special?
The reason was following:
// Even though this class is not a bean/service/configuration, it must be defined for
// the Spring-Security to work - otherwise the filters are never invoked with no error.
open class SecurityInitializer : AbstractSecurityWebApplicationInitializer()
I had the same problem, which was fixed by adding an implementation of the AbstractSecurityWebApplicationInitializer (see: Why is Spring Security not working?).
I have a plugin that executes a service call as a background process. That is, it does some action on a timer that is not related directly to any user action.
What I need to do is execute some code in the "main" application every time this service call finishes. Is there a way to hook into that plugin code? I have access to the plugin code, so altering it isn't a huge obstacle.
You can have your plugin service publish an event when it completes then listen for that event in your main application. I have used this pattern a few times and it has been a very convenient way to decouple various pieces of of my application. To do this, create an event class.
class PluginEvent extends ApplicationEvent {
public PluginEvent(source) {
super(source)
}
}
Then, have your plugin service implement ApplicationContextAware. That gives your plugin a way to publish your events
class PluginService implements ApplicationContextAware {
def applicationContext
def serviceMethod() {
//do stuff
publishPluginEvent()
}
private void publishPluginEvent() {
def event = new PluginEvent(this)
applicationContext.publishEvent(event)
}
}
Then in your main application, create a listener service that will respond when the event is published:
class ApplicationService implements ApplicationListener<PluginEvent> {
void onApplicationEvent(PluginEvent event) {
//whatever you want to do in your app when
// the plugin service fires.
}
}
This listener doesn't need to be a Grails Service, you can just use a POJO/POGO, but you'll need to configure it as a spring bean inside resources.groovy.
I have been using this approach recently and it has worked well for me. It's definitely a nice tool to have in your Grails toolbox.
Is it possible to inject a Spring bean into a Grails webflow? I tried the following
class CheckoutController {
ShoppingService shoppingService
def checkoutFlow = {
start {
action {
// This attempt to access the service doesn't work
flow.addresses = shoppingService.getOrder()
}
}
}
}
I can access shoppingService from a regular controller action, but I can't access it from an action of the webflow (see above).
add the following to your controller:
def transient shoppingService
There are issues with dependency injection with webflows in controllers that contain traditional actions plus webflows. It worked for me if the traditional action executed first.
see:
GRAILS-7095
GRAILS-4141
Webflows also break notions of defaultAction in mixed controllers. I have found the first webflow wins and becomes the default action.
separately using transient keeps your service from be serialized between flow states. (e.g. don't have to implement serializable)
At first I thought what you listed was pseudocode but I made a sample app using your example and got the NPE as well. I think it may be your flow structure that is the problem. action blocks should go within a flow state. Your flow definition should look something like:
class CheckoutController {
ShoppingService shoppingService
def checkoutFlow = {
start {
action {
flow.addresses = shoppingService.getOrder()
if(flow.addresses) {
showForm()
}
else {
showError()
}
}
on("showForm").to "showForm"
on("showError").to "showError"
}
showError {
...
}
//etc.
}
}
You can definitely use injected services in your web flows. I am guessing that the problem lies in your flow structure.
I'm using Grails Spring Security Core plugin and I need to perform a few actions when logout happens such as delete some class instances related to the user. I tried the following code:
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import grails.plugins.springsecurity.Secured
class LogoutController {
def index = {
def currentUser = currentUser()
currentUser.searchedResults.each{searched->
def searchInstance = Search.get(searched.searchId)
searchInstance.delete()
}
redirect uri: SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
}
private currentUser(){
return User.get(springSecurityService.principal.id)
}
}
However Grails is giving the error: No such property: User for class: LogoutController
My guess is that this is happening because when I installed Spring security core plugin, the LogoutController and LoginController were created in a different package called "default package". Is there any way to overcome this issue? Any help would be appreciated! Thanks
You simply need to import the User class. Something like:
import mypackage.User
I am trying to use the commentable plugin with Spring Security.
I can't manage to write the right
grails.commentable.poster.evaluator
I tried {User.get(springSecurityService.principal.id)},
but from the CommentController, both User and springSecurity seems unaccessible.
What should I do?
For springSecurityService.principal.id since there's no dependency injection field for springSecurityService it can't work, so you need to call what springSecurityService.principal.id calls - org.springframework.security.core.context.SecurityContextHolder.context.authentication.principal.id
To fix the problem with User, you'll need the full class name with package. So combined, this should be
{com.yourcompany.yourapp.User.get(org.springframework.security.core.context.SecurityContextHolder.context.authentication.principal.id)}
I adapted Burt's answer such that it doesn't throw an exception if nobody is logged in
grails.commentable.poster.evaluator = {
def principal = org.springframework.security.core.context.SecurityContextHolder.context.authentication?.principal
if (principal?.hasProperty('id')) {
def currentUserId = principal.id
if (currentUserId) {
com.yourcompany.yourapp.User.get(currentUserId)
}
}
}