Category Archives: Grails

Below are the steps to install the groovy SDK.
step no – 1 :
open the terminal and type the below statement.

step no -2 :
when you execute the step-1,you will get the following output, these are the last few lines of the output.

now copy the source location (from your terminal), as mentioned in the above statement.
for example :

step – 3 :
now install the groovy SDK, it may ask  your system user password.

It will also ask in the middle of installation as Do you want to continue? [Y/n] then type ‘y’ , see in the below statement.

step – 4 :
now check the groovy version.

you have installed groovy SDK software successfully.

Before we leap into the actual discussion, we should know how the client-server communication works.

    1. Browser sends a request to the server.
    2. Server handles that request.
    3. Dispatches the request to specified controller.
    4. Controller processes the request and adds required HTTP headers to the response.
    5. Finally flush the response to the browser.

Lets do it programmatically:

Defines a new action in SampleController

  def tooResponseHeaders(){
        (1..150).each{
            def cookieValue= 'This is default cookie value'
            def cookieName='Test-Cookie'
            Cookie cookie = new Cookie(cookieName, cookieValue)
            response.addCookie(cookie)
        }
       render "Welcome !"

By seeing the above line, you may think that it will simply return “Welcome!”  But what I am doing here is making response buffer bigger by adding more cookies. We are all set now. Run the grails app

>grails run-app

Hit the following link: http://localhost:8080/sample-oauth2-app/sample/sampleIndex, you could see this page (Blank Page)

BlankPage

After a lot of debugging, I came to know that when server flush the response, it checks whether response header’s size is bigger than max HTTp response header size, and on failing case it throws a HeadersTooLarge Exception and gives a 500 error response. Here you can see the server response and Error message server will throw.

LiveHttpHeaders

ExceptionMessage

The solution for it is:
1. We should not add more data to the response headers
2. Increase the maxHttpHeaderSize in server.xml

In this article, we will learn how to integrate Swagger-UI with Grails application. Basically ‘SwaggerUI’ is used to serve documentation of a REST API. It describes and visualises RESTful web services, not only that it will help to expose the REST APIs to end users. With Swagger-UI we can represent our APIs in graphical representation. In this article, we are going to integrate Swagger-UI into sample-oauth2-app. Our aim is to see the following pages.

swagger-ui-5

swagger-ui-6

Here are the steps to integrate Swagger-UI:

  1. Add swagger dependencies
  2. Configure the Swagger
  3. Writing a controller that enables the swagger into action
  4. Annotate API with swagger annotations
  5. Add swagger UI plugin

1. Add Swagger Dependencies

In this initial step, we need to add swagger dependencies in grails-app/conf/BuildConfig.grooy

compile "io.swagger:swagger-core:1.5.3"
compile "io.swagger:swagger-jaxrs:1.5.3"

2.Configure the Swagger

Swagger’s BeanConfig class allows you to set various properties for Swagger’s initialization. Configure the BeanConfig class in resource.groovy

Method Property Name Purpose
setTitle(String) title Sets the title of the application.
setDescription(String) description Sets the description of the application.
setTermsOfServiceUrl(String) termsOfServiceUrl Sets the URL of the application’s Terms of Service.
setContact(String) contact Sets the contact information for the application.
setLicense(String) license Sets the license of the application
setLicenseUrl(String) licenseUrl Sets the license URL of the application.
setVersion(String) version Sets the version of the API.
setBasePath(String) basePath Sets the basePath for the API calls.
setApiReader(String) apiReader Sets an API Reader class for Swagger.
setFilterClass(Sting) filterClass Sets a security filter for Swagger’s documentation.
setResourcePackage(String) resourcePackage Sets which package(s) Swagger should scan to pick up resources. If there’s more than one package, it can be a list of comma-separated packages
setScan(boolean) scan When set to true, Swagger will build the documentation
import io.swagger.jaxrs.config.BeanConfig
beans = {
    swaggerConfig(BeanConfig) {
        def serverUrl = grailsApplication.config.grails.serverURL.toString()
        def hostName = serverUrl.substring(serverUrl.indexOf("://")+3)
        resourcePackage = 'com.nbos.core'
        host = hostName
        basePath = "/api"
        version = 'v0' // Default "1".
        title = 'Core Registration API, Version V0' // Default: App Name.
        description = 'API for Accessing secured resources'
        contact = 'webservices@nbostech.com'
        license = ''
        licenseUrl = ''
    }
}

3. Writing a Controller that Enables the Swagger into Action

After the configuration, we have to write controller to get the swagger into action

package com.nbos.apidoc
import org.codehaus.groovy.grails.web.mapping.LinkGenerator

class ApiDocController {
    LinkGenerator grailsLinkGenerator
    def apiDocService
    def index = {
        String basePath = grailsLinkGenerator.serverBaseURL
        render(view: 'index', model: [apiDocsPath: "${basePath}/api/swagger-json"])
    }
    def swaggerJson = {
        render apiDocService.generateJSON()
    }
}

Map these actions in URL mappings.groovy

> grails url-mappings-report
Dynamic Mappings
 |    *     | /oauth/authorize                                          | Action: (default action)                 |
 |    *     | /oauth/token                                              | Action: (default action)                 |
 |    *     | /${controller}/${action}?/${id}?(.${format)?              | Action: (default action)                 |
 |    *     | /                                                         | View:   /index                           |
 |    *     | ERROR: 500                                                | View:   /error                           |

Controller: apiDoc
 |    *     | /api/info                                                 | Action: index                            |
 |    *     | /api/swagger-json                                         | Action: swaggerJson                      |

Controller: dbdoc
 |    *     | /dbdoc/${section}?/${filename}?/${table}?/${column}?      | Action: (default action)                 |

Controller: sample
 |    *     | /api/sample/securedWithClientOAuth                        | Action: securedWithClientOAuth           |
 |    *     | /api/sample/securedWithUserOAuth                          | Action: securedWithUserOAuth             |

For Swagger to actually produce the documentation, you must setScan(true). The BeanConfig should be called when your application starts up. Invoke the BeanConfig in service class

package com.care.apidoc
import io.swagger.jaxrs.config.BeanConfig
import io.swagger.util.Json;
import grails.transaction.Transactional

@Transactional
class ApiDocService {

    def swaggerConfig

    /*
     * generates SWAGGer JSON
     */
    def generateJSON() {

        String[] schemes = ["http"] as String[]
        swaggerConfig.setSchemes(schemes)
        swaggerConfig.setScan(true)
        def swagger = swaggerConfig.getSwagger()

        Json.mapper().writeValueAsString(swagger);
    }
}

4. Annotate API with Swagger Annotations

We are annotating the SampleController APIs with Swagger annotations, that will help to generate SwaggerJson.

package com.nbos.core
import grails.plugin.springsecurity.annotation.Secured
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation

import javax.ws.rs.GET
import javax.ws.rs.Path
import javax.ws.rs.Produces

@Path("/sample")
@Api(value = "auth", description = "Secured Access Using tokens")
@Produces(["application/json", "application/xml"])
class SampleController {

    static responseFormats = ['json', 'xml']

    @GET
    @Path("/securedWithClientOAuth")
    @ApiOperation(value = "Secured Access Using client tokens", httpMethod = "GET" )
    @Secured("#oauth2.isClient()")
    def securedWithClientOAuth() {
        def map=['sucsess':'AuthenticationSucces','message':'Client is authenticated successfully']
        respond map
    }
    @GET
    @Path("/securedWithUserOAuth")
    @ApiOperation(value = "Secured access using user token", httpMethod = "GET" )
    @Secured("#oauth2.isUser()")
    def securedWithUserOAuth(){
        def map=['sucsess':'AuthenticationSucces','message':'User is authenticated successfully']
        respond map
    }
}

5. Add swagger UI plugin

Lastly, we need to add Swagger UI plug. You can Download swagger UI, copy and paste it in folder/web app. Now write the index.html apidoc/index.gsp

Swagger UI

    %{--<!-- TODO: move these to use asset-pipeline -->--}%

    <script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'jquery-1.8.0.min.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'jquery.slideto.min.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'jquery.wiggle.min.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'jquery.ba-bbq.min.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'handlebars-2.0.0.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'underscore-min.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'backbone-min.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2', file: 'swagger-ui.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'highlight.7.3.pack.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'marked.js')}"></script><script src="${resource(dir: 'vendor/swagger-ui/2.1.4-M2/lib', file: 'swagger-oauth.js')}"></script>%{--<!-- enabling this will enable oauth2 implicit scope support -->--}% %{--<script></script>--}%<script>// <![CDATA[         $(function () {             window.swaggerUi = new SwaggerUi({                 url: "${apiDocsPath}",                 dom_id: "swagger-ui-container",                 supportedSubmitMethods: ['get', 'post', 'put', 'delete'],                 onComplete: function(swaggerApi, swaggerUi){                     if(typeof initOAuth == "function") {                         /*                          initOAuth({                          clientId: "your-client-id",                          realm: "your-realms",                          appName: "your-app-name"                          });                          */                     }                     $('pre code').each(function(i, e) {                         hljs.highlightBlock(e)                     });                 },                 onFailure: function(data) {                     console.log("Unable to Load SwaggerUI");                 },                 docExpansion: "none"             });             $('#input_apiKey').change(function() {                 var key = $('#input_apiKey')[0].value;                 if(key && key.trim() != "") {                     swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorization("Authorization", "Bearer " + key, "header"));                 }             })             window.swaggerUi.load();         });      // ]]></script></pre>
<div id="header">
<div class="swagger-ui-wrap">
<a id="logo" href="http://swagger.io">swagger</a>
<form id="api_selector">
<div class="input"><input id="input_baseUrl" name="baseUrl" type="text" placeholder="http://example.com/api" /></div>
<div class="input"><input id="input_apiKey" name="apiKey" type="text" placeholder="access_token" /></div>
<div class="input"><a id="explore" href="#">Explore</a></div>
</form>
</div>
</div>
<div id="message-bar" class="swagger-ui-wrap"></div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
<pre>

 

Now we all are set. Run the server.

> grails run-app

Go to browser and try to access “http://localhost:8080/sample-oauth2-app/api/info”. You will see above screens on the browser.

What is OAuth2

OAuth2 is a authorisation framework that provides a simple mechanism for end users to grant a third party access to their resource without providing a username and password.It also enable the user to grant limited access to their data in terms of scope ,duration etc.Typically client send username and password to the server ,for access the resources.Instead of doing this typical authentication process what client/user will do with OAuth2 is ,client sends request to oauth2 server(authentication server) it will validate the user request and respond with a accesstoken .With that access token client access the resources.Here the steps how client communicate with server

  1. User log in to the oauth2 server(authentication server)
  2. Obtain the Token
  3. Access protected resource with the Token
  4. Server check the Token
  5. If token is valid token allow the user to access protected resources

