Override Grails redirect method - grails

I'm carrying the locale of my Grails application in the URL, such as
http://myapp.com/LANG/controller/action/id.
Therefore, I adjusted the URLMappings.groovy with the language attribute. Since I would like to save work and don't apply the lang parameter at every link, I have overridden the g:link taglib with the language from params.lang. This works pretty good.
When I do a redirect from a controller, such as
redirect(action: "logout")
I'd like to append the params.lang automatically instead of writing every time
redirect(action: "logout", params: [lang: params.lang])
I found the thread grails override redirect controller method, but I'm unsure how to proceed. Where does this code take part?
How can I override the redirect() method and add the params.lang-attribute?
Please advice, thank you very much.

The easiest way to do this in your application would be to use a bit of meta programming and the BootStrap.groovy for your Grails application. The following is just a simple example of what that might look like:
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
class BootStrap {
def init = { servletContext ->
def ctx = servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
def app = ctx.getBean("grailsApplication")
app.controllerClasses.each() { controllerClass ->
def oldRedirect = controllerClass.metaClass.pickMethod("redirect", [Map] as Class[])
controllerClass.metaClass.redirect = { Map args ->
// new pre-redirect logic
if (!args['params']) args['params'] = [:] // just in case redirect was called without any parameters
args['params']['whatever'] = 'something' // add something into the parameters map
oldRedirect.invoke delegate, args
// new post-redirect logic
}
}
}
def destroy = {
}
}
The above example just wraps the implementation for redirect on all controllers within your Grails application and injects a new parameter called whatever with the value of something.
The above was tested (quickly) using Grails 2.4.2.

Related

How to use g.formatNumber in grails Service class

I want to use g.formatNumber in service, I have tried a below method, Which i got online. This is not working, its giving me the error "Cannot invoke method formatNumber() on null object", The code is below
import org.springframework.beans.factory.InitializingBean
class MyService implements InitializingBean {
boolean transactional = false
def gspTagLibraryLookup // being automatically injected by spring
def g
public void afterPropertiesSet() {
g = gspTagLibraryLookup.lookupNamespaceDispatcher("g")
assert g
}
def getFormattedNumber(){
def number = g.formatNumber(number: 5000,234 , type: "number" , maxFractionDigits: 2)
return number
}
}
How to do this.
I want to use g.formatNumber in service
Rather than jumping through the hoops you need to use a taglib within a service, it would be simpler to just use java.text.NumberFormat directly
NumberFormat format = NumberFormat.getNumberInstance()
format.maximumFractionDigits = 2
def number = format.format(5000.234)
If the service method is being called from a web request handling thread then you may wish to use the LocaleContextHolder to get the correct locale for the current web request, rather than just using the server's default.
This should work
def g = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib');
You will of course need grailsApplication injected by defining it ala
def grailsApplication

Possible to build secure https links with g:form and g:link in grails 2.x?

This is similar to my as of yet unanswered question https://stackoverflow.com/questions/10825422/can-grails-redirect-command-be-told-to-respect-protocol-of-the-current-request but in this case I simply want to ensure certain links and form actions I specify to controllers are explicitly https. I know I could build these links manually, but that defeats the purpose of the tags automatically adding the correct hostname, application path, etc.
In a perfect world the links would be relative if I was on an https page, and absolute if not, but I'll take absolute links always if that isn't possible.
Thanks
There's an open jira for this request.
I think you can create your own tag lib to do this work. Just call g.createLink and replace http for https.
class MyTagLib {
def secureLink = { attrs, body ->
def link = g.createLink(attrs)
out << link.replace('http','https')
}
}
The quickest way to do this would be to configure your grails.serverURL in Config.groovy to use the https protocol. Then use absolute="true" in your gsp form tags and link tags.
extending Sergios solution, but forcing absolute="true":
class MyTagLib {
def secureLink = { attrs, body ->
// forcing creation of an absolute url
attrs.absolute = 'true'
def link = g.createLink(attrs)
out << link.replaceFirst(/^http:/, 'https:')
}
}
or for your "perfect world" scenario, you could try this:
class MyTagLib {
def secureLink = { attrs, body ->
if (!request.isSecure()) {
attrs.absolute = 'true'
def link = g.createLink(attrs)
out << link.replaceFirst(/^http:/, 'https:')
} else {
out << g.createLink(attrs)
}
}
}

