g:Grails 2.3.7和Spring security 2.0-RC2中的actionSubmit和Exception处理

时间:2014-05-01 21:34:36

标签: security grails spring-security

我正在运行Grails 2.3.7和Spring security 2.0-RC2。

我发现了与此主题相关的较旧帖子(2011)和JIRA报告 http://jira.grails.org/browse/GRAILS-7664

但是我不清楚它是否真的被修复了。我使用的表单有两个提交按钮(相当于g:actionSubmit)

<g:form style='margin: 0' controller="bankAccount">
 <g:hiddenField name="id" value="${organizationRegisteredInstance?.bankAccount?.id}" />
 <button type="submit" class="btn btn-xs btn-danger" name="_action_deleteMyBankAccount" >DELETE</button>
 <button type="submit" class="btn btn-xs btn-warning" name="_action_editMyBankAccount" >EDIT</button>
</g:form>

出于测试目的,我试图与没有所需角色的用户调用这些链接。(@在控制器bankAccount中安全)。

Spring安全日志确实显示了AccessDeniedExeption,但Grails没有重定向到为403设置的错误页面。

如果我使用直接GET链接执行完全相同的操作,我会得到预期的行为,并且Grails重定向到URLMapping文件中定义的错误页面:

<g:link class="btn btn-xs btn-warning" controller="bankAccount" action="editMyBankAccount" id="${organizationRegisteredInstance?.bankAccount?.id}">

日志:

DEBUG Request '/bankaccount/index' matched by universal pattern '/**' 
DEBUG /bankAccount/index at position 1 of 9 in additional filter chain; firing Filter:     'SecurityContextPersistenceFilter' 
DEBUG Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT:     'org.springframework.security.core.context.SecurityContextImpl@57de70d6: Authentication:     org.springframework.security.authentication.UsernamePasswordAuthenticationToken@57de70d6: Principal: idr.IdrUser@17a81: Username: ass; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_NOT_ASSIGNED,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER, ROLE_NOT_ASSIGNED' 
DEBUG /bankAccount/index at position 2 of 9 in additional filter chain; firing Filter: 'MutableLogoutFilter' 
DEBUG /bankAccount/index at position 3 of 9 in additional filter chain; firing Filter: 'RequestHolderAuthenticationFilter' 
DEBUG /bankAccount/index at position 4 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
DEBUG /bankAccount/index at position 5 of 9 in additional filter chain; firing Filter: 'GrailsRememberMeAuthenticationFilter' 
DEBUG /bankAccount/index at position 6 of 9 in additional filter chain; firing Filter: 'GrailsAnonymousAuthenticationFilter' 
DEBUG /bankAccount/index at position 7 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
DEBUG /bankAccount/index at position 8 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
DEBUG Secure object: FilterInvocation: URL: /bankAccount/index; Attributes: [ROLE_ORG] 
DEBUG Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@57de70d6: Principal: idr.IdrUser@17a81: Username: ass; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_NOT_ASSIGNED,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER, ROLE_NOT_ASSIGNED 
DEBUG getReachableGrantedAuthorities() - From the roles [ROLE_USER, ROLE_NOT_ASSIGNED] one can reach [ROLE_USER, ROLE_NOT_ASSIGNED] in zero or more steps. 
DEBUG Access is denied (user is not anonymous); delegating to AccessDeniedHandler 
org.springframework.security.access.AccessDeniedException: Access is denied 
        at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.deny(AuthenticatedVetoableDecisionManager.java:113) 
        at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.checkOtherVoters(AuthenticatedVetoableDecisionManager.java:105) 
        at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.decide(AuthenticatedVetoableDecisionManager.java:44) 
        at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53) 
        at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49) 
        at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
        at java.lang.Thread.run(Thread.java:744) 
