Configure Spring Security on embedded Jetty in Spr

2019-02-07 11:14发布

问题:

I have a Spring beans definition file, as below

<bean id="jettyZk" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
    <!-- properties, threadPool, connectors -->

    <property name="handler">
        <bean class="org.eclipse.jetty.servlet.ServletContextHandler">
            <property name="eventListeners">
                <list>
                    <!-- my.ContextLoaderListener
                    * An ApplicationContextAware ContextLoaderListener that allows for using the current ApplicationContext,
                    * as determined by ApplicationContextAware, as the parent for the Root WebApplicationContext.
                    * 
                    * Also provides for specifying the contextConfigLocation of the Root WebApplicationContext, because
                    * Eclipse Jetty 7 ServletContextHandler does not expose a setInitParameters method.
                    -->
                    <bean class="my.ContextLoaderListener">
                        <property name="contextConfigLocation" value="/META-INF/spring/applicationContext-securityZk.xml"/>
                    </bean>
                    <!-- not sure if this is needed, disabled for now -->
                    <!-- <bean class="org.springframework.web.context.request.RequestContextListener"/> -->
                </list>
            </property>
            <property name="servletHandler">
                <bean class="org.eclipse.jetty.servlet.ServletHandler">
                    <property name="filters">
                        <list>
                            <bean class="org.eclipse.jetty.servlet.FilterHolder">
                                <property name="name" value="springSecurityFilterChain"/>
                                <property name="filter">
                                    <bean class="org.springframework.web.filter.DelegatingFilterProxy"/>
                                </property>
                            </bean>
                        </list>
                    </property>
                    <!-- filterMappings, servlets, servletMappings -->
                </bean>
            </property>
        </bean>
    </property>
</bean>

When trying to start the context, I get the following exception

Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: ServletContext must not be null

Caused by: java.lang.IllegalArgumentException: ServletContext must not be null
    at org.springframework.util.Assert.notNull(Assert.java:112)
    at org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext(WebApplicationContextUtils.java:109)

This is using Spring 3.0.5.RELEASE

The exception is understandable, looking at the code and JavaDocs for DelegatingFilterProxy#findWebApplicationContext, which says

The WebApplicationContext must have already been loaded and stored in the ServletContext before this filter gets initialized (or invoked).

because I'm trying to create the filter as a (sub)property of the context handler, so it seems sensible that the context has not yet been initialized and thus neither has the Spring WAC.

What I'd like to know is how can I configure Spring Security in an embedded Jetty container that Spring itself is assembling?

It seems like there's a catch 22 scenario that just needs a late initialisation, but I can't find a suitable flag to twiddle. I've tried setting lazy-init="true" onto the filter bean, but that didn't seem to achieve much, unsurprisingly.

Related: How to embed Jetty into Spring and make it use the same AppContext it was embedded into?

回答1:

I am running Jetty 6.1.4 and Spring 3.0.5, but I am doing it the old fashioned way, with WEB-INF/web.xml.

With that approach, it's causing zero problems.

public class JettyServer {

    public static void main(String[] args) throws Exception {
    Properties props = new Properties();
    props.load(new FileInputStream("./etc/server.properties"));

    Server server = new Server();

    final String configFile = props.getProperty("server.config");

    XmlConfiguration configuration = 
        new XmlConfiguration(new File(configFile).toURI().toURL());
    configuration.configure(server);
    HandlerCollection handlers = new HandlerCollection();

    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath(props.getProperty("context.path"));
    webapp.setDefaultsDescriptor(props.getProperty("default.config"));

    webapp.setWar(props.getProperty("war.path"));

    NCSARequestLog requestLog = new NCSARequestLog(props.getProperty("log.file"));
    requestLog.setExtended(true);
    RequestLogHandler requestLogHandler = new RequestLogHandler();
    requestLogHandler.setRequestLog(requestLog);

    handlers.setHandlers(
       new Handler[] { webapp, new DefaultHandler(), requestLogHandler });

    server.setHandler(handlers);

    server.setStopAtShutdown(true);
    server.setSendServerVersion(true);

    server.start();
    server.join();
}