Showing posts with label grails. Show all posts
Showing posts with label grails. Show all posts

Tuesday, December 6, 2016

Handling One or Multiple Selection in Grails

Scenario:
We have a select in the form with id="book".
The user may choose none, 1 or multiple in select and submit the form.
There is an each loop in the controller/service to process each user.

What happen:
For each selected book in the select one book=N parameter is posted to the controller.

Grails controller which creates params automatically brings a little intelligence and convert the params to a list if there are multiple instances of that parameters, so in the case of multiple book selection the params will be something like this:

params.book = [ N, M, ...]
It is great and we can loop on it and do the operation on each of them.

But..., if just one user is selected, the there will be no list by default and the param contains just a simple string

params.book = "N"

The bad:

  • The loop is not failed, it is a string and loop iterate over each char of the string
  • In the development and simple test cases, it works perfectly. For example, if it is the id like 5, then it is just a char same as the original. But if the id grows and become something like "58", then your loop process object id 5 and 8.
Solution:
Use params.list method to create a list for that parameter, even if it is single.
def bookIds = params.list("book")

Thursday, October 13, 2016

Add Base URLs to Grails Page and Scripts

Sometimes we are note sure about final deployment context root address, so the root of the application can be something like mydomain.com/ or mydomain/myapp/ .

Grails or most of the other web app frameworks handle the link creation for such situation with some link facility in pages, but the problem is links in JavaScript, like base url for ajax call or resource loaders.

One possible solution is finding the base urls using the same facility of the framework and set them in global javascript variables.

The best location to add them and complying DRY is the layout page, where all pages have access.

The following is a sample for grails framework to have the url of the root of the app and the assets as well.


window.grails = {
    baseUrl: '${raw(g.createLink(absolute:true, uri:"/"))}'
    assetsUrl : '${ raw(asset.assetPath(src: '')) }',
};


It can be used like this:

$.ajax({
    type: 'GET',
    url: window.grails.baseUrl + 'controller/show/' + id +'.json',
    contentType: 'application/json',
    success: function( data, textStatus, jqXHR )
    {
    },
    error: function( jqXHR, textStatus, errorThrown )
    {
    }
});

Tuesday, July 12, 2016

Control Pagination of Restful Controller

Problem: The default index action (scaffolded) paginate the result, even for xml and json request *that may not be needed for many cases and the result doesn't indicate it is paginated)

Solution: Using withFormat (response not request) and indicating each format (including html) individually. Using '*' overwrite all formats and results in unexpected format.

params.max = Math.min(max ?: 10, 100)
withFormat {
    'html' {
        respond UnknownNode.list(params), model: [unknownNodeInstanceCount: UnknownNode.count()]
    }
    'json' { respond UnknownNode.list(), [status: CREATED] }
    'xml' { respond UnknownNode.list(), [status: CREATED] }
}

Saturday, June 11, 2016

Some Grails Tricks

Set log level in running instance by console

import org.apache.log4j.*
Logger.getLogger("mt.omid.rira.DataService").level = Level.DEBUG

Set grails environment in app server (using same war file for test/release), great for testing in JBoss

Environment variable grails.env can be set to proper environment like development or production.
or

CATALINA_OPTS=-Dgrails.env=development

In JBoss System properties part in Configuration section accept key/value pair that is used for the same purpose.

Grails (Hibernate) Batch Insert/Update

To prevent memory issue and increase the performance of batch insert or update it can be divided into the smaller bunch data, e.g. 1000 records, and flush and clear the transaction after saving each bunch.

def batch = []  // temp batch list
dataList.each { d ->
    d.value = 'blah blah blah'
    batch.add(d)
    if(batch.size() > 1000)
       runBatch(batch)
}


And the runBatch can be a piece of code like this:
        log.debug("Start Data batch saving")
        Data.withTransaction {
            for(Data d in batch){
                log.debug "Saving datum: ${d} ${d.isDirty('value')}"
                // d.save(flush: true) // not required to flush here, since session will flush before clear
                d.save()
            }
        }
        batch.clear()
        def session = sessionFactory.getCurrentSession()
        session.flush()
        session.clear()
        log.debug("Batch saving transaction & clearing hbn session finished")

The hibernate details can be found here.


Saturday, January 2, 2016

Calling Taglib Methods in Grails Console

Loading Taglib Class (e.g. here ApplicationTaglib ):

def g = ctx.getBean(org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib.class.getName())

Calling Taglib Method:

g.createLink(controller: 'invitation', action: 'accept', params:[id: 'adasdasdas'])
g.link(action: 'create')

Saturday, October 10, 2015

Grails-JavaScript Encrypted Communication - Part II

In previous post told about setting up grails environment to use bouncycastle lib. Now move to the page side and javascript. After searching around for having a comprehensive, well-documented and simple to use js lib for RSA and AES, I found pidCrypt interesting (because of the live demo page and simple instruction to use and mainly PEM support, that after going to implement, I found out that is not supported, but I copied the following function from demo page to use it).

function certParser(cert){
    var lines = cert.split('\n');
    var read = false;
    var b64 = false;
    var end = false;
    var flag = '';
    var retObj = {};
    retObj.info = '';
    retObj.salt = '';
    retObj.iv;
    retObj.b64 = '';
    retObj.aes = false;
    retObj.mode = '';
    retObj.bits = 0;
    for(var i=0; i< lines.length; i++){
        flag = lines[i].substr(0,9);
        if(i==1 && flag != 'Proc-Type' && flag.indexOf('M') == 0)//unencrypted cert?
            b64 = true;
        switch(flag){
            case '-----BEGI':
                read = true;
                break;
            case 'Proc-Type':
                if(read)
                    retObj.info = lines[i];
                break;
            case 'DEK-Info:':
                if(read){
                    var tmp = lines[i].split(',');
                    var dek = tmp[0].split(': ');
                    var aes = dek[1].split('-');
                    retObj.aes = (aes[0] == 'AES')?true:false;
                    retObj.mode = aes[2];
                    retObj.bits = parseInt(aes[1]);
                    retObj.salt = tmp[1].substr(0,16);
                    retObj.iv = tmp[1];
                }
                break;
            case '':
                if(read)
                    b64 = true;
                break;
            case '-----END ':
                if(read){
                    b64 = false;
                    read = false;
                }
                break;
            default:
                if(read && b64)
                    retObj.b64 += pidCryptUtil.stripLineFeeds(lines[i]);
        }
    }
    return retObj;
}

