Category: grails

[Grails] ConfigObject

A popular question about ConfigSlurper:

Hey guys, I had in a project the following:
String variable = grailsApplication.config.grails.property.name + grailsApplication.config.grails.anotherproperty.name

And was working for almost a year but suddenly it stop working and throwing an error regarding the ConfigObject doesn’t have a plus method, did something similar happened to anyone?
Did someone knows why it was working and suddenly stop working ?

It doesn’t work because one of ‘property.name’ or ‘anotherproperty.name’ is not set.

If some option is not set, then ConfigSlurper return instance of ConfigObject.
That’s a common mistake.
Good news is that empty ConfigObject can be casted to false by the Groovy Truth.
Thus, to avoid this kind of mistakes and get null instead of ConfigObject you can use Elvis operator write something like:

// return empty list if supportedLocales isn't set
grailsApplication.config.supportedLocales ?: []

// return null if defaultLocale isn't set
grailsApplication.config.defaultLocale ?: null

[Linkset] Защита от атаки подбора пароля (brute force attack)

Just few links about various implementations of password cracking with brute force.

Brute-force search (Полный перебор)

Password cracking (Взлом пароля)

Theory + C#
http://www.bryanrite.com/preventing-brute-force-attacks-on-your-web-login/

Ruby authlogic
https://github.com/binarylogic/authlogic/blob/master/test/session_test/brute_force_protection_test.rb?source=cc
Doc
http://rdoc.info/github/binarylogic/authlogic/Authlogic/Session/BruteForceProtection

Ruby flood control
https://github.com/nedski/flood/blob/master/test/flood_test.rb

Drupal Mitigating a brute force attack
https://groups.drupal.org/node/293943

Drupal 6 login_security
https://drupal.org/project/login_security

IMPROVEMENTS TO SECURITY IN DRUPAL 7
http://drupalscout.com/knowledge-base/improvements-security-drupal-7

What’s Drupal’s flooding system?
http://www.braahm.be/posts/playing-drupal%E2%80%99s-flooding-system

API
https://api.drupal.org/api/drupal/modules!user!user.module/function/user_login_final_validate/7
https://api.drupal.org/api/drupal/includes%21common.inc/function/flood_register_event/7

Drupal 8 test
http://drupalcontrib.org/api/drupal/drupal!core!modules!user!lib!Drupal!user!Tests!UserLoginTest.php/function/UserLoginTest%3A%3AtestPerUserLoginFloodControl/8

http://api.drupalize.me/api/drupal/function/UserLoginTestCase%3A%3AtestGlobalLoginFloodControl/7

FloodInterface
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Flood!FloodInterface.php/interface/FloodInterface/8

Test
https://api.drupal.org/api/drupal/core!modules!system!lib!Drupal!system!Tests!System!FloodTest.php/8

Grails
http://grails.org/plugin/bruteforce-defender

Human readable past date formating in Grails

Sometimes it better to write ‘2 days ago’ instad of ’28 Jan 2015′.
You can find a lot of solution in How to calculate “time ago” in Java?.

Here is a simplest snippet for making it in Grails from my project with i18n support.
Just create new tag `timeAgo` in your project taglib:

    static encodeAsForTags = [ timeAgo: [taglib:'html'] ]

    final static long ONE_SECOND = 1000;
    final static long ONE_MINUTE = ONE_SECOND * 60;
    final static long ONE_HOUR = ONE_MINUTE * 60;
    final static long ONE_DAY = ONE_HOUR * 24;

    /**
     Converts time (in milliseconds) to human-readable format
     "<w> days, <x> hours, <y> minutes ago" or "just now"
     <code>
     System.out.println(millisToLongDHMS(123));
     System.out.println(millisToLongDHMS((5 * ONE_SECOND) + 123));
     System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR));
     System.out.println(millisToLongDHMS(ONE_DAY + 2 * ONE_SECOND));
     System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR + (2 * ONE_MINUTE)));
     System.out.println(millisToLongDHMS((4 * ONE_DAY) + (3 * ONE_HOUR) + (2 * ONE_MINUTE) + ONE_SECOND));
     System.out.println(millisToLongDHMS(42 * ONE_DAY));
     </code>
     output :
     0 second
     5 seconds
     1 day, 1 hour
     1 day and 2 seconds
     1 day, 1 hour, 2 minutes
     4 days, 3 hours, 2 minutes
     42 days
     */
    private String millisToLongDHMS(long duration) {
        StringBuffer res = new StringBuffer();
        long temp;
        if (duration >= ONE_MINUTE) {
            temp = duration / ONE_DAY;
            if (temp > 0) {
                duration -= temp * ONE_DAY;
                res.append(temp).append(' ').append(temp > 1 ? g.message(code: 'timeAgo.days') : g.message(code: 'timeAgo.day')).append(duration >= ONE_MINUTE ? ', ' : '')
            }
            temp = duration / ONE_HOUR;
            if (temp > 0) {
                duration -= temp * ONE_HOUR;
                res.append(temp).append(' ').append(temp > 1 ? g.message(code: 'timeAgo.hours') : g.message(code: 'timeAgo.hour')).append(duration >= ONE_MINUTE ? ', ' : '')
            }
            temp = duration / ONE_MINUTE
            if (temp > 0) {
                res.append(temp).append(' ').append(temp > 1 ? g.message(code: 'timeAgo.minutes') : g.message(code: 'timeAgo.minute'))
            }
            res.append(' ').append(g.message(code: 'timeAgo.ago'))
            return res.toString()
        } else {
            return g.message(code: 'timeAgo.justNow')
        }
    }

    /**
     * @emptyTag
     *
     * @attr date the date in past
     */
    def timeAgo = { attrs ->
        Date date = attrs.date
        out << millisToLongDHMS((new Date().getTime()) - date.getTime());
    }

And then you need to add message codes in `messages.properties`:

timeAgo.justNow=just now
timeAgo.minute=minute
timeAgo.minutes=minutes
timeAgo.hour=hour
timeAgo.hours=hours
timeAgo.day=day
timeAgo.days=days
timeAgo.ago=ago
# for Russian
timeAgo.justNow=только что
timeAgo.minute=минуту
timeAgo.minutes=минут
timeAgo.hour=час
timeAgo.hours=часов
timeAgo.day=день
timeAgo.days=дней
timeAgo.ago=назад
# for Ukrainian
timeAgo.justNow=тіки що
timeAgo.minute=хвилину
timeAgo.minutes=хвилин
timeAgo.hour=годину
timeAgo.hours=годин
timeAgo.day=день
timeAgo.days=днів
timeAgo.ago=тому

Avatars in Grails with Gravatar

On every site we often need ability to show user avatars. The simplest way is to use external serive Gravatar.com.

There exists even a plugin for Grails but you don’t need it.
You can use gravatars in gsp files like this:

<img src="https://www.gravatar.com/avatar/${user.email.encodeAsMD5()}"/>

That’s all. But if you want you can create a tag in taglib:

class TagLib {
    static encodeAsForTags = [ gravatar: [taglib: 'none'] ]

    /**
     * Render img tag with user avatar from Gravatar.com
     * @emptyTag
     *
     * @attr user User
     */
    def gravatar = { attrs ->
        User user = attrs.user
        assert user
        out << "<img src='https://www.gravatar.com/avatar/${user.email.encodeAsMD5()}'/>"
    }
}

[HOWTO] WYSIWYG with Grails + CKEditor + Spring Security

Add last version of Grails CKEditor plugin to BuildConfig.groovy

grails.project.dependency.resolution = {
...
    plugins {
        ...
        compile ":ckeditor:4.4.1.0"
    }
}

Plugin version corresponding to bundled CKEditor version, and may be outdated.
To update it, and you use assets pipeline plugin, download CKEditor and unpack to grails-app/assets/ckeditor.
Then you should add dependency to application.js like this

//= require jquery-1.11.1.min
//= require jquery-ui.min
//= require_tree plugins
//= require_tree globalize
//= require bootstrap
//= require ../ckeditor/ckeditor
//= require_self

If CKEditor version is good enough for you, just put ckeditor:resources tag into head of view:

<html>
<head>
    <title>Example</title>
    <ckeditor:resources/>
</head>

Then you can insert CKEditor in form with tag ckeditor:editor. For example editor of article content:

<ckeditor:editor name="content" height="400px" width="80%" userSpace="${currentUser.id}">${article.content}</ckeditor:editor>

Here used attribute userSpace with value of current user's id. It makes all user images upload to server separated to their own folders.

But you should also restrict access to users spaces. If you use Spring Security (S2) plugin you can create custom filter with command grails create-filters OfmSecurity:

class OfmSecurityFilters {
 def springSecurityService
 def filters = {
 all(uri: '/ck/ofm/**') {
 before = {
 if (springSecurityService.currentUser?.id != params.space?.toLong()) {
 redirect(controller: "user", action: "login")
 return false
 }

 }
 after = { Map model ->

 }
 afterView = { Exception e ->

 }
 }
 }
}

Working with cookies in Grails

I’m become a maintainer of Cookie Plugin for Grails.
And today happy to make it first production release.

To install it add compile ":cookie:1.0.1" dependency to BuildConfig.groovy.

Then you can use it via CookieService:

// This sets a cookie with the name `username` to the value `admin` with a expiration set to a week, defined in seconds
cookieService.setCookie('username', 'admin', 7 * 24 * 60)
// Or you can use named parameters:

cookieService.setCookie([
    name: 'username', // Cookie name. Can't be blank or null and is case-sensitive
    value: 'admin', // Cookie value.
    maxAge: 30 * 60, // Age to store cookie in seconds; if negative, means the cookie is not stored; if zero, deletes the cookie.
    path: '/admin/', // A path to which the client should return the cookie. The cookie is visible to all the pages in the directory
    domain: '.example.com', // It begins with a dot (.example.com) and means that the cookie is visible to servers in a specified DNS zone
    secure: true, // Indicates to the browser whether the cookie should only be sent using a secure protocol, such as HTTPS or SSL.
    httpOnly: true // "HTTP Only" cookies are not supposed to be exposed to client-side JavaScript code, and may therefore help mitigate XSS attack.
])  

// To get the cookie value
cookieService.getCookie('username') // returns 'admin'

cookieService.deleteCookie('username', '/admin/')

I will be thankful for any feedback and bug reports
Cookie Plugin on Grails.org

[Grails] Ещё пару GORM gotchas

Короткая заметка-черновик где хочу зафиксировать некоторые подводные камни с ипользованием GORM. Чуть позже докидаю примеров кода.
Это продолжение заметок:

И напоследок, обязательно изучите руководство по GORM’у чтобы не плодить проблем. Именно запросы в БД чаще всего являются узким местом в вашем приложении из-за которого проседает производтельность.
К сожалению в GORM очень много ловушек многих из которых избежать вам помогут три статьи евангелиста Grails Питера Ледбрука (Peter Ledbrook):

  1. GORM GOTCHAS (PART 1) Перевод на русский
  2. GORM GOTCHAS (PART 2) Перевод на русский
  3. GORM GOTCHAS (PART 3) (перевода на русский нет)

Advanced GORM — Performance, Customization and Monitoring

Implementing Burt Beckwith’s GORM Performance – No Collections

1. Всегда указывайте максимальный размер строковых полей

Если вы явно не указали максимальный размер строкового поля то GORM создаст таблицу с полем VARCHAR(255):

class Book {
  String title
}

grails schema-export:

create table book (
  id bigint generated by default as identity, 
  version bigint not null,
  title varchar(255) not null,
  primary key (id)
);

Наверное каждая база данных поддерживает VARCHAR до 255 символов, как этого требует стандарт ANSI SQL.
Проблема возникает при валидации объекта: поскольку максимальный размер поля не указан, то Grails его и не валидирует, пропуская объект дальше пока он не вызовет исключение при сохранении в БД. И то, я не проверял, но например MySQL может молча обрезать значение поля если не включен строгий режим. Хотя может на уровне Hibernate это и не допустится, я не в курсе.
Поэтому указывайте явно максимальный размер поля в секции constraints:

class Book {
    String title
    static constraints = {
        title maxSize: 255
    }
}

Кстати если вам требуется больше 255 символов, то вам следует использовать мапинг на текстовый блоб (CLOB):

class Book {
    String title
    static mapping = {
        title type: 'text'
    }
}

Правда вы теряете при этом возможность строить индексы по этому полю.
Но и в этом случае нужно указывать максимальный размер строки для валидации.

Проверка уникальности происходит только при сохранении

Ещё одна похожая ошибка. Так же как и размер строки, уникальные поля проверяются только момент сохранения, так что вы можете получить исключения уровня БД вместо ошибки на этапе валидации.

Лучше явно прописывайте Long id

Ключевое поле id создаётся динамически, то наверное лучше всё таки прописать его явно

class Book {
    Long id
    String title
}

Во первых, просто так становится меньше неявных мест. Ведь у вас могут быть другие доменные объекты у который ключ составной а поля id нет вовсе.
Это точно придётся сделать если вы захотите использовать это поле в выводе метода toString() или equals. А ведь бывают такие доменные объекты которые можно проверить на равенство только по id.

Лучше явно указывать тип полей hasMany

Тут ситуация схожая с явным id — иногда лучше избегать невного поведения.
По умолчанию поля генерируемые через hasMany имеют тип Set (PersistentSet).
Т.е. вам не гарантируется порядок например и каждый раз при вставке записи будут выгружены все объекты из ассоциации чтобы проверить на уникальность.
Если вы укажите тип в List то хибернейт тоже выгребет все записи, потому что он вынужден будет сохранить порядок. Поэтому самый лёгкий вариант указывать просто как Collection.
Это фича хибернейта как такового.
Так что лучше явно указать тип который вы желаете, чтобы хотя бы знать отчего проседает скорость:

class Book {
    Long id
    String title
    Set<Author> authors
    static hasMany = [authors: Author]
}