Skip to content

This is a simple example application that provides a secure RESTful API, written in Grails, for querying a database.

Notifications You must be signed in to change notification settings

jnunderwood/grails-secure-web-service-example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Grails Secure Web Service Example

Description

This is a simple example application that provides a web service for listing and searching for employees in a database. The project has the following characterisitcs:

  • Grails: uses the Grails v3.1 framework
  • Asynchronous: uses Grails asynchronous features
  • Web Service: uses Grails "rest-api" profile to create a web service
  • Secure: uses Grails Spring Security Core v3 and Rest v2 plugins

Object Model

Employee: id, username, firstName, lastName
User: id, username, password
Role: id, authority
UserRole: user, role

The User, Role, and UserRole objects are used for securing the application. The Employee object is the data we are interested in querying.

The intent for this web service is to be consumed by another Grails web application, not a person using a web browser. Thus, the User object actually represents an application, not a person.

Asynchronous Service

There are two services, EmployeeService (synchronous) and AsyncEmployeeService (asynchronous), which are used by primary controller. The synchronous service provides a simple interface to database queries. These include count(), list(), findByField(), findByName(). The asynchronous service automatically mirrors the synchronous version by using the @DelegateAsync transformation.

Restful Controller

The primary controller, EmployeeController, extends RestfulController as per the grails documentation for web services. It provides an asynchronous interface to the employee service by using .onComplete and .onError features of Grails Promises.

Security

This application is secured via Grails Security Rest plugin. There is not much to do. Configuration can be found in grails-app\conf\application.groovy. Additionally, the @Secured annotation is used on the controller methods, which is standard for Grails Spring Security Core.

To secure the communication between the client app and this web service, just use SSL.

Usage

Run grails normally to start the app: grails run-app. Use curl, for example, to test the API:

# login and get authorization token
$ curl -s -H "Content-Type: application/json" -d '{"username": "admin", "password": "admin"}' http://localhost:8080/api/login