DEBUG SecurityContextHolder now cleared, as request processing completed 
DEBUG Request '/grails-errorhandler' matched by universal pattern '/**' 
DEBUG /grails-errorhandler at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 
DEBUG Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@57de70d6: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@57de70d6: Principal: idr.IdrUser@17a81: Username: ass; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_NOT_ASSIGNED,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER, ROLE_NOT_ASSIGNED' 
DEBUG /grails-errorhandler at position 2 of 9 in additional filter chain; firing Filter: 'MutableLogoutFilter' 
DEBUG /grails-errorhandler at position 3 of 9 in additional filter chain; firing Filter: 'RequestHolderAuthenticationFilter' 
DEBUG /grails-errorhandler at position 4 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 
DEBUG /grails-errorhandler at position 5 of 9 in additional filter chain; firing Filter: 'GrailsRememberMeAuthenticationFilter' 
DEBUG /grails-errorhandler at position 6 of 9 in additional filter chain; firing Filter: 'GrailsAnonymousAuthenticationFilter' 
DEBUG /grails-errorhandler at position 7 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 
DEBUG /grails-errorhandler at position 8 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 
DEBUG /grails-errorhandler at position 9 of 9 in additional filter chain; firing Filter: 'SwitchUserFilter' 
DEBUG /grails-errorhandler reached end of additional filter chain; proceeding with original chain 
DEBUG Chain processed normally 
DEBUG SecurityContextHolder now cleared, as request processing completed

尽管在URLMapping中有以下设置:

"403"(controller: "login", action: "denied") 
"404"(controller: "home", action: "http404") 
"405"(controller: "home", action: "http405") 

我只是在Chrome和Firefox中获得一个空白页面,在IE中显示一个明确的HTTP 403。 看起来Grails只是忽略了错误处理(错误页面设置)。

编辑:添加控制器操作的代码:

@Secured(['ROLE_ORG'])
def editMyBankAccount(BankAccount bankAccountInstance) {
    log.debug "## bankAccount.editMyBankAccount ##"
    log.debug params
    def selectedRace
    // Used to redirect to MyRace page if ID is provided
    if (params?.race_id && params?.race_id!="") {
        selectedRace = idr.Race.get(params.race_id)
    }
    if (!bankAccountInstance) {
        notFound()
        return
    }
    def org = springSecurityService.getCurrentUser().organization
    // check if logged org is the same as the one having the bankAccount
    if (org && org.bankAccount &&  org.bankAccount==bankAccountInstance) {
        return [bankAccountInstance: bankAccountInstance, race_id: selectedRace?.id]
    } else {
        errorPage(message(code: 'organizationRegistered.mismatch.message', default:'TODO'))
        return
    }
}

和GSP代码:

<%@ page import="idr.BankAccount" %>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta name="layout" content="main" />
        <g:set var="entityName" value="${message(code: 'bankAccount.label', default:   'BankAccount')}" />
        <r:require modules="bootstrap"/>
        <title><g:message code="default.create.label" args="[entityName]" /></title>
    </head>
<content tag="topmenu">
<g:render template="/common/navMenuTop" model="[activeMenu:'myPrivateProfile_org']" />
</content>
    <body>
<div class="container">
    <div class="row">
        <div class="col-12">
            <legend><g:message code="organization.bankaccount.section" /> <i class="glyphicon glyphicon-pencil"></i></legend>
                <g:if test="${flash.message}">
                    <div class="alert alert-info">${flash.message}</div>
                </g:if>
                <g:hasErrors bean="${bankAccountInstance}">
                    <div class="alert alert-danger">
                        <g:renderErrors bean="${bankAccountInstance}" as="list" />
                    </div>
                </g:hasErrors>
        </div>
    </div>
        <g:form role="form" controller="bankAccount" action="update" name="accountForm">
            <fieldset>
                <g:hiddenField name="id" value="${bankAccountInstance?.id}" />
                <g:hiddenField name="version" value="${bankAccountInstance?.version}" />
                <g:render template="form"/>
                <div class="row">
                    <div class="col-lg-offset-2 col-md-offset-1 col-lg-4 col-md-4 col-sm-5">    
                        <div class="form-group">
                            <g:if test="${race_id && race_id!=""}">
                                <g:link class="btn btn-default" controller="race" action="myRace" id="${race_id}" >${message(code: 'default.button.cancel.label', default: 'Cancel')}</g:link>
                            </g:if>
                            <g:else>
                                <g:link class="btn btn-default" controller="organizationRegistered" action="myPrivateProfile" >${message(code: 'default.button.cancel.label', default: 'Cancel')}</g:link>
                            </g:else>
                            <button type="submit" class="btn btn-success">${message(code: 'default.button.update.label', default: 'Update')}</button>
                        </div>
                    </div>
                </div>
            </fieldset>
        </g:form>
</div> <!-- container -->
</body>

谢谢, 约翰

0 个答案:

没有答案