Results 1 to 10 of 10

Thread: How are Grails applications loaded/bootstrapped?

Hybrid View

  1. #1

    Question Struggling with how Grails applications are loaded/bootstrapped

    I'm struggling with configuring Spring Security CAS for Grails; I believe the cause of my troubles is (my lack of understanding of) how Grails applications are bootstrapped/loaded. I tried two different methods of configuring Spring Security CAS, both failed at run time; I've described both approaches below. I'd appreciate help in understanding why I'm getting the following errors respectively.

    First approach: Placed the security configurations in "resources.xml", but that led to the following error (see full debug log):
    org.springframework.beans.factory.NoSuchBeanDefini tionException: No bean named 'springSecurityFilterChain' is defined
    Second approach: Placed the security configurations in "applicationContext-security.xml" and loaded it as context-param in web.xml, but that led to the following error:
    context.GrailsContextLoader Error executing bootstraps: Unexpected exception parsing XML document from file /data/workspace/facility/trunk/facility-web/./web-app/WEB-INF/classes/spring/applicationContext-security.xml]; nested exception is java.lang.IllegalStateException: AuthenticationManager has already been registered!
    Thanks!
    Last edited by dan0; Aug 6th, 2010 at 01:58 PM.

  2. #2
    Join Date
    Jul 2007
    Posts
    121

    Default

    You don't want to touch applicationContext-security.xml - that's the parent context; your beans should go in resources.xml or resources.groovy. It's impossible to know what's wrong without seeing your web.xml additions and what you're adding to resources.xml.

    It'd be a lot easier to just use the Spring Security Core and CAS plugins though. They should be customizable for whatever configuration you need.

  3. #3

    Question

    Quote Originally Posted by burtbeckwith View Post
    You don't want to touch applicationContext-security.xml - that's the parent context; your beans should go in resources.xml or resources.groovy. It's impossible to know what's wrong without seeing your web.xml additions and what you're adding to resources.xml.
    Below is the web.xml file. Most of the configurations are defaults; I added: Spring Security Filter, Spring Security Filter Mapping and Spring Security concurrent session management listener.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4"
             xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <display-name>/@grails.project.key@</display-name>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
    
        <context-param>
            <param-name>webAppRootKey</param-name>
            <param-value>@grails.project.key@</param-value>
        </context-param>
        
        <!-- Spring Security Filter -->
        <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
    
        <filter>
            <filter-name>sitemesh</filter-name>
            <filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
        </filter>
    
        <filter>
            <filter-name>charEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <param-name>targetBeanName</param-name>
                <param-value>characterEncodingFilter</param-value>
            </init-param>
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        
        <!-- Spring Security Filter Mapping -->
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <filter-mapping>
            <filter-name>charEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <filter-mapping>
            <filter-name>sitemesh</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <!-- Spring Security concurrent session management listener -->
        <listener>
      	    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
        </listener>
    
        <listener>
            <listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
        </listener>
    
        <listener>
            <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
        </listener>
    
        <!-- Grails dispatcher servlet -->
        <servlet>
            <servlet-name>grails</servlet-name>
            <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!-- The Groovy Server Pages servlet -->
        <servlet>
            <servlet-name>gsp</servlet-name>
            <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>gsp</servlet-name>
            <url-pattern>*.gsp</url-pattern>
        </servlet-mapping>
    
        <welcome-file-list>
            <!--
            The order of the welcome pages is important.  JBoss deployment will
            break if index.gsp is first in the list.
            -->
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>index.gsp</welcome-file>
        </welcome-file-list>
    
        <jsp-config>
            <taglib>
                <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
                <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
            </taglib>
            <taglib>
                <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
                <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
            </taglib>
            <taglib>
                <taglib-uri>http://www.springframework.org/tags</taglib-uri>
                <taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
            </taglib>
            <taglib>
                <taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
                <taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
            </taglib>
        </jsp-config>
    
    </web-app>
    Below is the resources.xml file. I have custom implementations of UserDetails & UserDetailsService (i.e. FacilityUserDetailsService, it is loaded via component scanning).
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:sec="http://www.springframework.org/schema/security"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">
     
        <context:annotation-config/>
        <context:component-scan base-package="com.facility.web.security"/>
        
        <bean id="casTicketValidator" class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
            <constructor-arg index="0" value="http://localhost:8080/facility-cas"/>
        </bean>
        
        <bean id="casService" class="org.springframework.security.cas.ServiceProperties">
            <property name="service" value="http://localhost:9999/facility-web/sign-in"/>
            <property name="sendRenew" value="false"/>
        </bean>
        
        <bean id="casAuthEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
            <property name="loginUrl" value="http://localhost:8080/facility-cas/login"/>
            <property name="serviceProperties" ref="casService"/>
        </bean>
        
        <bean id="authenticationUserDetailsService" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper" depends-on="facilityUserDetailsService">
            <constructor-arg ref="facilityUserDetailsService"/>
        </bean>
        
        <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
            <property name="ticketValidator" ref="casTicketValidator"/>
            <property name="serviceProperties" ref="casService"/>
            <property name="key" value="facility-cas"/>
            <property name="authenticationUserDetailsService" ref="facilityUserDetailsService"/>
        </bean>
        
        <sec:authentication-manager alias="authenticationManager">
            <sec:authentication-provider ref="casAuthenticationProvider"/>
        </sec:authentication-manager>
        
        <bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
            <property name="authenticationManager" ref="authenticationManager"/>
            <property name="filterProcessesUrl" value="/facility-web/sign-in"/>
        </bean>
        
        <sec:http auto-config="true" entry-point-ref="casAuthEntryPoint">
            <sec:custom-filter ref="casAuthenticationFilter" position="CAS_FILTER"/>
            <sec:intercept-url pattern="/register" filters="none"/>
            <sec:intercept-url pattern="/**" access="ROLE_USER, ROLE_SUPER_USER, ROLE_ADMIN"/>
        </sec:http> 
           
        <bean id="webClient" class="org.apache.cxf.jaxrs.client.WebClient" factory-method="create">
            <constructor-arg type="java.lang.String" value="http://localhost:8080"/>
        </bean>
    
        <bean id="validatorFactory" class="javax.validation.Validation" factory-method="buildDefaultValidatorFactory"/>
        
        <bean id="validator" factory-bean="validatorFactory" factory-method="getValidator"/>
        
    </beans>
    Quote Originally Posted by burtbeckwith View Post
    It'd be a lot easier to just use the Spring Security Core and CAS plugins though. They should be customizable for whatever configuration you need.
    Can I use the Spring Security Core plugin with my custom java implementations of UserDetails and UserDetailsService? If yes, would I still need to create user and role classes via:
    Code:
    grails s2-quickstart com.myapp User Roles
    While I plan on using the plugins, I'm still interested in learning what I was doing wrong in my previous (two) approaches, so if you can discern the cause of my problems kindly share. Thanks.
    Last edited by dan0; Aug 10th, 2010 at 08:09 PM.

  4. #4
    Join Date
    Jun 2010
    Location
    London
    Posts
    304

    Default

    Not sure about the second problem. It looks like double-loading of Spring beans, perhaps due to a cached copy of the old applicationContext.xml.

    Your first problem simply seems to be that the springSecurityFilterChain bean isn't defined anywhere. I don't see it in resources.xml. How is it supposed to be defined?

  5. #5

    Default

    Quote Originally Posted by pledbrook View Post
    Your first problem simply seems to be that the springSecurityFilterChain bean isn't defined anywhere. I don't see it in resources.xml. How is it supposed to be defined?
    I'm relying on the security namespace to create the 'springSecurityFilterChain' bean:

    Code:
    <sec:http auto-config="true" entry-point-ref="casAuthEntryPoint">
            <sec:custom-filter ref="casAuthenticationFilter" position="CAS_FILTER"/>
            <sec:intercept-url pattern="/register" filters="none"/>
            <sec:intercept-url pattern="/**" access="ROLE_USER, ROLE_SUPER_USER, ROLE_ADMIN"/>
    </sec:http>

  6. #6
    Join Date
    Jul 2007
    Posts
    121

    Default

    Sorry, you were right about creating an applicationContext-security.xml. I misread that (even though I copy/pasted it ...) as applicationContext.xml which you shouldn't edit. But the only way I could get this to work was to refer to a second app context xml file from web.xml in the contextConfigLocation attribute. I put it in WEB-INF along with applicationContext.xml:

    Code:
    <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>
          /WEB-INF/applicationContext.xml
          /WEB-INF/applicationContext-security.xml
       </param-value>
    </context-param>
    I was also missing the config jar so I added that to the Ivy config in BuildConfig.groovy (you could also just copy the jars to the lib dir):

    Code:
    grails.project.class.dir = 'target/classes'
    grails.project.test.class.dir = 'target/test-classes'
    grails.project.test.reports.dir = 'target/test-reports'
    
    grails.project.dependency.resolution = {
    
       inherits 'global'
       log 'warn'
    
       repositories {
          grailsPlugins()
          grailsHome()
          grailsCentral()
          ebr() // SpringSource  http://www.springsource.com/repository
       }
    
       dependencies {
          runtime('org.springframework.security:org.springframework.security.core:3.0.3.RELEASE') {
             excludes 'com.springsource.org.aopalliance',
                      'com.springsource.org.apache.commons.logging',
                      'org.springframework.beans',
                      'org.springframework.context',
                      'org.springframework.core'
          }
    
          runtime('org.springframework.security:org.springframework.security.config:3.0.3.RELEASE')
    
          runtime('org.springframework.security:org.springframework.security.web:3.0.3.RELEASE') {
             excludes 'com.springsource.javax.servlet',
                      'com.springsource.org.aopalliance',
                      'com.springsource.org.apache.commons.logging',
                      'org.springframework.aop',
                      'org.springframework.beans',
                      'org.springframework.context',
                      'org.springframework.core',
                      'org.springframework.web'
          }
    
          runtime('org.springframework.security:org.springframework.security.cas:3.0.3.RELEASE') {
             excludes 'com.springsource.javax.servlet',
                      'com.springsource.org.aopalliance',
                      'com.springsource.org.apache.commons.logging',
                      'com.springsource.org.apache.xmlcommons',
                      'org.springframework.aop',
                      'org.springframework.beans',
                      'org.springframework.context',
                      'org.springframework.core',
                      'org.springframework.transaction',
                      'org.springframework.web'
          }
       }
    }

  7. #7
    Join Date
    Jun 2010
    Location
    London
    Posts
    304

    Default

    Quote Originally Posted by dan0 View Post
    I'm relying on the security namespace to create the 'springSecurityFilterChain' bean:

    Code:
    <sec:http auto-config="true" entry-point-ref="casAuthEntryPoint">
            <sec:custom-filter ref="casAuthenticationFilter" position="CAS_FILTER"/>
            <sec:intercept-url pattern="/register" filters="none"/>
            <sec:intercept-url pattern="/**" access="ROLE_USER, ROLE_SUPER_USER, ROLE_ADMIN"/>
    </sec:http>
    Would you be able to zip up an example project that demonstrates the issue and attach it to a JIRA issue? I can't see why it wouldn't work, unless the custom element is doing something unusual.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •