Fork me on GitHub

Apache Shiro Logo Simple. Java. Security. Apache Software Foundation Event Banner

Handy Hint
Shiro v1 version notice

As of February 28, 2024, Shiro v1 was superseded by v2.

Apache Shiro’s JAX-RS support is built on top of the more general Servlet support, and requires Shiro’s Servlet Filter to be setup. The Servlet Filter can be setup by using Shiro’s Servlet fragment, web.xml configuration, or programmatically.

Dependencies

Include the shiro-servlet-plugin and shiro-jaxrs dependencies in you application classpath (we recommend using a tool such as Apache Maven or Gradle to manage this).

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-servlet-plugin</artifactId>
  <version>2.0.2</version>
</dependency>
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-jaxrs</artifactId>
  <version>2.0.2</version>
</dependency>
compile 'org.apache.shiro:shiro-servlet-plugin:2.0.2'
compile 'org.apache.shiro:shiro-jaxrs:2.0.2'
libraryDependencies += "org.apache.shiro" % "shiro-servlet-plugin" % "2.0.2"
libraryDependencies += "org.apache.shiro" % "shiro-jaxrs" % "2.0.2"
<dependency org="org.apache.shiro" name="shiro-servlet-plugin" rev="2.0.2"/>
<dependency org="org.apache.shiro" name="shiro-jaxrs" rev="2.0.2"/>
[org.apache.shiro/shiro-servlet-plugin "2.0.2"]
[org.apache.shiro/shiro-jaxrs "2.0.2"]
'org.apache.shiro:shiro-servlet-plugin:jar:2.0.2'
'org.apache.shiro:shiro-jaxrs:jar:2.0.2'
This is not required if using Jakarta EE module

For information on other ways to set up the Apache Shiro Filter see the web documentation.

Configuration

There are two basic approaches used to define the authentication and authorization for your JAX-RS resources: paths defined statically in configuration, or via annotations on your resource.

If you are using Guice or Spring see those docs on how to configure Shiro.

Paths defined in shiro.ini

Just like any other web application, your resources paths can be defined in a shiro.ini file. For example, to require resources under /api/secured to use basic authentication, your [urls] section would look like:

[urls]

/api/secured/** = authcBasic

See the web documentation for more details.

The other, probably more popular, option is to use Shiro’s annotations alongside other JAX-RS annotations on your resources. However, you MUST still define at least one path in your shiro.ini file.

The below code block will allow for basic authentication but NOT require it (via the permissive flag). This way all the resources under /api can optional require authentication and authorization based on annotations.

[urls]

/api/** = authcBasic[permissive]

Jakarta EE Security Annotations (JSR-250)

In addition to all Shiro annotations, Jax-RS module allows to specify Jakarta EE security annotations such as @RolesAllowed, @DenyAll and @PermitAll on your Jax-RS Endpoints.

Principal Propagation

If calling remote EJBs, for example, the container security mechanism might interpret java.security.Principal and will error the remote EJB call as unauthenticated. If Jax-RS is used in conjunction with the Jakarta EE module, the principal propagation is configured by Jakarta EE. However, if Jax-RS module is used standalone, principal propagation can be disabled by adding a configuration property to the map as illustrated below:

@ApplicationPath("/api")
public class JaxRsApplication extends Application {
    @Override
    public Map<String, Object> getProperties() {
        return Map.of(SHIRO_WEB_JAXRS_DISABLE_PRINCIPAL_PARAM, Boolean.TRUE);
    }
}

Example

To create a simple example we can define a JAX-RS resource HelloShiro:

@Path("/shiro")
public class HelloShiro {

  @GET
  @RequiresUser
  public String sayHelloShiro() {
      return "Hello!";
  }

  @GET
  @Path("define")
  @RequiresPermissions("hello:define")
  public String defineShiro() {
      return  "Shiro is the Japanese term for a castle";
  }
}

This resource has two end points, the first allows access by any logged-in user, the second any user with the permission hello:define.

The corresponding JAX-RS Application class:

@ApplicationPath("/api")
public class ExampleApp extends Application {

@Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();

        // register the Shiro Feature
        classes.add(ShiroFeature.class);

        // register resources:
        classes.add(HelloShiro.class);

        return classes;
    }
}

The ShiroFeature does three things:

  • configures exception mapping from Shiro’s AuthorizationException to HTTP status codes (401 and 403)

  • exposes Shiro’s Subject as a java.security.Principal (Principal Propagation)

  • Configures processing of Shiro’s annotations

In the above example, requests to either /api/shiro or /api/shiro/define will return an HTTP status of 401 if a user is not currently logged in. A request to /api/shiro/define made by a user without the hello:define will return a 403.

Want to see more?

You can find portable JAX-RS application that runs with Jersey, RestEasy or Apache CXF in the samples directory on GitHub.