# response
{"username":"admin","roles":["ROLE_ADMIN"],"token_type":"Bearer","access_token":"eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUDBcL2JRQlJcL0RvbW9RS0tBMUVvZFlBRTI1RWhsek1TXC9Wa1VtVkUyelVBbDBzUlwvbTRIem4zcDBoV1ZBbUdCaEFiWkdRK2hYNEpyRDBBeUE2ZEdYdXlqdERjTm9GY1pQOTd1ZmZ2K2VMVzZnWURYT3habHdZUHhWWnpLVnZVczFsYkRETU5MY2RQek9vSTdRNTRuME9iTklFN285WEFpK0FFbzhzakFjN2JJOVZCWk54ZGEyMWc2R3R0VFc4VlRwK1lOelNMTUY5cFhmOVIrNVFhZnhIb0tEMlRrc3d1QTVqTEF4VkptMWR5ZVYyeWpWRzZ6QmF6QUlWN3JyUnE1QnVVRnJPaE9tSERxSmtMWUZSQU1Nc3M5dUtWRGthQ3lcL3Z6V2FXaTJvRGJTMkFGeWt6aHR6OWw2UmhuWFYzNzJ4S1N2QVZEcURjVGowNjFOMk1nXC9xT3gxOVVRbEJxcnFTWmJzcEVSWHlMTzNIaTcwNTgrM1h5czlzc0FWQW5zMDlcL1U4emZMRUQzY3VQdlpGNjBGMXA0M1dlOWdOWGFLYmtaSzVnXC9hM1RLMStjZnY1XC9kSG4wWklHV0hlUGY4ZlV6UFB6VFhXVlJKeWpTenFtOUhSTHRmZHM5RXZ2QTBlVzhMSGJcL0JrMVFnXC9WSFNZdlFvVVJCVDNMSldvdGUzaGFGUGE4SHk1dnpTNm9lNmU2MndLT0dTVkVmeTBHNWJmcUJvVjhkXC9UcTlPcG02SVlRVXFlMHhrU0oyUEZxQjZsclJRSDE2Y1RRelwvK0gyY0orajl6WGZLODF4bEVRTUFBQT09Iiwic3ViIjoiYWRtaW4iLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImV4cCI6MTQ1NTAzODQ2NSwiaWF0IjoxNDU1MDM0ODY1fQ.2_Jz9wTYdFWH_ZUngJgNc4hj90_6oYl328ciGd2Ppcs","expires_in":3600,"refresh_token":"eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUDBcL2JRQlJcL0RvbW9RS0tBMUVvZFlBRTI1RWhsek1TXC9Wa1VtVkUyelVBbDBzUlwvbTRIem4zcDBoV1ZBbUdCaEFiWkdRK2hYNEpyRDBBeUE2ZEdYdXlqdERjTm9GY1pQOTd1ZmZ2K2VMVzZnWURYT3habHdZUHhWWnpLVnZVczFsYkRETU5MY2RQek9vSTdRNTRuME9iTklFN285WEFpK0FFbzhzakFjN2JJOVZCWk54ZGEyMWc2R3R0VFc4VlRwK1lOelNMTUY5cFhmOVIrNVFhZnhIb0tEMlRrc3d1QTVqTEF4VkptMWR5ZVYyeWpWRzZ6QmF6QUlWN3JyUnE1QnVVRnJPaE9tSERxSmtMWUZSQU1Nc3M5dUtWRGthQ3lcL3Z6V2FXaTJvRGJTMkFGeWt6aHR6OWw2UmhuWFYzNzJ4S1N2QVZEcURjVGowNjFOMk1nXC9xT3gxOVVRbEJxcnFTWmJzcEVSWHlMTzNIaTcwNTgrM1h5czlzc0FWQW5zMDlcL1U4emZMRUQzY3VQdlpGNjBGMXA0M1dlOWdOWGFLYmtaSzVnXC9hM1RLMStjZnY1XC9kSG4wWklHV0hlUGY4ZlV6UFB6VFhXVlJKeWpTenFtOUhSTHRmZHM5RXZ2QTBlVzhMSGJcL0JrMVFnXC9WSFNZdlFvVVJCVDNMSldvdGUzaGFGUGE4SHk1dnpTNm9lNmU2MndLT0dTVkVmeTBHNWJmcUJvVjhkXC9UcTlPcG02SVlRVXFlMHhrU0oyUEZxQjZsclJRSDE2Y1RRelwvK0gyY0orajl6WGZLODF4bEVRTUFBQT09Iiwic3ViIjoiYWRtaW4iLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImlhdCI6MTQ1NTAzNDg2NX0.XLaIsy1dffb_6-5wRFWbBp8x7yonoD4EpKM42KzdFhw"}