oauth2
Here we are going to implement Sample OAuth2 application with grails

 

1.Create App

create a sample app using grails

> grails create-app sample-oauth2-app
 cd sample-oauth2-app/
> grails run-app

2.Configure Spring Security Oauth2 Provider

2.1 Add spring-security-oauth2-provider dependency in grails-app/conf/BuildConfig.groovy

plugin{
 compile "org.grails.plugins:spring-security-oauth2-provider:2.0-RC1"
}

Then compile the App

> grails compile

This will install the oauth2 provider in your application.OAuth2 provider defines two endpoints.
OAuth endpoints are the URLs we use to make OAuth authentication requests.We need to use the correct OAuth endpoint when issuing authentication requests in your application

  • Authorization endpoint
  • Token endpoint

Authorization endpoint
The authorization end point is an an endpoint on the authorisation server where the resorce owner login in and get authentication to client application.

Token endpoint
Token endpoint is the endpoint on the server where the client application exchange the client_id and client secret ,for an access token.
In this blog we are going to concentrate on Token endPoints.
The following are the rest token endpoints supporting OAuth2 protocols, which provide a token using various protocols.

[ POST] /oauth/token:

  • OAuth2 Authorization Code Grant
    parameters[?grant_type=authorization_code&code=139R59&client_id=my-client ]
  • OAuth2 Resource Owner Password Grant.
    parameters [ ?grant_type=password&client_id=..&client_secret=my-secret&username=aa&password=bb&scope=read ]
  • OAuth2 Client Credentials Grant
    parameters [ ?grant_type=client_credentials&client_id=my-client&scope=read ]
  • OAuth2 Refresh Token Grant
    parameters [ ?grant_type=refresh_token&refresh_token=22c3f395-690c-4838-a14f-3137e6802db1&client_id=my-client&scope=read ]

Each OAuth flow defines which endpoints you need to use and what request data you need to provide.

Here you can see dynamic mappings of end points.

> grails url-mappings-report

| URL Mappings Configured for Application
| ---------------------------------------

Dynamic Mappings
 |    *     | /oauth/authorize                                          | Action: (default action)                 |
 |    *     | /oauth/token                                              | Action: (default action)                 |
 |    *     | /${controller}/${action}?/${id}?(.${format)?              | Action: (default action)                 |

2.2 Create Domain classes

Execute grails s2-init-oauth2-provider <package> <client-name> <authorization-code-name> <access-token-name> <refresh-token-name>
eg:

> grails s2-init-oauth2-provider com.nbos.oauth OAuthClient OAuthAuthorizationCode OAuthAccessToken OAuthRefreshToken 

This will create Domain classes for you in specified domain package and update the grails-app/conf/Config.groovy so the plugin recognize them.

  • Client
  • AUthorizationCode
  • AccessToken
  • RefreshToken

Client;
This class represent Client details like client_seceret,clientId,clinet scope,client authorities

AuthorizationCode
This class represents an authorization code that has been issued via the authorization endpoint as part of an authorization code grant. The authentication object serialized is an instance of OAuth2Authentication from Spring Security OAuth.

AccessToken
This class represents an access token than has been issued to a client on behalf of a user. The authentication object serialized is an instance of OAuth2Authentication from Spring Security OAuth.

RefreshToken
This class represents a refresh token issued as part of one of the grants that supports issuing a refresh token. The length of time the refresh token is valid is determined by the token services and can be configured.

Updated lines in grails-app/conf/Config.groovy

grails.plugin.springsecurity.oauthProvider.clientLookup.className = 'com.nbos.oauth.OAuthClient'
grails.plugin.springsecurity.oauthProvider.authorizationCodeLookup.className = 'com.nbos.oauth.OAuthAuthorizationCode'
grails.plugin.springsecurity.oauthProvider.accessTokenLookup.className = 'com.nbos.oauth.OAuthAccessToken'
grails.plugin.springsecurity.oauthProvider.refreshTokenLookup.className = 'com.nbos.oauth.OAuthRefreshToken

2.3 Exclude client secret from Logs

When grails logs a stacktrace ,the log message may include all the names and values of request parameters for the current request.To mask out the values of secure request parameters , specify the parameters name in the grails.exceptionresolver.params.exclude config property.
Update the params exlusion list in grails/config/Config.groovy , so the client secrets are not logged in clear

> grails.exceptionresolver.params.exclude = ['password', 'client_secret']

2.4 Sample Client

Before our(client) application can access oauth2 resources we should resister the client with the ouath2.It’s similar to creating clientId for our app in Google plus/facebook .The registration is typically a one-time task. Once registered, the registration remains valid.

For example, you can register a client in grails-app/conf/Bootstrap.groovy as follows:

 def init = { servletContext ->
        new OAuth2Client(
                clientId: 'my-client',
                clientSecret: 'my-secret',
                authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'],
                authorities: ['ROLE_CLIENT'],
                scopes: ['read','write'],
                redirectUris: ['http://localhost:8080/sample-oauth2-app']
        ).save(flush: true)

    }

2.5 Configure the filter chain

Spring Security maintains a filter chain internally where each of the filters has a particular responsibility and filters are added or removed from the configuration depending on which services are required. The ordering of the filters is important as there are dependencies between them.Spring Security infrastructure is based entirely on standard servlet filters.We can exclude some default filters with chain map.

grails.plugin.springsecurity.filterChain.chainMap = [
        '/oauth/token': 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-rememberMeAuthenticationFilter',
        '/**': 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter',
]

Run the app,You can observe what ever url you give it will navigate to /login/auth .This is because of ‘staticRules’ Map

grails.plugin.springsecurity.controllerAnnotations.staticRules = []

To avoid this ,comment ‘staticRules’ Map and add below two configurations in config.groovy

grails.plugin.springsecurity.rejectIfNoRule = false
grails.plugin.springsecurity.fii.rejectPublicInvocations = false

If you set rejectIfNoRule or rejectPublicInvocations to true we’ll need to configure the staticRules map to include URLs that can’t otherwise be guarded.

2.6 Register Authentication Providers

The Spring security plugin register Authentication providers that will perform authentication.Add below lines in grails-app/conf/config.groovy

grails.plugin.springsecurity.providerNames = [
        'clientCredentialsAuthenticationProvider',
        'daoAuthenticationProvider',
        'anonymousAuthenticationProvider',
        'rememberMeAuthenticationProvider'
]

This is the time to run the app and test the application

grails run-app

3.Sample input/output on token endpoint

3.1 Client credentials grant

The client credentials grant is performed by authenticating the client via token endpoint.This is the client we loaded in grails-app/conf/bootstrap.groovy

> curl –X POST –d {
"grant_type":"client_credentials",
"client_id":"my-client",
"client_secret":"my-secret",
"scope":"read"
}
http://localhost:8080/sample-oauth2-app/oauth/token

The access_token come in json response

{
access_token: "3c27a91f-4753-425e-aa6e-6f8920a21d42"
token_type: "bearer"
expires_in: 43199
scope: "read"
}

3.2 Resource Owner Grant

Create a domain classes in grails.

grails create-domain-class com.nbos.core.Login

Add the necessary properties for Login.groovy

package com.nbos.core

class Login {

    def springSecurityService

    String username
    String password

    boolean enabled;
    boolean accountExpired;
    boolean accountLocked;
    boolean passwordExpired;

    static constraints = {
        username blank: false, unique: true
        password blank: false
    }

    static mapping = {
        password column: 'password'
    }

    def getAuthorities() {
        [];
    }

    def beforeInsert() {
        encodePassword()
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
        }
    }

    protected void encodePassword() {
        password = springSecurityService.encodePassword(password)
    }

    @Override
    def String toString(){
        "Login[${id},${username}]"
    }
}

Register a user in grails-app/conf/Bootstrap.groovy as follows:

def init = { servletContext ->
.......
......
  new Login(username: 'abc',password: 'abc').save(flush: true)
}

Set userLookup domain class as Login.groovy in grails-app/conf/config.groovy

grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.nbos.core.Login'

Our next step is to get the resource owner password grant.Send a request with curl

> curl –X POST –d {
"grant_type":"password",
"client_id":"my-client",
"client_secret":"my-secret",
"username":"abc",
"password":"abc",
"scope":"read"
}
 http://localhost:8080/sample-oauth2-app/oauth/token

The access_token is included in response

{
access_token: "b43138dc-aad1-4dc9-9071-8d8230b15c0a"
token_type: "bearer"
refresh_token: "2110e67b-9739-4cf3-908a-7332c7d0df43"
expires_in: 43199
scope: "read"
}

4.Controlling Access To Resources

Access to resources is controlled by the Spring Security Core plugin’s access control mechanisms.This plugin has full support for the OAuth 2.0 SPeL extensions provided by the underlying Spring library. Refer to the methods in OAuth2SecurityExpressionMethods for what is available in the plugin.
Using SPeL is the only tested and confirmed way to enforce OAuth 2.0 specific restrictions on resource access.

Create a Sample controller

grails create-controller com.nbos.core.Sample

Add action to Sample controller which are protected with spring security

package com.nbos.core
import grails.plugin.springsecurity.annotation.Secured

class SampleController {

    static responseFormats = ['json', 'xml']

    @Secured("#oauth2.isClient()")
    def securedWithClientOAuth() {
        def map=['sucsess':'AuthenticationSucces','message':'Client is authenticated successfully']
        respond map
    }

    @Secured("#oauth2.isUser()")
    def securedWithUserOAuth(){
        def map=['sucsess':'AuthenticationSucces','message':'User is authenticated successfully']
        respond map
    }

}

SDKMAN is a tool for managing parallel versions of multiple Software Development Kits on most Unix based systems.

Before you start, ensure JAVA_HOME is set. Also, if you already have a grails installation set up, make sure you get rid of it and remove the GRAILS_HOME variable from your bash_profile.

Installing SDk

Installing GVM is a very simple process .To run the installer enter the following in the terminal.

$ curl -s get.sdkman.io | bash

