Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 

In this post, we are going to explore how to implement Single Sign-on authentication in a Grails app hosted on HANA Cloud Platform.

Assuming that you have Grails installed already, start by creating your project:


$ grails create-app HANACloudGrailsSSO
$ cd HANACloudGrailsSSO



Then you'll get a directory structure such as this:


application.properties
grails-app
lib
scripts
src
test
web-app



next, we need to provide our own version of MANIFEST.MF instead of the one generated by Grails because it is causing errors when deployed over the HANA Cloud Platform.

Create a file MANIFEST.MF inside web-app/META-INF

MANIFEST.MF


Manifest-Version: 1.0





and then we need to define our .war creation hook in _Events.groovy and put it inside scripts folder.


includeTargets << grailsScript("_GrailsInit")
eventCreateWarStart = { warName, stagingDir ->
    ant.copy(todir: "$stagingDir/META-INF", file: "web-app/META-INF/MANIFEST.MF", overwrite: true)
}
eventWebXmlEnd = { String filename ->
      def webxml = webXmlFile
      def newxml = new File(webxml.path + ".bak")
      def root = new XmlParser().parse(webxml)
      // add the jdbc/mydatasource resource reference to the web.xml
      def resourceRef = root.appendNode('resource-ref')
      resourceRef.appendNode('description','The SAP NetWeaver JNDI Database resource')
      resourceRef.appendNode('res-ref-name','jdbc/DefaultDB')
      resourceRef.appendNode('res-type','javax.sql.DataSource')
          def loginConfig = root.appendNode('login-config')
          loginConfig.appendNode('auth-method','CLIENT-CERT')
          def securityConstraint = root.appendNode('security-constraint')
          def webResourceCollection = securityConstraint.appendNode('web-resource-collection')  
          webResourceCollection.appendNode('web-resource-name','Protected Area')
          webResourceCollection.appendNode('url-pattern','/*')
          def authConstraint = securityConstraint.appendNode('auth-constraint')
          authConstraint.appendNode('role-name', 'Everyone')
      def writer = new StringWriter()
      new XmlNodePrinter(new PrintWriter(writer)).print(root)
      newxml.withWriter { out ->
          out.writeLine(writer.toString())
      }
      webxml.delete()
      newxml.renameTo(webxml.path)
}





So there are two events that we are overriding here: When the creation of war file starts and when the creation of web.xml ends.

When the creation of war file starts, we need to supply our own MANIFEST.MF instead of the one generated by grails so we'll do it here here using ant's copy command. Next, when grails is done generating web.xml, we need to inject three nodes, resource-ref, login-config and security-config. resource-ref defines the datasource that we need to use. login-config defines the type of authentication method to use when someone tries to access a protected resource defined by the security-config's url-pattern. Lastly, we'll delete the old web.xml and write a new one with the same filename.

Next, update the datasource to point to the correct JNDI name we've defined in our web.xml.

/conf/DataSource.groovy


production {
        dataSource {
             dbCreate = "update"
             jndiName = "java:comp/env/jdbc/DefaultDB"
             dialect = "org.hibernate.dialect.SAPDBDialect"
        }
    }




Next, we need to have access to User Management API during compile time so we need to install two jars files from HANA Cloud SDK installation directory using grails install-dependency command.


$ grails install-dependency neo:neo-sdk-core-api:1.40.26.2 --dir /Applications/Dev/neo-sdk-javaweb-1.40.26.2/api/
$ grails install-dependency osgi:org.eclipse.osgi:3.7.2 --dir /Applications/Dev/neo-sdk-javaweb-1.40.26.2/api/




We can now add these dependencies to our grails-app/conf/BuildConfig.groovy.

/conf/BuildConfig.groovy


dependencies {
        // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g.
        provided 'neo:neo-sdk-core-api:1.40.26.2'
        provided 'osgi:org.eclipse.osgi:3.7.2'
    }




We need to specify provided because we only need these jar files during compile time but not necessarily needed to be packaged as part of the war file. This is because these are already available at runtime provided by HANA Cloud Platform.

We are now ready to create our protected resource. Let's create a controller/servlet:


$ grails create-controller com.sap.mic.SecuredController





and modify it so that it retrieves the currently authenticated user and displays the username.


package com.sap.mic
import com.sap.security.um.service.UserManagementAccessor;
import com.sap.security.um.user.User;
import com.sap.security.um.user.UserProvider;
class SecuredController {
    def index() {
        UserProvider userProvider = UserManagementAccessor.getUserProvider();
        User user = userProvider.getUser(request.getUserPrincipal().getName());
        render user.getAttribute("firstname")
    }
}



If you haven't installed the HCP local server, you can install and run it by executing:


$ neo.sh install-local
$ neo.sh start-local




After that, build the war file and deploy to your local HANA Cloud Platform local server.


$ grails war
$ cp target/HANACloudGrailsSSO-0.1.war /Applications/Dev/neo-sdk-javaweb-1.40.26.2/server/pickup

After a few minutes, your web application is now accessible from your browser. Open http://localhost:8080/HANACloudGrailsSSO-0.1/secured/ and you will see the default login screen provided by the HCP runtime.

You wouldn't be able to login here because there's no service that will handle the authentication so we need to provide a file that the local HCP server will look up. You can grab neousers.json from your HCP SDK installation under NEO_SDK/samples/authentication and copy it to NEO_SDK/server/config_master/com.sap.security.um.provider.neo.local/. Then you can now login using joe and doe as username and password respectively.

If you'd like to know more about configuring your Grails app to connect to MaxDB and UI5, head over to Using SAP UI5 and NW Cloud Persistence Service with Grails Scaffolding.

2 Comments