# use the returned token to find employees
$ curl -s -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUDBcL2JRQlJcL0RvbW9RS0tBMUVvZFlBRTI1RWhsek1TXC9Wa1VtVkUyelVBbDBzUlwvbTRIem4zcDBoV1ZBbUdCaEFiWkdRK2hYNEpyRDBBeUE2ZEdYdXlqdERjTm9GY1pQOTd1ZmZ2K2VMVzZnWURYT3habHdZUHhWWnpLVnZVczFsYkRETU5MY2RQek9vSTdRNTRuME9iTklFN285WEFpK0FFbzhzakFjN2JJOVZCWk54ZGEyMWc2R3R0VFc4VlRwK1lOelNMTUY5cFhmOVIrNVFhZnhIb0tEMlRrc3d1QTVqTEF4VkptMWR5ZVYyeWpWRzZ6QmF6QUlWN3JyUnE1QnVVRnJPaE9tSERxSmtMWUZSQU1Nc3M5dUtWRGthQ3lcL3Z6V2FXaTJvRGJTMkFGeWt6aHR6OWw2UmhuWFYzNzJ4S1N2QVZEcURjVGowNjFOMk1nXC9xT3gxOVVRbEJxcnFTWmJzcEVSWHlMTzNIaTcwNTgrM1h5czlzc0FWQW5zMDlcL1U4emZMRUQzY3VQdlpGNjBGMXA0M1dlOWdOWGFLYmtaSzVnXC9hM1RLMStjZnY1XC9kSG4wWklHV0hlUGY4ZlV6UFB6VFhXVlJKeWpTenFtOUhSTHRmZHM5RXZ2QTBlVzhMSGJcL0JrMVFnXC9WSFNZdlFvVVJCVDNMSldvdGUzaGFGUGE4SHk1dnpTNm9lNmU2MndLT0dTVkVmeTBHNWJmcUJvVjhkXC9UcTlPcG02SVlRVXFlMHhrU0oyUEZxQjZsclJRSDE2Y1RRelwvK0gyY0orajl6WGZLODF4bEVRTUFBQT09Iiwic3ViIjoiYWRtaW4iLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImV4cCI6MTQ1NTAzODQ2NSwiaWF0IjoxNDU1MDM0ODY1fQ.2_Jz9wTYdFWH_ZUngJgNc4hj90_6oYl328ciGd2Ppcs","expires_in":3600,"refresh_token":"eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUDBcL2JRQlJcL0RvbW9RS0tBMUVvZFlBRTI1RWhsek1TXC9Wa1VtVkUyelVBbDBzUlwvbTRIem4zcDBoV1ZBbUdCaEFiWkdRK2hYNEpyRDBBeUE2ZEdYdXlqdERjTm9GY1pQOTd1ZmZ2K2VMVzZnWURYT3habHdZUHhWWnpLVnZVczFsYkRETU5MY2RQek9vSTdRNTRuME9iTklFN285WEFpK0FFbzhzakFjN2JJOVZCWk54ZGEyMWc2R3R0VFc4VlRwK1lOelNMTUY5cFhmOVIrNVFhZnhIb0tEMlRrc3d1QTVqTEF4VkptMWR5ZVYyeWpWRzZ6QmF6QUlWN3JyUnE1QnVVRnJPaE9tSERxSmtMWUZSQU1Nc3M5dUtWRGthQ3lcL3Z6V2FXaTJvRGJTMkFGeWt6aHR6OWw2UmhuWFYzNzJ4S1N2QVZEcURjVGowNjFOMk1nXC9xT3gxOVVRbEJxcnFTWmJzcEVSWHlMTzNIaTcwNTgrM1h5czlzc0FWQW5zMDlcL1U4emZMRUQzY3VQdlpGNjBGMXA0M1dlOWdOWGFLYmtaSzVnXC9hM1RLMStjZnY1XC9kSG4wWklHV0hlUGY4ZlV6UFB6VFhXVlJKeWpTenFtOUhSTHRmZHM5RXZ2QTBlVzhMSGJcL0JrMVFnXC9WSFNZdlFvVVJCVDNMSldvdGUzaGFGUGE4SHk1dnpTNm9lNmU2MndLT0dTVkVmeTBHNWJmcUJvVjhkXC9UcTlPcG02SVlRVXFlMHhrU0oyUEZxQjZsclJRSDE2Y1RRelwvK0gyY0orajl6WGZLODF4bEVRTUFBQT09Iiwic3ViIjoiYWRtaW4iLCJyb2xlcyI6WyJST0xFX0FETUlOIl0sImlhdCI6MTQ1NTAzNDg2NX0.XLaIsy1dffb_6-5wRFWbBp8x7yonoD4EpKM42KzdFhw" http://localhost:8080/api/employees/findByName/Wi

# response
[{"id":"22","firstName":"Natalie","lastName":"Wilcox","username":"NWilcox"},{"id":"67","firstName":"Yardley","lastName":"William","username":"YWilliam"}]

Refer to grails-app/controllers/api/UrlMappings.groovy to see the full set of URLs that have been made available.

TODO

Tests! Functional tests, especially, need to create a simple JSON string containing the "admin" username/password pair, send it to the web service, receive the response, confirm authentication, and test successful querying. A similar sequence using "guest" credentials should be tested and confirmed with expected failure.

Furthermore, the application is currently setup with data that is read-only. It might be nice to allow for creating and updating of objects; however, this is not essential.

Miscellaneous

Sample data is loaded from a JSON file during Bootstrap. It was obtained from generatedata.com. Bookmark that site. You're welcome ;-)

About

This is a simple example application that provides a secure RESTful API, written in Grails, for querying a database.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages