Search code examples
grailsspring-security

How to customize spring security plugin Login page in grails


I've tried without success to customize the login page in spring security core 3.1.1. I created a login directory in the views directory and an auth.gsp in the login directory and put my custom form there. Here is the code:

<g:form name="form-login" method="POST" action="${resource('file': 'j_spring_security_check')}">
     <label for="j_username">Username:</label>
      <g:textField name="j_username"/>
                <label for="j_password">Password:</label>
                <g:passwordField name="j_password"/>
            <g:submitButton name="login" value="Log in" />
    </g:form>

It takes the username and password alright but upon clicking the login button, it still shows the form. Any solutions.


Solution

  • That's an old form using the old action address (the core problem that's causing the redirect) and old names for username/password (the lurking problem that would have been more frustrating because it will always fail with correct values, since they're not usable if they're set for the wrong parameter names).

    It's not as simple in 3.x as it was in 2.x to override plugin files. In 2.x plugins are zip files unpacked in your project root's target directory, and you can do valid and/or crazy things with plugin source. In 3.x the plugins are compiled jars, so hopefully we reduced the total amount of crazy, but we also have made it harder to do valid things like this.

    But this is open source software, and the exact .gsp file or one that's close enough is very easy to find in the source repo, which is here.

    auth.gsp changes rarely so it's fine to get the latest file from the master branch, or you could look through the history (recentl builds are and future builds will continue to be tagged) so it would be easy to get an older version, e.g. from version 3.0.4.

    That's not neccessarily the final answer though because the plugin is very configurable, and you can override several variables used in the GSP in the config, so you should replace code that looks up values with just the values since your app is unlikely to benefit from that flexibility. The defaults for config settings are in DefaultSecurityConfig.groovy, but I left this GSPs inside the lookup code, so you just need to remove that and retain the values.

    Here's the inner form element (you need the whole file but I'm not showing the parts that don't need changes):

    <form action="${postUrl ?: '/login/authenticate'}" method="POST" id="loginForm" class="cssform" autocomplete="off">
        <p>
            <label for="username"><g:message code='springSecurity.login.username.label'/>:</label>
            <input type="text" class="text_" name="${usernameParameter ?: 'username'}" id="username"/>
        </p>
    
        <p>
            <label for="password"><g:message code='springSecurity.login.password.label'/>:</label>
            <input type="password" class="text_" name="${passwordParameter ?: 'password'}" id="password"/>
        </p>
    
        <p id="remember_me_holder">
            <input type="checkbox" class="chk" name="${rememberMeParameter ?: 'remember-me'}" id="remember_me" <g:if test='${hasCookie}'>checked="checked"</g:if>/>
            <label for="remember_me"><g:message code='springSecurity.login.remember.me.label'/></label>
        </p>
    
        <p>
            <input type="submit" id="submit" value="${message(code: 'springSecurity.login.button')}"/>
        </p>
    </form>
    

    and for the initial pass you would want to change it to this:

    <form action="/login/authenticate' method="POST" id="loginForm" class="cssform" autocomplete="off">
        <p>
            <label for="username"><g:message code='springSecurity.login.username.label'/>:</label>
            <input type="text" class="text_" name="username" id="username"/>
        </p>
    
        <p>
            <label for="password"><g:message code='springSecurity.login.password.label'/>:</label>
            <input type="password" class="text_" name="password" id="password"/>
        </p>
    
        <p id="remember_me_holder">
            <input type="checkbox" class="chk" name="remember-me" id="remember_me"/>
            <label for="remember_me"><g:message code='springSecurity.login.remember.me.label'/></label>
        </p>
    
        <p>
            <input type="submit" id="submit" value="${message(code: 'springSecurity.login.button')}"/>
        </p>
    </form>
    

    You can use whatever post url and username/password param names you want including the old ones, but you need to set the config properties so the Spring Security filter that processes logins is looking at the correct uri and is expecting the param names that you're sending. If you're ok with the defaults then this will work, and you can of course make whatever regular HTML and CSS/JS changes you want.