Show Navigation

Grails Basic Auth

Learn how to secure a Grails app using 'Basic' HTTP Authentication Scheme.

Authors: Sergio del Amo

Grails Version: 4.0.1

1 Getting Started

RFC7617 defines the "Basic" Hypertext Transfer Protocol (HTTP) authentication scheme, which transmits credentials as user-id/password pairs, encoded using Base64.

In this guide you are going to create a Grails app and secure it with HTTP Basic Auth.

1.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.8 or greater installed with JAVA_HOME configured appropriately

1.2 How to complete the guide

To get started do the following:

or

The Grails guides repositories contain two folders:

  • initial Initial project. Often a simple Grails app with some additional code to give you a head-start.

  • complete A completed example. It is the result of working through the steps presented by the guide and applying those changes to the initial folder.

To complete the guide, go to the initial folder

  • cd into grails-guides/grails-basicauth/initial

and follow the instructions in the next sections.

You can go right to the completed example if you cd into grails-guides/grails-basicauth/complete

If you want to start from scratch, create a new Grails 3 application using Grails Application Forge.

forgeDefault

2 Writing the App

Create an app with the rest-api profile

grails create-app example --profile=rest-api

2.1 Add Security Dependencies

First thing we need to do is add the spring-security-core Grails Plugin to build.gradle.

build.gradle
compile 'org.grails.plugins:spring-security-core:4.0.0.RC2'

Then run the command:

grails s2-quickstart example.grails User Role

The command generates the following domain classes:

  • grails-app/domain/example.grails.User

  • grails-app/domain/example.grails.Role

  • grails-app/domain/example.grails.UserRole

a password encoder listener:

src/main/groovy/example.grails.UserPasswordEncoderListener

and default security configuration at:

  • grails-app/conf/application.groovy

Modify the generated application.groovy to enable basic auth.

grails-app/conf/application.groovy
grails.plugin.springsecurity.useBasicAuth = true

2.2 Controller

Create HomeController which returns the username of the authenticated user.

grails-app/controllers/example/grails/HomeController.groovy
package example.grails

import groovy.transform.CompileStatic
import grails.plugin.springsecurity.SpringSecurityService
import grails.plugin.springsecurity.annotation.Secured
import grails.plugin.springsecurity.userdetails.GrailsUser

@CompileStatic
@Secured('isAuthenticated()')
class HomeController {

    static responseFormats = ['json']

    SpringSecurityService springSecurityService

    def index() {
        [name: loggedUsername()]
    }

    String loggedUsername() {
        if ( springSecurityService.principal == null ) {
            return null
        }
        if ( springSecurityService.principal instanceof String ) {
            return springSecurityService.principal
        }
        if ( springSecurityService.principal instanceof GrailsUser ) {
            return ((GrailsUser) springSecurityService.principal).username
        }
        null
    }

}

2.3 Views

Render the controller output as a JSON Payload with the aid of JSON Views.

grails-app/views/home/index.gson
model {
    String name
}

json {
    username name
}

2.4 GORM Data Service

GORM Data Services take the work out of implemented service layer logic by adding the ability to automatically implement abstract classes or interfaces using GORM logic.

Create a GORM Data service to ease User domain class CRUD operations.

grails-app/services/example/grails/UserDataService.groovy
package example.grails

import grails.gorm.services.Service

@Service(User)
interface UserDataService {

    User save(String username, String password, boolean enabled, boolean accountExpired, boolean accountLocked, boolean passwordExpired)

    void delete(Serializable id)

    int count()
}

2.5 Test

Create a test which verifies the user authentication flow via Basic Auth.

src/integration-test/groovy/example/grails/HomeControllerSpec.groovy
package example.grails

import grails.testing.mixin.integration.Integration
import grails.testing.spock.OnceBefore
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import spock.lang.Specification

@Integration
class HomeControllerSpec extends Specification {

    UserDataService userDataService
    HttpClient client

    @OnceBefore
    void init() {
        String baseUrl = "http://localhost:$serverPort"
        this.client  = HttpClient.create(baseUrl.toURL())
    }

    def "verify basic auth is possible"() {
        given:
        final String username = 'sherlock'
        final String password = 'elementary'

        when:
        User user = userDataService.save(username, password, true, false, false, false, )

        then:
        userDataService.count() == old(userDataService.count()) + 1

        when:
        HttpRequest request = HttpRequest.GET("/home")
                .basicAuth(username, password)
        HttpResponse<Map> rsp = client.toBlocking().exchange(request, Map)

        then:
        rsp.status == HttpStatus.OK

        and:
        rsp.body().username == username

        cleanup:
        userDataService?.delete(user?.id)
    }
}

To run tests, do ./gradlew test

2.6 Next Steps

Read Basic and Digest Authentication section of the Grails Springs Security Core Plugin documentation to learn about the different configuration options available for Basic Authentication.

3 Do you need help with Grails?

Object Computing, Inc. (OCI) sponsored the creation of this Guide. A variety of consulting and support services are available.

OCI is Home to Grails

Meet the Team