If all is well ,you should see a message confirmation that gvm is installed. Follow the instructions on screen to complete installation. Next open a new terminal or enter

$ source "$HOME/.sdkman/bin/sdkman-init.sh"

Check sdk installed or not 

Open new terminal and enter the following

$ sdk help

Install new version of Grails

Simply tell to gvm which version of grails do you want to install. To do that run the following in terminal

$ sdk install grails --version--

eg: sdk install grails 2.4.4

You will see new version of grails being installed.Id you don’t specify any version the latest version of grails will be installed.

Listing available versions of grails

Run the following in terminal

$ sdk list grails

This will show you available versions of grails.

Switching to different grails versions

To activate a version of grails you have installed

$ sdk use grails --version--;

eg:sdk use grails 2.4.4

Check current activated grails

To do that run the following in terminal

$ sdk current grails

This will show you current version of grails

Uninstall the grails

Removing a version is as simple as

$ sdk uninstall grails --version--

Switch User

To enable a user to switch from the current Authentication to another user’s, set the useSwitchUserFilter attribute to true. This feature is similar to the ‘su’ command in Unix. It enables, for example, an admin to act as a regular user to perform some actions, and then switch back.

Switching to Another User

To switch to another user, typically you create a form that submits to /j_spring_security_switch_user:

Here the form is guarded by a check that the logged-in user has ROLE_SWITCH_USER and is not shown otherwise.

Switching Back to Original User

To resume as the original user, navigate to /j_spring_security_exit_user.

Customizing URLs

You can customize the URLs that are used for this feature, although it is rarely necessary:

Property Default Meaning
useSwitchUserFilter false Whether to use the switch user filter.
switchUser. switchUserUrl ‘/j_spring_security_switch_user’ URL to access (via GET or POST) to switch to another user.
switchUser. exitUserUrl ‘/j_spring_security_exit_user’ URL to access to switch to another user.
switchUser. targetUrl Same as successHandler.defaultTargetUrl URL for redirect after switching.
switchUser. switchFailureUrl Same as failureHandler.defaultFailureUrl URL for redirect after an error during an attempt to switch.
switchUser. usernameParameter SwitchUserFilter. SPRING_SECURITY_SWITCH_USERNAME_KEY The username request parameter name

Sample url to switch as user:

http://coolshop.com/j_spring_security_switch_user?j_username=logmein%40shopping.com

j_username  is passed url encoded value logmein@shopping.com which is the user login we want to switch.

On successful switching user will be redirected to url configured using  switchUser. targetUrl

Dynamic switchUser.targetUrl

If you are working on Spring Security Web version “spring-security-web-3.0.7”. You have ability to overrider ‘switchUser. targetUrl’  value for current request by  pass request parameter “spring-security-redirect”. On successful user switch Spring security looks for a parameter with name “spring-security-redirect” before using ‘switchUser. targetUrl’ .

If  grails.plugin.springsecurity.switchUser.targetUrl : /my-accunt/profile

URL: http://coolshop.com/j_spring_security_switch_user?j_username=logmein%40shopping.com  will redirect user to /my-accunt/profile

URL: http://coolshop.com/j_spring_security_switch_user?j_username=logmein%40shopping.com&spring-security-redirect=%2Fmy-account%2Ffavourites  will redirect user to /my-account/favourites

By passing spring-security-redirect request parameter we can overrider default switch user targetUrl.

 

The intent is to implement OAuth2 provider protocol & secure appropriate rest api’s using OAuth2 token.

The generic need for any application would be to have some public API’s that can be accessed without any security, & some secured using token associated with clientId/secretKey & some secured using token associated with user credentials.

The following are the rest endpoints supporting OAuth2, which provide a token using different protocols, i.e Authorization Code Grant flow (1a,1b), Implicit Grant flow (2), Resource Owner Password Grant (3), Client Credentials Grant (4), Refresh Token Grant(5).

  • OAuth2 Rest End Points 
      1. [ GET] /oauth/authorize:
        • (1a) OAuth2 Authorization Code Grant
          parameters [ ?response_type=code&client_id=my-client&scope=read ]
        • (2) OAuth2 Implicit Grant
          parameters [ ?response_type=token&client_id=my-client&scope=read ]
      2. [ POST] /oauth/token:
            • (1b) OAuth2 Authorization Code Grant
              parameters [ ?grant_type=authorization_code&code=139R59&client_id=my-client ]
            • (3) OAuth2 Resource Owner Password Grant.
              parameters [ ?grant_type=password&client_id=..&client_secret=my-secret&username=aa&password=bb&scope=read ]
            • (4) OAuth2 Client Credentials Grant
              parameters [ ?grant_type=client_credentials&client_id=my-client&scope=read ]
            • (5) OAuth2 Refresh Token Grant
              parameters [ ?grant_type=refresh_token&refresh_token=22c3f395-690c-4838-a14f-3137e6802db1&client_id=my-client&scope=read ]

