Could anyone advise a feasible solution to prevent direct access to *.gsp pages on Grails?
After reviewing intercepting '/**.gsp', I found it is impossible to use that as it not only filters out direct access, but also the pages rendering from controllers, etc.
I tried to setup the following in UrlMapping.groovy, even though I can prevent the *.gsp direct access, but I also make a mess to the navigation of the pages; all the links seem to go to home page then.
"/**.gsp" {
isEligible = {
System.err.println("ALL PARAMS: " + params)
request.requestURL.toString().endsWith(".gsp")
}
controller = {
if (request.requestURL.toString().endsWith(".gsp")) {
"public"
} else {
"*"
}
}
action = {
if (request.requestURL.toString().endsWith(".gsp")) {
"home"
} else {
"*"
}
}
}
Once I thought about setup filter like org.springframework.web.filter.OncePerRequestFilter, but not quite sure how to define it probably as Grails tends to generate the web.xml filters section by itself.
Any thoughts?
Thanks a lot!
tom
unfortunately I did not find a solution with UrlMappings.
here is a solution which is little bit ugly but if you use the same layout (for example main.gsp) on all pages you could add this lines to the layout (main.gsp).
<% if (request.requestURL.toString().endsWith(".gsp")) {
response.sendRedirect("${request.contextPath}/")
} %>
this way if the user tries to access the gsp page direct he gets redirected to the home page.
maybe not the best solution but did work for me so far.
cheers shifty
Add these to UrlMappings:
"/**.gsp" {
controller = {
if(request.requestURL.toString().endsWith(".gsp")) {
"forbidden"
} else params.controller
}
}
And create a ForbiddenController and an index.gsp with "Never think of accessing GSPs directly dude." as its content.
Cheers.
according to the grails FAQ the "/**.gsp" configuration in the UrlMapping.groovy should work.
couldn't try it out yet.
How did you add the links to the page ?
Are the links also broken when you use the link tag ?
<g:link controller="book" action="list">Book List</g:link>
What about writing a filter that will be executed on each request ?
Related
I'm using Grails 2.2.3 and the Spring Security ACL plugin 1.1.1, and I'd like to have a URL that is open to the public and the service layer using the #PostAuthorize annotation secures the resource. We're doing it this way because to determine whether a user has access to a particular object we need to look at the object first.
What I'd like to be able to do is in the controller layer catch the AccessDeniedException, then have the browser ask for credentials and try again. I've tried the naive approach of setting the response status to 401 and redirecting back to itself to try again. The problem I ran into is that the browser never asked for credentials.
To put this into code what I'd like to do is in the controller layer:
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def controllerAction() {
try {
someService.action()
} catch (AccessDeniedException ade) {
// if logged in show FORBIDDEN, if not ask for credentials and try again
}
}
And the service layer would simply have:
#PostAuthorize("""returnObject.availability == 'ALL'""")
def action() {
PersistedObject.findById(1)
}
Thanks for any help!
I ended up solving the problem, and it turns out I was missing a header that I needed to send along with the 401 status code.
To correct what I have above what you want to do is:
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def controllerAction() {
try {
someService.action()
} catch (AccessDeniedException ade) {
if (!springSecurityService.isLoggedIn()) {
response.setHeader 'WWW-Authenticate', 'Basic realm="Grails Realm"' // the missing line
response.sendError HttpServletResponse.SC_UNAUTHORIZED
}
}
The "redirect" I was looking for happens automatically within the browser after credentials are submitted. I was mistaken about needing something specific for the redirect.
Just a quick one to see whether it is possible to run a block of code after the bootstrap's init() has completed?
Hows the best way to go about it?
I have some external systems I need to connect to, and I want to show an 'index' page saying 'Connecting to sub systems' or something similar whilst this block completes, and then once its done the application works as normal.
Am I right in thinking you cant access a page until after bootstrap? Is there a simple way to restrict people accessing other parts of the system whilst this service runs? Does this seem feasible?
Cheers for any help!
Based on your requirement as you also pointed out bootstrap is not your friend. you need a view and controller for your screen and a service for your connection logic to external systems. You also need a flag or a method for sanity check of the communication within the scope of application or session. Then I would suggest to create a filter and check if you have the connections, if not redirect them to the controller that will connect it.
Sudo:
class ConnectionFilters {
def filters = {
loginCheck(controller: '*', action: '*') {
before = {
if (!session.connection ) {
redirect(controller:'connection',action: 'connect')
return false
}
}
}
}
}
class controller {
def connectionService
def connect (){
try {
connectionService.connectTo('systemx')
connectionService.connectTo('systemy')
connectionService.connectTo('systemz')
}
catch(e){
session.connection = false
redirect view:'error'
}
session.connection = true
}
}
class ConnectionService {
def connectTo(systemname){
....
}
}
I have question regarding redirection in Grails web-flow.
I am in a view state which will allow users to enter the answers for a question. On 2 wrong attempts I should be able to re-direct the user to view page from different controller. What i mean is
challengeQuestionOne{
onRender() {
//Display question
}
on('next') {BuildQuestion command ->
bindData(flow.recovery,command)
[return the model to flow]
if(command.hasErrors()) {
flow.command = command
return error()
}
if(check for status. If doesnot pass){
flash.message=message(code:'loginForm.account.locked', default: 'Please Contact Admin.')
redirect(controller : "login",action: "login")//how to redirect from here to diff controller
}
if (//compare answer entered) {
}
else{
//set status not active
}
}.to("challengeQuestionTwo")
on(Exception).to("error")
on('cancel').to('finish')
}
I have tried to redirect from onRender . It was redirecting to the page. But how do I display the error msg on the redirected page. How can i forward the error message from one controller to other??
Ivo Houbrechts wrote an excelent tutorial about grails webflow:
Webflow defines its own flash scope. Although it has the same semantics as the standard grails flash scope (the main purpose is to store objects only until after the next request), it is a different scope. This means that objects stored in webflow's flash scope are not visible in standard grails actions.
import org.springframework.web.context.request.RequestContextHolder
....
RequestContextHolder.currentRequestAttributes().flashScope.message = "YourMessage"
You can read more here:
http://livesnippets.cloudfoundry.com/docs/guide/
Flash scope will not work in this case as expected.
Try to use another approach to show error. E.g. you can pass parameters with redirect. Or you can throw some exception and check it on rendered page as follow:
<g:if test="${flowExecutionException}">
<div class="error"><g:message code="loginForm.account.locked"/></div>
</g:if>
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.
Want to make the URLs SEO friendly when using grails webflow. It is quite limiting with the convention grails uses and hard to go around the way it's built.
For example, i have a flow called fooProcess in the controller called FooController, when i trigger the flow i would like the display: /foo/bar/test, instead of /foo/fooProcess?excecution=e1s2
class FooController {
def fooProcessFlow {
showFoo {
}
}
}
I tried using redirect and specify the uri but that's not supported, grails complains that the page isn't found
fooProcessFlow {
showFoo {
redirect(uri:"/foo/bar/test")
}
}
grails/foo/fooProcess.dispatch/externalRedirect:/foo/bar/test
Also, a redirect is an end state in a flow, if I only want to render the page, i have to use the render method and specify the view name or structure my views according to webflow convention.
fooProcessFlow {
showFoo {
render(view:"/foo/bar/test")
on "add".to "add"
}
}
The url will be in this case
/foo/fooProcessProcess?execution=e6s1
Anyone dealt with this case before ?
Did anyone use UrlRweriteFilter with webflows in grails
http://code.google.com/p/urlrewritefilter/
ken
You can use URLMappings Grails Plugin
See: http://grails.org/doc/latest/ref/Plug-ins/URL%20mappings.html
Edit this file: grails-app/conf/UrlMappings.groovy
Putting something like this inside:
class UrlMappings {
static mappings = {
"/foo/bar/test" (controller: "foo", action: "fooProcessFlow")
"/$controller/$action?/$ids?"{
constraints {
}
}
}
}