Search code examples
grailsintellij-ideaspring-securitygenerated-code

Grails, spring security - login controller's imports not working


I started a new Grails (2.4.4) project in intellij and added compile ":spring-security-core:2.0.0" to install spring security - this worked fine. I then ran s2-quickstart io.mylife.feedmyface User Role to generate domain classes User, Role and UserRole - this also worked fine, I even successfully bootstrapped in a couple of roles and users. Next I copied over the login & logout controllers as well as the login views from target/work/plugins/spring-security-core-2.0.0/grails-app/controllers/grails/plugin/springsecurity and target/work/plugins/spring-security-core-2.0.0/grails-app/views/login respectively. This is where the problem comes in. Many of the imports as well as other keywords are marked red by intellij, giving the pop-up cannot resolve symbol 'Secured', for instance. In the views I get a couple of similar errors, e.g. <div class='errors'><g:message code="springSecurity.denied.message" /></div>, the springSecurity.denied.message will be marked red with the pop-up cannot resolve property key. I'm less worried about the views though coz I have noticed in the past that generated code does that sometimes without causing any real trouble. I would just like to find out how to fix the controllers. Just to cover my bases I'll mention that I am using Postgresql db, but I doubt that makes a difference? Please let me know if I need to supply more info. Here's the contollers' code:

LoginController:

/* Copyright 2013-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.mylife.feedmyface

import grails.converters.JSON

import javax.servlet.http.HttpServletResponse

/* 'security is red on all of the below imports'*/
import org.springframework.security.access.annotation.Secured
import org.springframework.security.authentication.AccountExpiredException
import org.springframework.security.authentication.CredentialsExpiredException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.web.WebAttributes

@Secured('permitAll')  // 'Secured' is red
class LoginController {

/**
 * Dependency injection for the authenticationTrustResolver.
 */
def authenticationTrustResolver

/**
 * Dependency injection for the springSecurityService.
 */
def springSecurityService

/**
 * Default action; redirects to 'defaultTargetUrl' if logged in, /login/auth otherwise.
 */
def index() {
    if (springSecurityService.isLoggedIn()) {
        redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl
    }
    else {
        redirect action: 'auth', params: params
    }
}

/**
 * Show the login page.
 */
def auth() {

    def config = SpringSecurityUtils.securityConfig

    if (springSecurityService.isLoggedIn()) {
        redirect uri: config.successHandler.defaultTargetUrl
        return
    }

    String view = 'auth'
    String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}"
    render view: view, model: [postUrl: postUrl,
                               rememberMeParameter: config.rememberMe.parameter]
}

/**
 * The redirect action for Ajax requests.
 */
def authAjax() {
    response.setHeader 'Location', SpringSecurityUtils.securityConfig.auth.ajaxLoginFormUrl
    response.sendError HttpServletResponse.SC_UNAUTHORIZED
}

/**
 * Show denied page.
 */
def denied() {
    if (springSecurityService.isLoggedIn() &&
            authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) {
        // have cookie but the page is guarded with IS_AUTHENTICATED_FULLY
        redirect action: 'full', params: params
    }
}

/**
 * Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page.
 */
def full() {
    def config = SpringSecurityUtils.securityConfig
    render view: 'auth', params: params,
        model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication),
                postUrl: "${request.contextPath}${config.apf.filterProcessesUrl}"]
}

/**
 * Callback after a failed login. Redirects to the auth page with a warning message.
 */
def authfail() {

    String msg = ''
    def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
    if (exception) {
        if (exception instanceof AccountExpiredException) {  // 'AccountExpiredException' is red
            msg = g.message(code: "springSecurity.errors.login.expired")
        }
        else if (exception instanceof CredentialsExpiredException) {  // 'CredentialsExpiredException' is red
            msg = g.message(code: "springSecurity.errors.login.passwordExpired")
        }
        else if (exception instanceof DisabledException) {  // 'DisabledException' is red
            msg = g.message(code: "springSecurity.errors.login.disabled")
        }
        else if (exception instanceof LockedException) {  // 'LockedException' is red
            msg = g.message(code: "springSecurity.errors.login.locked")
        }
        else {
            msg = g.message(code: "springSecurity.errors.login.fail")
        }
    }

    if (springSecurityService.isAjax(request)) {
        render([error: msg] as JSON)
    }
    else {
        flash.message = msg
        redirect action: 'auth', params: params
    }
}

/**
 * The Ajax success redirect url.
 */
def ajaxSuccess() {
    render([success: true, username: springSecurityService.authentication.name] as JSON)
}

/**
 * The Ajax denied redirect url.
 */
def ajaxDenied() {
    render([error: 'access denied'] as JSON)
}
}

LogoutController:

/* Copyright 2013-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.mylife.feedmyface

import javax.servlet.http.HttpServletResponse

/* Again, 'security' is red */
import org.springframework.security.access.annotation.Secured
import org.springframework.security.web.RedirectStrategy

@Secured('permitAll')  // 'Secured' is red
class LogoutController {

/** Dependency injection for RedirectStrategy. */
RedirectStrategy redirectStrategy  // 'RedirectStrategy' is red

/**
 * Index action. Redirects to the Spring security logout uri.
 */
def index() {

    if (!request.post && SpringSecurityUtils.getSecurityConfig().logout.postOnly) {
        response.sendError HttpServletResponse.SC_METHOD_NOT_ALLOWED // 405
        return
    }

    // TODO put any pre-logout code here
    redirectStrategy.sendRedirect request, response, SpringSecurityUtils.securityConfig.logout.filterProcessesUrl // '/j_spring_security_logout'
    response.flushBuffer()
}
}

Solution

  • It's not necessary to copy the login and logout controllers. After creating the sample users and roles in bootstrap.groovy, you just have to configure the permissions to your custom controllers either using @secure annotation or request mapping in config.groovy. for more info you can follow this tutorial in the plugins documentation.