The following are the API endpoints we would like to support using the token provided above

    1. Public API’s
      1. [  GET] /api/v0/about
      2. [  GET] /api/v0/sample/about
    2. Secured access using a Client Token
      1. [  GET] /api/v0/sample/securedWithClientOAuth : Sample API secured with client token
      2. [POST] /api/v0/members/signup: Create a new User
      3. [POST] /api/v0/auth/login: Login using username/password credentials
    3. Secured access using User Token
      1. [  GET] /api/v0/sample/securedWithUserOAuth: Sample Secured with user token
      2. [  GET] /api/v0/members: Get list of members supports pagination ?filter=”field1=value,field2=v”&sort=”field2″&offset=15
      3. [  GET] /api/v0/members/{memberId}: Get information about a user
      4. [  PUT] /api/v0/members/{memberId}: update a user
      5. [  GET] /api/v0/auth/logout: logout the user associated with the token

In addition, we would want the api server to respond with the following standard HTTP Status responses across all api calls

  1. HTTP 200: Any successful REST api call along with its specific json data
  2. HTTP 400: Any api that results in validation errors like “invalid username”, “empty password” etc. along with json data with list of property errors
    “{ [propertyName:””, messageCode:””, message:””], [propertyName:””,messageCode:””].. }
  3. HTTP 404: Any non-existent REST api request using json along with json response of
    { messageCode:”api.notfound”, message:”locale based message desc”}
  4. HTTP 500: Any REST api request resulting in internal error along with json response of
    {messageCode:”api.internal.error”, message:”locale based message” }
  5. HTTP 403: Any REST api request resulting in forbidden
  6. HTTP 405: Any REST api request using invalid method i.e using GET instead of POST/PUT

Any REST API that supports pagination should respond data in the following format, with results containing the appropriate list items and accept “filter”,”offset”,”sort” & “order” as parameters.

{ 
      "from":10, 
        "to":15, 
"totalCount":100,
     results: [
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" }
     ]
}

Here is sample input/output for the api endpoints for successful responses

Input Output
[POST] /api/v0/members/signup: Create a new User
curl –X POST –d ‘{
“clientId”:”my-client”,
“username”:”abcdef”,
“password”:”123456″,
“email”:”abcd@ef.com”,
“firstName”:”abcd”
}’
{“member”: {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
},
“token”: {
“access_token”: “7224..”,
“expires_in”: 43199,
“refresh_token”: “ebff..”,
“scope”: “read,write”,
“token_type”: “bearer”
} }
[POST] /api/v0/auth/login: Member Login
curl –X POST –d ‘{
“clientId”: “my-client”,
“username”: “abcdef”,
“password”: “123456”
}’
{“member”: {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
},
“token”: {
“access_token”: “7224..”,
“expires_in”: 43199,
“refresh_token”: “ebff..”,
“scope”: “read,write”,
“token_type”: “bearer”
} }
[  GET] /api/v0/members/{memberId}: Get Member
curl -H     “Authorization: Bearer 7224…” http://../api/v0/members/5 {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
}
[  PUT] /api/v0/members/{memberId}: Update Member
curl –X PUT –H “Authorization: Bearer 7224…”
-d { “id”: 5, “firstName”: “fname”, “lastName”: “lname”,”phone”: 0, “description”: “desc”} http://../api/v0/members/5
{
“description”: “desc”,
“email”: “abcd@ef.com”,
“firstName”: “fname”,
“id”: 5,
“lastName”: “lname”,
“phone”: 0,
“socialAccounts”: []
}


We will walk thru the implementation in the following sequence.

      1. Implement OAuth2 endpoints using spring security oauth2 provider plugin along with sample endpoints access controlled by client/user tokens
      2. Annotate your API with Swagger-UI
      3. Create API for Member Create/Read/Update
      4. Write Unit tests for Member Create/Read/Update
      5. Create API for Auth login/logout & Write Unit Tests
      6. Integrating with Email plugin

Before we start ensure that your environment is all set

      • Install Grails 2.4.5
      • Create a starter app using grails
        mkdir ~/work;
        cd ~/work;
        grails create-app starter-app-rest-grails;
        cd starter-app-rest-grails;
        grails run-app;  // you should now see
        ...
        ======================================================================
        | Server running. Browse to http://localhost:8080/starter-app-rest-grails
        

1. Create API for Member Create/Read/Update

Lets make a list of features that we want, just so it would guide us in our design.

  Feature
Login Domain
1a Ensure that password is getting encrypted while saving
1b We shouldn’t be able to create new Login with same username
1c We should have the ability to expire an account
1d We should have the ability to lock an account
Member Domain
2a Each member should have a unique UUID to identify them using URL
2b We cannot have two members with same email
2c A Member cannot exist without a Login
API / MemberController / create
3a Registration with an existing username should respond with 400
3b Registration with an existing email should respond with 400
3c Invalid email syntax should return 400
3d Successful registration should respond with 200 along with member info

Given the list of features, we will start off with the following ER Model

login-member-ermodel

Our next step is to create a domain classes in grails.

grails create-domain-class com.nbos.core.Login
grails create-domain-class com.nbos.core.Member

Add the necessary properties for Login.groovy

package com.nbos.core

class Login {

    def springSecurityService

    String username
    String password

    boolean enabled;
    boolean accountExpired;
    boolean accountLocked;
    boolean passwordExpired;

    static constraints = {
        username blank: false, unique: true
        password blank: false
    }

    static mapping = {
        password column: 'password'
    }

    def getAuthorities() {
        [];
    }

    def beforeInsert() {
        encodePassword()
    }

    def beforeUpdate() {
        if (isDirty('password')) {
            encodePassword()
        }
    }

