Grails: Simple IP-Filter

Here are a few code snippets to show how easy it is to create an ip filter in Grails, i.e. allowing access only from specific remote addresses using just plain Grails code without any plugin.

Nothing fancy and more or less officially documented. Summarized here to remind myself how easy it is. :-)

The allowed ip addresses can be configured by a regular expression admin.ip using the grails standard configuration stuff. E.g. Config.groovy with a line like this: admin.ip = 192.168.1.2|192.168.1.5 to allow 2 ip addresses. The .s will be escaped automatically by the filter code.

package softnoise

import static org.springframework.http.HttpStatus.FORBIDDEN


class IpFilters {
    def grailsApplication

    def filters = {
        all (controller:'*', action:'*', controllerExclude:'allowed') {
            before = {
                def ips = getIpRegEx (grailsApplication.config)

                if (request.remoteAddr =~ ips) {
                    return true
                }

                response.sendError (FORBIDDEN.value ())
                false
            }
        }
    }

    private String getIpRegEx (def config) {
        config.admin.ip.replaceAll  ('\\.', '\\\\.')
    }

}

Here are a couple of unit tests for it using Spock. The third test just checks if the filter has excluded the allowed controller.

package softnoise

import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.Specification
import org.springframework.http.HttpStatus
import static org.springframework.http.HttpStatus.FORBIDDEN
import static org.springframework.http.HttpStatus.OK


@TestFor (GormController)
@Mock (IpFilters)
class IpFiltersSpec extends Specification
{
    static String VALID_REMOTE_ADDRESS = "162.168.1.2"
    static String INVALID_REMOTE_ADDRESS = "200.200.1.2"

    def setup () {
        grailsApplication.config.admin.ip = VALID_REMOTE_ADDRESS
    }

    def "reject access if the ip does NOT match the admin ip config" ()
    {
        given:
            request.remoteAddr = INVALID_REMOTE_ADDRESS

        when:
            withFilters (action:"index") {
                controller.index ()
            }

        then:
            HttpStatus.valueOf (response.status) == FORBIDDEN
    }

    def "allow access if the ip does match the admin ip config" ()
    {
        given:
            request.remoteAddr = VALID_REMOTE_ADDRESS

        when:
            withFilters (action:"index") {
                controller.index ()
            }

        then:
            HttpStatus.valueOf (response.status) == OK
    }

    def "allow access to 'allowed' controller from anywhere" () {
        given:
            request.remoteAddr = INVALID_REMOTE_ADDRESS

        when:
            withFilters (controller: 'allowed', action:"index") {
                controller.index ()
            }

        then:
            HttpStatus.valueOf (response.status) == OK
    }
}
Advertisements