On server side, when I tried to decrypt the message I found 2 level bas64 encoding on the message. So first decode as base64 the hash and pass it to doFinal and again decode result as base 64 to have byte [] of the message, then convert to string.

Cipher decryptRSACipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC")
decryptRSACipher.init(Cipher.DECRYPT_MODE, privateKey)
new String(decryptRSACipher.doFinal(hash.decodeBase64()).decodeBase64(), StandardCharsets.UTF_8)

It supposed to be good thing for form submission from javascript side.

The next challenge was decrypting the actual data that encrypted by AES, but the decrypted key in previous by RSA didn't work, so after some research on source and net, another door of knowledge is opened to my eyes. As you may know, it is recommended to use a salt as part of AES key (password), that is fine, but in openssl implementation (that pidCrypt AES follow), the salt is send as part of prefix to the encrypted message (byte 8 to 16), and interesting thing is first 8 bytes are assigned for a "Salted__" string, yes a fixed string. So the message that supposed to be decrypted should be extracted according to the following format.

"Salted__" + 8 Bytes Random Salt + EncryptedMessage

I did some changes to this format to support one time password or expiring the key that will be explained in next post.

This link may describe openssl AES format better than me.

Sunday, October 4, 2015

Grails-JavaScript Encrypted Communication - Part I

For adding new feature to my framework RIRA I should have encrypted communication between client (page) and server(controller) for sensitive information and actions like username and password on login or setting new password. So the basic plan was having RSA (private/public key) encryption of form data in page by javascript and decrypt and use them in controller side.

On testing, troubleshooting and studying best practices for this purpose I found that RSA supposed to be used for encrypting short length data, something like a password or key and not the whole form data. So the best practice was encrypting data by AES with a random key, then encrypt that random key with RSA public, and do vice versa on server side.

For the server side I chose the bouncycastle java lib as provider since it is supporting PEM key reading (parsing), because I want to make it easy for the admin of the application to generate and change the key simply, by something like openssl command line in this case. Here is the method to read PEM file:

static KeyPair getKeyPair(String pk, char [] password) {
 PEMParser pemParser = new PEMParser(new CharArrayReader(pk.toCharArray()))
 Object object = pemParser.readObject()

 PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password)
 JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC")

 KeyPair kp
 if (object instanceof PEMEncryptedKeyPair) {
  kp = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv))
 } else {
  kp = converter.getKeyPair((org.bouncycastle.openssl.PEMKeyPair) object)
 }
 kp
}

For security the password must be passed and processed as char [] instead of String object, since String is seen as one object and may be accessed before garbage collection.

The first challenge appear here that PEMParser (Thhe deprecated and removed class was PEMReader) class that is used in most of examples was not resolvable and accessible that was because of existence of old version in global grails lib through some dependency to garils-doc and itext (The dependencies can be checked by grails dependency-report command). So first solution was to exclude the bouncycastle lib in BuildConfig.groovy of my plugin by something like the following code:

dependencies {
 compile("com.lowagie:itext:2.0.8") {
  excludes "bouncycastle:bcprov-jdk14:138", "org.bouncycastle:bcprov-jdk14:1.38"
 }
}

It was OK for compiling source code in plugin project but same error of not founding some classes repeated on application project that use the plugin. So I added same to build config of application and it resolved. So now I can encrypt and decrypt strings by RSA keys in grails side.

I added syntax highlighter to blog template for this post.

Tuesday, April 7, 2015

Get Relative Path of Application Context

def s = ctx.grailsLinkGenerator

s.contextPath

s.serverBaseURL


The service is in the following package :
org.codehaus.groovy.grails.web.mapping.LinkGenerator

Use Services in Grails Shell/Console

def svc = ctx.getBean('serviceName')

def svc = ctx.serviceName

Thursday, January 1, 2015

Manage Update/Remove of hasMany field

class ManagedTeam {
    String name
    static hasMany = [ users: ManagedUser ]
}

update method in controller:

//clear all users
managedTeamInstance.users = []
//add the selected ones back
params.users.each() {
    def ManagedUser user = ManagedUser.get( it )
    managedTeamInstance.users.add( user )
    log.debug( "in associateUser: added " + user )
};

//try to save the changes
if( !managedTeamInstance.save( flush: true ) )
{
    return error()
}
else{
    flash.message = "Successfully associated users"
}

Monday, July 7, 2014

Sending data_sm by jSMPP

String messageId = session.dataShortMessage( "",
                    TypeOfNumber.UNKNOWN,
                    NumberingPlanIndicator.UNKNOWN, "1234",
                    TypeOfNumber.UNKNOWN,
                    NumberingPlanIndicator.UNKNOWN, "099232322",
                    new ESMClass(),
                    new RegisteredDelivery( SMSCDeliveryReceipt.DEFAULT ),
                    new GeneralDataCoding( Alphabet.ALPHA_DEFAULT, MessageClass.CLASS1, false ),
                    new OptionalParameter.COctetString( (short)0x0424, "Message content and payload") );