    protected void encodePassword() {
        password = springSecurityService.encodePassword(password)
    }

    @Override
    def String toString(){
        "Login[${id},${username}]"
    }
}

Add the necessary properties for Member.groovy

package com.nbos.core

import org.apache.commons.lang.builder.HashCodeBuilder

class Member {

    Login login
    String uuid
    String firstName
    String lastName
    String email
    Long phone
    String description

    def memberService

    static belongsTo = [login:Login]

    static constraints = {
        email(nullable: true)
        lastName(nullable: true)
        phone(nullable: true)
        description(nullable: true)
        uuid(nullable: true)
    }

    static mapping = {
    }

    @Override
    boolean equals(other){
        if (!(other instanceof Member)) return false;
        if ( id &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; other.id &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; id == other.id ) return true;
        if ( email == other.email ) return true;
        return false;
    }

    @Override
    int hashCode(){
        def builder = new HashCodeBuilder();
        if(id) { builder.append(id) }
        else { builder.append(email) }
        builder.toHashCode()
    }

    def beforeInsert() {
        uuid = memberService.generateUUID()
    }

    @Override
    def String toString() {
        "member: ${id}, ${login}"
    }
}

Time to create service classes

grails create-service com.nbos.core.MemberService
grails create-service com.nbos.core.TransactionService

And its simple implementation for each of these.

package com.nbos.core

class MemberService {
    def generateUUID() {
        UUID.randomUUID().toString()
    }
}

The intent of creating TransactionService is to help us in unit testing of controllers, the idea is, we could check that “transactionService.rollback” is being called in case of exceptions.

package com.nbos.core

import org.springframework.transaction.TransactionStatus

class TransactionService {

    def rollback(TransactionStatus status) {
        status.setRollbackOnly();
    }
}

Lets Create our first API to create a Member

grails create-controller com.nbos.core.MemberRestfulController

Add an action to create Member.

package com.nbos.core

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import grails.transaction.Transactional
import grails.validation.Validateable

class MemberRestfulController {
    static responseFormats = ['json', 'xml']
    static allowedMethods = [create: 'POST']

    static namespace = 'v0'

    def transactionService
    def memberService
    def mailService
    def securityService

    def create() {
        MemberRegistrationCommand cmd = new MemberRegistrationCommand()
        bindData(cmd, request.getJSON())
        try {
            if (!cmd.validate()) {
                response.setStatus(400)
                respond cmd.errors.collect { [ messageCode:it.code, message:message(code:it.code,args:it.arguments), propertyName:it.field] }
                return
            }
            Member m = cmd.createMember()
            respond [ firstName:m.firstName, lastName:m.lastName, id:m.id, email:m.email ]

        } catch (e) {
            transactionService.rollback(transactionStatus)
            response.setStatus(500)
            log.error("Signup Internal Error : ${e.getMessage()}")
            respond [messageCode:'internal.error', message:message(code:'internal.error',args:[])]
        }
    }
}

@Validateable
class MemberRegistrationCommand {
    String clientId
    String username
    String email
    String password
    String firstName
    String lastName
    static constraints = {
        clientId nullable:true, validator: { val, cmd, errors -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
            Object[] args = new Object[1]
            args[0] = val
            if(!val){
                errors.rejectValue("clientId", "clientId.empty", args, null)
            }
        }
        username nullable: true, validator: { val, cmd, errors -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
            Object[] args = new Object[1]
            args[0] = val
            if (!val) {
                errors.rejectValue("username", "user.username.null", args, null)
            } else if (Login.findByUsername(val)) {
                errors.rejectValue("username", "user.username.exists", args, null)
            }
        }
        email nullable: true, validator: { val, cmd, errors -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
            Object[] args = new Object[1]
            args[0] = val
            if (val) {
                def pattern = /[_A-Za-z0-9-]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})/
                if ( ! val ==~ pattern ) {
                    errors.rejectValue("email", "user.email.wrongformat", args, null)
                } else {
                    def member = Member.findByEmail(val)
                    if (member) {
                        errors.rejectValue("email", "user.email.exists", args, null)
                    }
                }
            }
        }
        password nullable: true, validator: { val, cmd, errors -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
            Object[] args = new Object[1]
            args[0] = val
            if (!val) {
                errors.rejectValue("password", "user.password.null", args, null)
            }
        }
        firstName nullable: true, validator: { val, cmd, errors -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;
            Object[] args = new Object[1]
            args[0] = val
            if (!val) {
                errors.rejectValue("firstName", "user.firstName.null", args, null)
            }
        }
        lastName nullable: true
    }

    def createMember() {
        Login login = new Login(username: username, password: password, enabled: true)
        login.save(failOnError: true, flush: true)
        Member m = new Member(login: login, firstName: firstName, lastName: lastName, email: email)
        m.save(failOnError: true, flush: true)
    }
}

 

We will continue this post with creating tests for the features that we have built.

Solr provides ability to customize handling of Solr requests by extending built in or by writing completely new Request handlers and Search Components. Search components define the logic for running Solr queries and make the results available in the response which will be returned to users. There are several default search components that work with all SearchHandlers without any additional configuration and these are executed by default, in the following order

Screen Shot 2015-09-08 at 10.16.11 am

