Announcement Announcement Module
Collapse
No announcement yet.
Integrating Spring Security into a web slice bundle. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Integrating Spring Security into a web slice bundle.

    I have a web application running consisting of a host bundle + a couple of slices. I am also using spring security and I was just wondering if it is possible to define the security settings for the slice within the slice. Currently, as far as I can determine, the security settings need to be set in the host (with a filter defined in the slice web.xml to bind the requests security info to the slices security threadlocal).

    While having a spring security definition loaded in the slice does not appear to cause slice startup to fail, any security settings defined in the slice appear to be ignored/never reached. Is this correct?

    My appologies if there is a thread dealing with this already.

    Cheers in advance.

  • #2
    Fixed this.

    The problem was that during startup, the 'findWebApplicationContext' method of the org.springframework.web.filter.DelegatingFilterPro xy will return the root web app context using WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT _ATTRIBUTE. To get the the slice's web app context, need to use the WebApplicationContextUtils.getWebApplicationContex t( ServletContext sc, String attrName), passing in the value "org.springframework.web.servlet.FrameworkServlet. CONTEXT."<dispatcherServletNameForSlice> as the attribute. This returns the slices web app context, that can then be refered to from the filter.

    Comment


    • #3
      Excellent, glad to hear you solved your problem. Apologies for not managing to look at this sooner.

      Comment


      • #4
        wendigo, would you mind sharing your set-up? Did you create a custom filter or request wrapper?

        When spring security runs in the host slice, each security filter will add a request attribute that it already ran. This means any secondary configuration in the slice with a Spring Security filter and configuration will be ignored because request attributes are already set.

        We are contemplating a custom filter in the slice that shadows spring security request attributes or going osgi published service with customizing FilterSecurityInterceptor to consume dynamic slice intercept urls.

        Comment


        • #5
          Sorry for delay, haven't looked at this thread for a while.

          The motivation behind this was to add slice specific security settings that could be set within the slice. What I found was that during startup of the slice, the slice would pick up the host's web application context by default. If one were using the Spring Security default 'springSecurityFilterChain' naming convention, this would lead to the hosts security settings being bound to the slice. To get around this I created a filter that would get a handle to the slices web app context. In the context of slices, the slices web app context is held as an attribute in the servlet context, the key for which is an aggregation of the string "org.springframework.web.servlet.FrameworkServlet. CONTEXT." + the slices dispatcher servlet name.

          Hence created a filter:

          Code:
          /**
           * An extension of the {@link DelegatingFilterProxy} that has identical
           * functionality apart from the {@link #findWebApplicationContext()} method that
           * is overwritten to return the slices {@link WebApplicationContext} (as opposed
           * to the hosts, which happens by default). Allows slice specific settings (eg
           * security) to be applied.
           * 
           *
           */
          public class SliceDelegatingFilterProxy extends DelegatingFilterProxy {
          
              /**
               * Key for looking up the slice bundle.
               */
              private static final String SLICE_CONTEXT_KEY = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
          
              /**
               * The name of the servlet that is the delegate for this slice.
               */
              private String servletName;
          
          
              /**
               * Attempts to get the slice {@link WebApplicationContext}. If that fails it
               * falls back to the default functionality of the
               * {@link DelegatingFilterProxy}.
               * 
               * @see org.springframework.web.filter.DelegatingFilterProxy#findWebApplicationContext()
               */
              @Override
              protected WebApplicationContext findWebApplicationContext() {
                  final String name = getServletName ();
                  if (null != name) {
                      final WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext (getServletContext (), SLICE_CONTEXT_KEY + servletName);
                      if (null != applicationContext) {
                          return applicationContext;
                      }
                  }
                  return super.findWebApplicationContext ();
              }
          
          
              /**
               * Gets the servlet name to use or null if the name is null or a zero length
               * string.
               * 
               * @return the servlet name or null.
               */
              private String getServletName() {
                  if (null == this.servletName) {
                      return null;
                  }
                  final String servletNme = this.servletName.trim ();
                  if (servletNme.length () == 0) {
                      return null;
                  }
                  return servletNme;
              }
          
          
              /**
               * Set the servlet name.
               * 
               * @param servletName
               *            the servletName to set
               */
              public void setServletName(String servletName) {
                  this.servletName = servletName;
              }
          
          }
          In the web.xml, declare the filter:

          Code:
            <filter>
              <filter-name>springSecurityFilterChain</filter-name>
              <filter-class>SliceDelegatingFilterProxy</filter-class>
              <init-param>
                  <param-name>targetBeanName</param-name>
                  <param-value>slicesSpringSecurityFilterChain</param-value>
              </init-param>
              <init-param>
                 <!-- Required for looking up the slices web app context -->
                  <param-name>servletName</param-name>
                  <param-value>slice.dispatcher.servlet.name</param-value>
              </init-param>
            </filter>     
            <filter-mapping>
              <filter-name>springSecurityFilterChain</filter-name>
              <url-pattern>....</url-pattern>     
            </filter-mapping>
          
              <!--
              Servlet definition.  Handles all requests to the slice
              -->
            <servlet>
              <servlet-name>slice.dispatcher.servlet.name</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   
              <init-param>
                  <param-name>contextClass</param-name>
                  <param-value>com.springsource.server.web.dm.ServerOsgiBundleXmlWebApplicationContext</param-value>
              </init-param>
            </servlet>  
            <servlet-mapping>
              <servlet-name>slice.dispatcher.servlet.name</servlet-name>
              <url-pattern>*.html</url-pattern>
            </servlet-mapping>
          Wherever the security settings are set:

          Code:
           <bean id="slicesSpringSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
               <security:filter-chain-map path-type="ant">
                 <security:filter-chain  pattern="*.html"    filters="<DECLARE FILTERS TO APPLY>" />    
               </security:filter-chain-map>     
             </bean>
          Hope this makes sense.
          Last edited by wendigo; Oct 14th, 2009, 10:18 PM.

          Comment


          • #6
            This makes perfect sense (if you can believe it).

            I am sure there were a lot of dead fairies after you were done (http://blog.springsource.com/2007/12...ng-security-2/)

            Thank you, this is a very nice and clean solution. Kicking myself for not cooking this up

            I was trying to publish a FilterInvocationSecurityMetadataSource from slice and use <osgi:list /> in the host for FilterSecurityInterceptor configuration.

            Thanks again.

            Comment


            • #7
              wendigo,

              I just took a quick glance at your code. It looks good, but I think your custom SliceDelegatingFilterProxy is unnecessary.

              FYI: I added support for a contextAttribute directly to DelegatingFilterProxy for exactly this purpose (i.e., providing the name of the WebApplicationContext to retrieve from the ServletContext). In fact, the (now deprecated) Web Module support in dm Server 1.x relied on this feature to configure filters via Web-* manifest headers.

              Thus instead of using your SliceDelegatingFilterProxy, simply use the standard DelegatingFilterProxy and set the contextAttribute init-param to org.springframework.web.servlet.FrameworkServlet.C ONTEXT.XXX, where XXX is the name of your configured DispatcherServlet.

              Give it a try and let me know how that works for you!

              Sam

              Comment


              • #8
                For sure. However, I'm lazy, and find remembering having to prepend with the whole "org.springframework.web.servlet.FrameworkServlet. CONTEXT." a tad of an embuggerance...

                Comment


                • #9
                  Hi Sam,
                  I got the same problem. Can you help correct my code? Here is part of my slice web.xml. It seems does not work.

                  <filter>
                  <filter-name>springSecurityFilterChain</filter-name>
                  <filter-class>org.springframework.web.filter.DelegatingFil terProxy</filter-class>
                  <init-param>
                  <param-name>contextAttribute</param-name>
                  <param-value>org.springframework.web.servlet.FrameworkSer vlet.CONTEXT.slicesServlet</param-value>
                  </init-param>
                  </filter>
                  <filter-mapping>
                  <filter-name>springSecurityFilterChain</filter-name>
                  <url-pattern>/*</url-pattern>
                  </filter-mapping>

                  <servlet>
                  <servlet-name>slicesServlet</servlet-name>
                  <servlet-class>
                  org.springframework.web.servlet.DispatcherServlet
                  </servlet-class>
                  <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>
                  /WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-security.xml
                  </param-value>
                  </init-param>
                  <load-on-startup>1</load-on-startup>
                  </servlet>
                  <servlet-mapping>
                  <servlet-name>slicesServlet</servlet-name>
                  <url-pattern>/app/*</url-pattern>
                  </servlet-mapping>

                  And here is the security configuration applicationContext-security.xml.

                  <s:http use-expressions="true">
                  <s:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
                  <s:form-login login-page="/../login.jsp" default-target-url="/"/>
                  </s:http>

                  It should forbit access to any pages in the slice if it is working, right?

                  Thanks,
                  Alexi


                  Originally posted by Sam Brannen View Post
                  wendigo,

                  I just took a quick glance at your code. It looks good, but I think your custom SliceDelegatingFilterProxy is unnecessary.

                  FYI: I added support for a contextAttribute directly to DelegatingFilterProxy for exactly this purpose (i.e., providing the name of the WebApplicationContext to retrieve from the ServletContext). In fact, the (now deprecated) Web Module support in dm Server 1.x relied on this feature to configure filters via Web-* manifest headers.

                  Thus instead of using your SliceDelegatingFilterProxy, simply use the standard DelegatingFilterProxy and set the contextAttribute init-param to org.springframework.web.servlet.FrameworkServlet.C ONTEXT.XXX, where XXX is the name of your configured DispatcherServlet.

                  Give it a try and let me know how that works for you!

                  Sam

                  Comment


                  • #10
                    Hi Wendigo,

                    I tried your code, but it seems not work. See the above comment. Can you share your slice web.xml and applicationContext.xml?

                    Thanks,
                    alexi

                    Originally posted by wendigo View Post
                    Sorry for delay, haven't looked at this thread for a while.

                    The motivation behind this was to add slice specific security settings that could be set within the slice. What I found was that during startup of the slice, the slice would pick up the host's web application context by default. If one were using the Spring Security default 'springSecurityFilterChain' naming convention, this would lead to the hosts security settings being bound to the slice. To get around this I created a filter that would get a handle to the slices web app context. In the context of slices, the slices web app context is held as an attribute in the servlet context, the key for which is an aggregation of the string "org.springframework.web.servlet.FrameworkServlet. CONTEXT." + the slices dispatcher servlet name.

                    Hence created a filter:

                    Code:
                    /**
                     * An extension of the {@link DelegatingFilterProxy} that has identical
                     * functionality apart from the {@link #findWebApplicationContext()} method that
                     * is overwritten to return the slices {@link WebApplicationContext} (as opposed
                     * to the hosts, which happens by default). Allows slice specific settings (eg
                     * security) to be applied.
                     * 
                     *
                     */
                    public class SliceDelegatingFilterProxy extends DelegatingFilterProxy {
                    
                        /**
                         * Key for looking up the slice bundle.
                         */
                        private static final String SLICE_CONTEXT_KEY = "org.springframework.web.servlet.FrameworkServlet.CONTEXT.";
                    
                        /**
                         * The name of the servlet that is the delegate for this slice.
                         */
                        private String servletName;
                    
                    
                        /**
                         * Attempts to get the slice {@link WebApplicationContext}. If that fails it
                         * falls back to the default functionality of the
                         * {@link DelegatingFilterProxy}.
                         * 
                         * @see org.springframework.web.filter.DelegatingFilterProxy#findWebApplicationContext()
                         */
                        @Override
                        protected WebApplicationContext findWebApplicationContext() {
                            final String name = getServletName ();
                            if (null != name) {
                                final WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext (getServletContext (), SLICE_CONTEXT_KEY + servletName);
                                if (null != applicationContext) {
                                    return applicationContext;
                                }
                            }
                            return super.findWebApplicationContext ();
                        }
                    
                    
                        /**
                         * Gets the servlet name to use or null if the name is null or a zero length
                         * string.
                         * 
                         * @return the servlet name or null.
                         */
                        private String getServletName() {
                            if (null == this.servletName) {
                                return null;
                            }
                            final String servletNme = this.servletName.trim ();
                            if (servletNme.length () == 0) {
                                return null;
                            }
                            return servletNme;
                        }
                    
                    
                        /**
                         * Set the servlet name.
                         * 
                         * @param servletName
                         *            the servletName to set
                         */
                        public void setServletName(String servletName) {
                            this.servletName = servletName;
                        }
                    
                    }
                    In the web.xml, declare the filter:

                    Code:
                      <filter>
                        <filter-name>springSecurityFilterChain</filter-name>
                        <filter-class>SliceDelegatingFilterProxy</filter-class>
                        <init-param>
                            <param-name>targetBeanName</param-name>
                            <param-value>slicesSpringSecurityFilterChain</param-value>
                        </init-param>
                        <init-param>
                           <!-- Required for looking up the slices web app context -->
                            <param-name>servletName</param-name>
                            <param-value>slice.dispatcher.servlet.name</param-value>
                        </init-param>
                      </filter>     
                      <filter-mapping>
                        <filter-name>springSecurityFilterChain</filter-name>
                        <url-pattern>....</url-pattern>     
                      </filter-mapping>
                    
                        <!--
                        Servlet definition.  Handles all requests to the slice
                        -->
                      <servlet>
                        <servlet-name>slice.dispatcher.servlet.name</servlet-name>
                        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   
                        <init-param>
                            <param-name>contextClass</param-name>
                            <param-value>com.springsource.server.web.dm.ServerOsgiBundleXmlWebApplicationContext</param-value>
                        </init-param>
                      </servlet>  
                      <servlet-mapping>
                        <servlet-name>slice.dispatcher.servlet.name</servlet-name>
                        <url-pattern>*.html</url-pattern>
                      </servlet-mapping>
                    Wherever the security settings are set:

                    Code:
                     <bean id="slicesSpringSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
                         <security:filter-chain-map path-type="ant">
                           <security:filter-chain  pattern="*.html"    filters="<DECLARE FILTERS TO APPLY>" />    
                         </security:filter-chain-map>     
                       </bean>
                    Hope this makes sense.

                    Comment


                    • #11
                      OK. seems Slice only support one filter. Here is the code from com.springsource.osgi.slices.core.internal.webapp. container.ImmutableFilterChain

                      I am right?

                      public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
                      int index = this.index.getAndIncrement();

                      if (index < this.filters.length) {
                      Filter filter = filters[index];
                      filter.doFilter(request, response, this);
                      } else {
                      servlet.service(request, response);
                      }
                      }

                      Comment


                      • #12
                        Not sure I understand. The slice supports as many filters as you care to declare in the slices web.xml.

                        Comment

                        Working...
                        X