4

Update: I have changed this question to be about the specific problem I am having. This is because unit testing of Filters will be supported in Grails 2.0 so hopefully the documentation will be better then.

I am trying to write unit tests for the filters I set up to implement Shiro security in my grails app. I am using Grails 1.3.7 and wont be able to use 2.0 for a while (if ever) for this particular project.

The idea behind my filter is that I need to give anonymous access to a number or controller/action combinations but protect access to the others. I also want it to fail safe, i.e. if you forget to explicitly allow access then access is prohibited.

The filter class

class SecurityFilters {
    def filters = {

        homeAccess(controller: "home", action: "*") {
            before = {

                // Allow all access
                request.accessAllowed = true
            }
        }

        serverAccess(controller: "server", action: "list") {
            before = {

                // Allow all access
                request.accessAllowed = true
            }
        }

        layerAccess(controller: "layer", action: "list|listBaseLayersAsJson|listNonBaseLayerAsJson|showLayerByItsId") {
            before = {

                // Allow all access
                request.accessAllowed = true
            }
        }

        all(uri: "/**") {
            before = {

                // Check if request has been allowed by another filter
                if (request.accessAllowed) return true            

                // Ignore direct views (e.g. the default main index page).
                if (!controllerName) return true

                // Access control by convention.
                accessControl(auth: false)
            }
        }
    }
}

The Unit tests

import org.codehaus.groovy.grails.plugins.web.filters.FilterConfig

class SecurityFiltersTests extends FiltersUnitTestCase {

    protected void setUp() {
        super.setUp()
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testHomeControllerFilter() {

        checkFilter('homeAccess')
    }

    void testServerControllerFilter() {

        checkFilter('serverAccess')
    }

    void testLayerControllerFilter() {

        checkFilter('layerAccess')
    }

    void testAllFilter() {

        assertTrue "Write tests", false
    }

    void checkFilter(String filterName) {

        FilterConfig filter = initFilter(filterName)
        assertNotNull filterName + " filter should exist", filter
        assertExistsBefore(filterName)

        assertEquals "accessAllowed should be null to start with", null, filter.request.accessAllowed

        // Run filter
        filter.before()

        assertEquals "accessAllowed should be true now", true, filter.request.accessAllowed
    }
}

The Exception

The problem is that when these test are run I get the following exception:

No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at grails.test.MockUtils$_addCommonWebProperties_closure32.doCall(MockUtils.groovy:316)
    at shiro.SecurityFilters$_closure1_closure5_closure12.doCall(SecurityFilters.groovy:40)
    at shiro.SecurityFilters$_closure1_closure5_closure12.doCall(SecurityFilters.groovy)
    at shiro.SecurityFiltersTests.checkFilter(SecurityFiltersTests.groovy:92)
    at shiro.SecurityFiltersTests$checkFilter.callCurrent(Unknown Source)
    at shiro.SecurityFiltersTests.testLayerControllerFilter(SecurityFiltersTests.groovy:65)

Additionally I have placed the following line in the Unit test:

println "filter.request: " + filter.request

Which prints the following:

filter.request: org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletRequest@2914cca4

So it certainly seems to be using a mock request object.

So, the questions.

Am I using FiltersUnitTestCase correctly to execute my filters?

And, if so:

Why am I experiencing this exception?

David
  • 1,940
  • 3
  • 17
  • 30

1 Answers1

1

A reminder to the rules of debugging for everyone out there: Keep removing code until you find the exact line the problem is on. Even if it is obvious that the line is not causing the problem. Because: sometimes it actually is.

As part of my debugging work I had the following line of code in my filter:

println "controllerName = '${controllerName}', actionName = '${actionName}'"

This was directly before the line:

request.accessAllowed = true

I had taken it out of the code pasted into this question to try and keep it tidy, but apparently I hadn't tried commenting it out when running the tests. Sorry to anyone who looked-into that code and couldn't find a problem. You were right, the problem wasn't in any of the code I provided.

So the answer is you may see the exception reported here if you try and access the controllerName or actionName variables.

The solution is to use the setControllerName() and setActionName() methods in FiltersUnitTestCase before executing any filter that might reference controllerName or actionName.

David
  • 1,940
  • 3
  • 17
  • 30