dependency inject Grails Webflow

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.

How to dynamically generate urls used by grails.plugins.springsecurity?

This is not one of the simple questions.. So let me explain it in detail...
The background:
In my grails application I have this mapping:
class UrlMappings {
static mappings = {
"/$storeId/$controller/$action?/$id?"
...
}
}
This means that all url's my application will process has preceding url parameter "storeId". All controllers will use this parameter to render content and perform other actions...
Also I have controller with annotation
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
class SomeController {
def index = {
// ...
}
}
Let's say user is trying to access this page:
/555/some/index
If this is unauthenticated user, security-plugin will redirect him to the
/login/auth
The issue is:
When spring-security will redirect to this page, user will see 404. This happens because login controller will handle only urls like
/555/login/auth
The question is:
What should I do to dynamically build this url?
p.s.
It turns out that:
There is config param for
spring-security, called
"auth.loginFormUrl". But this is just
static text. And I need to build this
url based on what url influenced this
redirection
The redirection is done (I'm not 100%
sure) in org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint#commence.
But how to override it?
Typically that's a static value, but it's called from LoginUrlAuthenticationEntryPoint.getLoginFormUrl(), so you could subclass that and do a dynamic calculation of the url in an overridden method. The plugin already subclasses it with org.codehaus.groovy.grails.plugins.springsecurity.AjaxAwareAuthenticationEntryPoint so you should extend that.
To register your implementation instead of the plugins, add a bean override in grails-app/conf/spring/resources.groovy:
import com.yourcompany.yourapp.YourAuthenticationEntryPoint
beans = {
authenticationEntryPoint(YourAuthenticationEntryPoint) {
loginFormUrl = '/login/auth' // has to be specified even though it's ignored
ajaxLoginFormUrl = '/login/authAjax'
portMapper = ref('portMapper')
portResolver = ref('portResolver')
}
}
You don't have direct access to the request in this method, but it's available in a thread-local - call org.codehaus.groovy.grails.plugins.springsecurity.SecurityRequestHolder.getRequest().

Secure some, but not all pages in a Grails application with the Shiro plugin

Might be just me, but I have a hard time understanding how to secure just some of the pages in a Grails application with the Shiro Plugin.
I use this in my security filter:
class SecurityFilters {
def filters = {
all(uri: "/**") {
before = {
// Ignore direct views (e.g. the default main index page).
if (!controllerName) return true
// Access control by convention.
accessControl ( auth:false)
}
}
}
}
and I have created a user in my bootstrap:
def adminRole = new Role(name: "Administrator")
adminRole.addToPermissions("secured1")
adminRole.addToPermissions("secured2:create,save,edit,update")
adminRole.save()
def user = new User(username: "admin", passwordHash: new Sha512Hash("***").toHex())
user.addToRoles Role.findByName('Administrator')
user.save()
and it works. Problem is, that it also secures all controllers/actions.
I was hoping, that it would be possible to NOT specify the actions I want to protect in my SecurityFilter, but only in the permissions.. But is this possible?
The static property 'filter' allows you to define multiple filtering patterns. You can use the 'uri' parameter or the 'controller' parameter. If you use 'controller' you can also add an 'action' parameter. Each of these parameters takes a regular expression so you can do stuff like:
admin(uri:"/admin/**")
...
browseStore(controller:"store", action:"(show|list)")
...
shopStore(controller:"store", action:"*")
...
Check out http://www.grails.org/Filters for more info.

Resources