If you register a new search component with one of these default names, the newly defined component will be used instead of the default. The search component is defined in solrconfig.xml separate from the request handlers, and then registered with a request handler as needed. By default Solr uses a search component named “query” for performing search operations.  Below sample configuration is for overwriting default search component with a new search component ‘MyQueryComponent’.

/products/solrconfig.xml

Executing multiple search queries

By default QueryComponent can execute one Solr search per request. For supporting multiple Solr queries we need to write a search component either by extending QueryComponent or SearchComponent.

Write a class by extending QueryComponent

Overwrite prepare() and process() methods to customize our needs.

prepare() method:

We can write logic for validating request and prepare component for processing queries.  The custom query component we are writing do not support grouping and validating mandatory query parameters.

process () method:

Process method first extracts raw solr queries (buildRawQueries())  and build SolrParams (parseRawQueries) out of raw Solr queries. Each SolrParams instance resembles one query.  Execute one query at a time and the query result is added to ResponseBuilder. The logic for query execution is delegated to QueryComponent as there is nothing much we need to override for our requirement (processQuery).  Queries are executed in order specified and until we retrieve max rows required.  If rows parameter is passed -1 all queries are executed.

Prepare the final result by merging all the results of all queries executed and return to user.

Sample Solr query:

http://localhost:8983/solr/products/select?qn=3&mQry1=…&mQry2=….&mQry3=…&rows=25&bebug=true&sort=…&qt=multiQuery

Parameters:
qt  :   Name of query handler that process multi query Solr request .
qn :   Number of Solr queries in the request
mQryX: Solr query which can be executed independently. Where X in parameter name should be an integer which denotes the order of execution of query. If ‘qn’ parameter is 4, we have to pass mQry1, mQry2, mQry3 and mQry4 parameters.
debug:  Defaults to false. If passed true Solr query debug information is returned in response.
sort:  Default Sort parameter if sort parameter is not available in individual queries (mQryX).

Register custom search component in solr  by adding the following in solrconfig,xml

MultipleQueryComponent has to be register with RequestHandler to be used. We can configure a new request handler using existing StandardRequestHandler or write a custom request handler.

Use built-in request handler and configure MultipleQueryComponent:

As a custom request handler:

Code of MultipleQuerySearchHandler:

Complete code of MultipleQueryComponent:

Handling HTTP 413 error status from Solr while executing multiple Solr queries.

When sending multiple queries in one request, Solr may return HTTP 413 status code.

Solr returns HTTP 413 status code when the client sends Solr queries in GET request and total number of characters are more than allowed.  The maximum number of characters allowed depends on server configuration Solr is running. Mostly all servers allow 1024 characters in GET request. To avoid HTTP 413 error, clients should send Solr queries using POST method when request payload contains more than 1024 characters.

 

Connecting to amazon server:

import org.apache.commons.io.IOUtils
import org.jets3t.service.impl.rest.httpclient.RestS3Service
def bucket = "s3-test"
def aws = ctx.aws

def credentials = aws.s3().on(bucket).credentialsHolder
def s3Service = new RestS3Service(credentials.buildJetS3tCredentials())

or 

String awsAccessKey = "YOUR_AWS_ACCESS_KEY";
String awsSecretKey = "YOUR_AWS_SECRET_KEY";
AWSCredentials awsCredentials = 
    new AWSCredentials(awsAccessKey, awsSecretKey);
S3Service s3Service = new RestS3Service(awsCredentials);

Creating a folder(bucket):

def testBucket = s3Service.createBucket("eu-bucket")

while try to create a folder in S3 we are facing the following error:

org.jets3t.service.S3ServiceException: S3 Error Message. -- ResponseCode: 403, ResponseStatus: Forbidden, XML Error Message: <?xml version="1.0" encoding="UTF-8"?><Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>EA9B7EAADF369597</RequestId><HostId>BaVq73YFG+zfCTBdEldKW7ooBOs33r6wXb+5rew33T99FdrYYd2WbNzhD6PKymGf4/Zn+WXqvg8=</HostId></Error>

for this we need to set the permissions on the above ACCESS_KEY

Upload a file:

File fileData = new File("/CodeSamples.java");
S3Object fileObject = new S3Object(fileData);
s3Service.putObject(testBucket, fileObject);

Copy S3 object from one place to other in the same S3 bucket:


        String bucketName = testBucket
        def credentials = aws.s3().on(bucketName).credentialsHolder
        def s3Service = new RestS3Service(credentials.buildJetS3tCredentials())
        s3Service.copyObject(bucketName, sourceObjectKey, bucketName, new          StorageObject(destinationObjectKey), true)

Deleting a file:

s3Service.deleteObject(testBucket, fileObject.getKey());

Canonical URL: the search engine friendly URL that you want the search engines to treat as authoritative.  In other words, a canonical URL is the URL that you want visitors to see.

The standard way of creating URLs in grails:

<a href="${createLink(controller:'news', action: 'show', params: [id: news.id])}">${news.title}</a>

which generates the url: /news/show/$id

If you want to this in canonical form like
/news/$id/nbos-canonical-url

You could turn the 'nbos-canonical-url' into a parameter like this:
name story: "/news/$id/$headline" {
 controller = "news"
 action = "show"
}
(In UrlMappings.groovy)

<a href="${createLink(mapping: "story", params: [id: 102, headline: 'nbos-canonical-url'])}">${news.title</a>