How to upload a file in Grails 3 - grails

Grails 2 had a plugin for that, there also used to be
request.getFile
method. There is no method like this in Grails 3 as far as I can see, or a plugin.
I tried using
request.getInputStream
But this one is always empty. Other thing I tried was by using Spring-boot way of handling Uploads, but this one relies on
#RequestParam("file") MultipartFile file
It cannot be used in Grails, controllers there do not allow parameters to be defined this way AFAIK.
How to upload files in Grails 3?

Actually there is
request.getFile(fileName)
in Grails 3 as well. It was just not displayed in autofill in my IDE for some reason (the rest of the request methods like getParameters or isPost are displayed correctly).

Related

Shiro - "No SecurityManager accessible to the calling code..." exception in Grails app

I'm in the process of converting a rather large Grails 2 application to Grails 4. It uses the Shiro plugin, which I have upgraded to version 4.3 (compile "org.grails.plugins:grails-shiro:4.3"). In one large GSP (which has always worked OK), the Shiro taglib is now causing the following error:
Error executing tag <shiro:isLoggedIn>: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
The SecurityManager is initialized OK in Bootstrap.groovy, and in another simple test page, shiro:isLoggedIn works fine. So my question is why might the SecurityManager not be available in this use of the taglib? What should I be looking out for?
I'm not a Grails person, but one common reason folks see this problem is that the ShiroFilter did not process the request (or the filter is not configured early enough in the chain).
What happens is the ShiroFilter creates a Subject (the user) and associates it and the SecurityManager with the request thread. Other API (like the tag lib) would use that Subject and/or SecurityManager.
Check your servlet filters, maybe compare them with the old version with the new version and see what has changed.
G'day John, I look after the grails shiro plugin. That error occurs in the taglib because for some reason I'm trying to track down, the ThreadContext doesn't appear to be available. That means the SecurityUtils goes looking for a static security Manager which isn't normally set in web applications.
So basically it's a bug, and hopefully I'll fix it shortly (help welcome).

How do I create a grails 3 plugin which exposes a JSON view?

In my custom Grails plugin, how can I set up a JSON view for a non-domain class and get client apps to use it by default?
I have a view file in the plugin:
/views/com/mycompany/myplugin/myclass/_myClass.gson
When I do grails install, I can see that this .gson file is in the generated JAR. However, the client app is not using it.
What can I do to make it work?
Are there any settings or steps that can make troubleshooting easier?
I am using Grails 3.2.4.
Update:
When I copy the view into a client app, using the exact same path, the view is getting invoked. It's only when the view is defined in the plugin that the view cannot be found.
The framework seems to be trying to look up the plugin as a class from the classloader:
myclientproject_com_mycompany_myplugin_myclass__myClass_gson
How do I get my plugin to add this class to the classpath?
For my use case, what I actually needed was a custom converter.
See:
In JSON views, how do I flatten an object out as a single string?
This obviated the need for my plugin to publish a view.

Overwrite a plugin GSP and Controller within another Plugin

I have a fairly complicated grails plugin dependency structure within my project and I am having problems overriding classes from the security plugin.
My structure is a little something like this:
Web App
|_ Audit Plugin
|_ Spring Security Core Plugin
|_ Security Wrapper Plugin
|_ Audit Plugin
|_ Spring Security Core Plugin
The reason it is like this is audit is shared between some apps which have the security wrapper, and some what don't, which is why it pulls in Security-Core (it needs at least the ability to get the current principal).
Similarly the wrapper is shared between multiple web apps therefore we put it in a plugin. My problem comes after upgrading Spring-Security-Core to version 2.
My wrapper has a customer auth.gsp and LoginController.groovy. In the older version of security this was fine, as the plugin templated those and made them available in the source of the installing plugin.
However now these files are internal to the plugin, and although I know you can override them within the main app, when trying to override them within another plugin I get some bizarre results.
The Spring-Security-Core version of the login page always overrides my custom login page. I cannot get mine to take precedence.
The second problem is that the LoginController.groovy from the Spring-Security-Core plugin sometimes takes precedence over my one from the wrapper. It seems almost random between builds as to which one will be in use.
Is there any correct way to go about making sure my views and controllers take precedence?
OK playing around with things I found a solution that seems to work for me:
Firstly I couldn't change the order in which the plugins load because the security wrapper does a lot with spring beans and it has to load after the core plugin for this to work. So after a bit of digging in the (DefaultSecurityConfig.groovy) I noticed that you can set the following properties:
grails.plugin.springsecurity.failureHandler.defaultFailureUrl = '/login/authfail? login_error=1'
grails.plugin.springsecurity.failureHandler.ajaxAuthFailUrl = '/login/authfail?ajax=true'
grails.plugin.springsecurity.auth.loginFormUrl = '/login/auth'
So I created a custom controller and login page which have a different name to the ones use in the core plugin and changed these properties to point to my locations.
To neaten this up, in the UrlMappings for the wrapper (named: SecWrapperUrlMappings) I put a mapping from /login/** to /seclogin/**.
Make sure that these new locations aren't locked down so that people can access them and that seems to work well. I now reliable know, whichever order they load in my login page and login controller are used.
In Grails-4.013 and spring-security-core-4.0.4, I did the following trick.
In my custom plugin instead of LoginController and LogoutController I named them as SigninController and SignoutController respectively. And in UrlMappings.groovy of App mapped them like..
static mappings = {
"/login/$action?"(controller: "signin")
"/logout/$action?"(controller: "signout")
....
....
}

How to add filters to a Grails app

I'm trying to add these single signout filters to my Grails 2.3.6 app. According to the Grails docs on Filters it seems like you can only add new (custom) filters to Grails apps, whereas these are existing filters imported from another project/JAR.
I scanned my project for the existence of a web.xml and didn't find anything.
How can I add the specific filters in the above link to my Grails app?
The easiest way is to run "grails install-templates" and edit the resulting src/templates/war/web.xml file.
You can use WebXmlConfig plugin which provides a DSL approach to add/modify contents to web.xml.

Is it possible to add Grails MVC classes at deployment time?

I'm writing a Grails app which I'd like 3rd parties to augment at runtime. Ideally they would be able to add a JAR/WAR to the webapp directory which contains new domain, controller and service classes, new views, and other content.
Is there a simple way to do this within grails? Would it be simplest to create a startup script which copies the new classes etc. into the relevant directories and then updates grails.xml and web.xml?
You will be able to do this in version 2 of grails in which plugins will be also OSGI plugins http://jira.codehaus.org/browse/GRAILS/fixforversion/15421
It seems that the Grails plugins will actually fit quite well for this: http://www.grails.org/Understanding+Plugins
A plugin can do just about anything... One thing a plugin cannot do though is modify the web-app/WEB-INF/web.xml or web-app/WEB-INF/applicationContext.xml files. A plugin can participate in web.xml generation, but not modify the file or provide a replacement. A plugin can NEVER change the applicationContext.xml file, but can provide runtime bean definitions

Resources