Search code examples
javasessionshiroembedded-jetty

Why doesn't Shiro's AnonymousFilter create new web sessions in this example?


I have two applications secured with Shiro allowing anonymous access to all pages. One is a WAR deployed inside a Jetty server, and the other is a standalone Java application with an embedded Jetty server.

  1. Why does the standalone app not create sessions but the WAR app does?
  2. How do I configure the standalone app so that sessions are created?
  3. Why does the standalone app require the session manager to be explicitly defined in the shiro.ini but the WAR app does not? (Removing it means the authcBasic filter doesn't work either).

WAR app

WEB-INF/shiro.ini:

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager

[urls]
/** = anon

WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<welcome-file-list>
    <welcome-file>home.jsp</welcome-file>
</welcome-file-list>

</web-app>

home.jsp:

<!DOCTYPE html>
<html>
<body>
</body>
</html>

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress osmorcNonOsgiMavenDependency -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.foo.example</groupId>
    <artifactId>apache-shiro-tutorial-webapp</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>Apache Shiro Tutorial Webapp</name>
    <packaging>war</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.1.0.v20131115</version>
                <configuration>
                    <webApp>
                        <contextPath>/</contextPath>
                    </webApp>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.2</version>
        </dependency>
    </dependencies>
</project>

Standalone app

classpath:shiro.ini:

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager

[urls]
/** = anon

Main.java:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.env.EnvironmentLoaderListener;
import org.apache.shiro.web.servlet.ShiroFilter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import static java.util.EnumSet.allOf;

public class Main {

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        ShiroFilter shiroFilter = new ShiroFilter();

        ServletContextHandler context = new ServletContextHandler();
        context.addEventListener(new EnvironmentLoaderListener());
        context.setContextPath("/");
        context.addFilter(new FilterHolder(shiroFilter), "/", allOf(DispatcherType.class));
        context.addServlet(new ServletHolder(dummyServlet), "/");

        server.setHandler(context);

        server.start();
        SecurityUtils.setSecurityManager(shiroFilter.getSecurityManager());
        server.join();
    }

    private static HttpServlet dummyServlet = new HttpServlet() {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("OK");
        }
    };
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test</groupId>
    <artifactId>test</artifactId>
    <version>1.0-SNAPSHOT</version>

<dependencies>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.3.1.v20150714</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>9.3.1.v20150714</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.2.2</version>
    </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
            <scope>runtime</scope>
        </dependency>
</dependencies>

</project>

Proving the standalone app works (and therefore the AnonymousFilter is the problem)

In the standalone app, if I replace the shiro.ini file with:

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager

[users]
name = password

[urls]
/** = authcBasic

then I can log in as "name" and a session is created. It seems to only be the anonymous filter which refuses to create sessions.

Other info

When I say "a session is created" I mean when I browse to localhost:8080/ the I can see the Set-Cookie: JSESSIONID=blahblahblah header in the response from the server. No such cookie is ever set by the anonymous filter in the standalone app.


Solution

  • I tracked down the cause of this issue to the url pattern of the Filter:

    /*
    

    vs

    /