blob: a5f9243dbb6d4bb9ba948c4ddde331ecf8ad2fb4 [file] [log] [blame]
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE- 2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Apache Shiro Jakarta EE Integration | Apache Shiro</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="keywords" content='documentation,jakarta-ee,integrations,web'>
<meta name="generator" content="JBake">
<meta name="google-site-verification" content="QIax6uT5UX3enoU0G8Pz2pXbQ45KaQuHZ3nCh9V27mw">
<meta name="google-site-verification" content="ecFap6dWJgS_GCCtxmJQJ_nFYQhM6EgSpBPZDU7xsCE">
<meta name="google-site-verification" content="gBTYOG8lMfNb_jrWrH3kFbudpEs_WrAJ2lb2-zLRaso"/>
<meta name="msvalidate.01" content="0B57EB46CBFAD8FD45008D2DB6B6C68C">
<meta property="og:title" content="Apache Shiro Jakarta EE Integration | Apache Shiro"/>
<meta property="og:type" content="article"/>
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@ApacheShiro" />
<meta property="article:modification_time" content="2023-02-06T00:00:00Z"/>
<meta property="article:tag" content='documentation'/>
<meta property="article:tag" content='jakarta-ee'/>
<meta property="article:tag" content='integrations'/>
<meta property="article:tag" content='web'/>
<meta property="og:locale" content="en_US" />
<meta property="og:url" content='https://shiro.apache.org/jakarta-ee.html'/>
<meta property="og:image" content='images/shiro-featured-image.png'/>
<meta property="og:image:width" content='1200'/>
<meta property="og:image:height" content='628'/>
<meta property="og:site_name" content="Apache Shiro"/>
<!-- Le styles -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="bootstrap-icons-1.5.0/bootstrap-icons.css" rel="stylesheet">
<link href="css/asciidoctor.css" rel="stylesheet">
<link href="css/base.css" rel="stylesheet">
<link href="highlight.js-11.2.0/styles/default.min.css" rel="stylesheet">
<link href="css/gh-pages/gh-fork-ribbon.css" rel="stylesheet"/>
<!-- Fav and touch icons -->
<!--<link rel="apple-touch-icon-precomposed" sizes="144x144" href="../assets/ico/apple-touch-icon-144-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="../assets/ico/apple-touch-icon-114-precomposed.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="../assets/ico/apple-touch-icon-72-precomposed.png">
<link rel="apple-touch-icon-precomposed" href="../assets/ico/apple-touch-icon-57-precomposed.png">-->
<link rel="shortcut icon" href="favicon.ico">
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//matomo.privacy.apache.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '2']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
<div id="top-bar"></div>
<a class="github-fork-ribbon right-top" href="https://github.com/apache/shiro" title="Fork me on GitHub">Fork me on GitHub</a>
<div id="wrap">
<div class="masthead">
<p class="lead">
<a href="index.html"><img src="images/apache-shiro-logo.png" style="height:100px; width:auto; vertical-align: bottom; margin-top: 20px;" alt="Apache Shiro Logo"></a>
<span class="tagline">Simple. Java. Security.</span>
<a class="pull-right" href="https://www.apache.org/events/current-event.html">
<img style="padding-top: 8px" src="https://www.apache.org/events/current-event-125x125.png" alt="Apache Software Foundation Event Banner"/>
</a>
</p>
</div>
<!-- Fixed navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light shadow-sm mb-4">
<div class="container-fluid">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="get-started.html">Get Started</a>
</li>
<li class="nav-item">
<a class="nav-link" href="documentation.html">Docs</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-webapps" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Web Apps
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown-webapps">
<li><a class="dropdown-item" href="web.html">General</a></li>
<li><a class="dropdown-item" href="jaxrs.html">JAX-RS</a></li>
<li><a class="dropdown-item" href="jakarta-ee.html">Jakarta EE</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="web-features.html">Features</a></li>
</ul>
</li>
<li><a class="nav-link" href="features.html">Features</a></li>
<!-- integrations -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-integrations" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Integrations
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown-integrations">
<li><a class="dropdown-item" href="spring-boot.html">Spring</a></li>
<li><a class="dropdown-item" href="guice.html">Guice</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="integration.html">Third-Party Integrations</a></li>
</ul>
</li>
<!-- Community -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-community" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Community
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown-community">
<li><a class="dropdown-item" href="forums.html">Community Forums</a></li>
<li><a class="dropdown-item" href="mailing-lists.html">Mailing Lists</a></li>
<li><a class="dropdown-item" href="articles.html">Articles</a></li>
<li><a class="dropdown-item" href="news.html">News</a></li>
<li><a class="dropdown-item" href="events.html">Events</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="community.html">More</a></li>
</ul>
</li>
<!-- About -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-about" role="button" data-bs-toggle="dropdown" aria-expanded="false">
About
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown-about">
<li><a class="dropdown-item" href="about.html">About</a></li>
<li><a class="dropdown-item" href="privacy-policy.html">Privacy Policy</a></li>
<li><a class="dropdown-item" href="security-reports.html">Vulnerability Reports</a></li>
</ul>
</li>
</ul>
<ul class="d-flex justify-content-end navbar-nav mb-2 mb-lg-0">
<!-- The ASF -->
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-asf" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Apache Software Foundation
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown-asf">
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Homepage</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="page-header">
<h1>Apache Shiro Jakarta EE Integration</h1>
</div>
<div class="admonitionblock tip">
<table>
<tbody>
<tr>
<td class="icon">
<div class="title">Handy Hint</div>
</td>
<td class="content">
<div class="title">Shiro v1 version notice</div>
<div class="paragraph">
<p>As of 2024-02-28, Shiro v1 will soon be superseded by v2.<p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Apache Shiro Jakarta EE module makes it transparent to use Shiro features in Jakarta EE applications
with minimal configuration. It makes annotations such as <code>@RequiresRoles</code> available in Jakarta EE (CDI, EJB, etc.) code.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Jakarta EE integration is available in Shiro 2.0 or later.<br>
The module is compatible with Java EE 8 through Jakarta EE 10 or later. It may work with earlier versions of Jakarta EE but was not tested with those.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="dependencies">Dependencies</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Include the <code>shiro-jakarta-ee</code> dependency in you application classpath (we recommend using a tool such as Apache Maven or Gradle to manage this).</p>
</div>
<ul class="nav nav-tabs" id="dependency-cli-tab" role="tablist">
<li class="nav-item" role="presentation">
<button
class="nav-link active"
id="maven-cli-tab"
data-bs-toggle="tab"
data-bs-target="#maven-cli"
type="button"
role="tab"
aria-controls="maven-cli"
aria-selected="true"
>Maven</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="gradle-cli-tab"
data-bs-toggle="tab"
data-bs-target="#gradle-cli"
type="button"
role="tab"
aria-controls="gradle-cli"
aria-selected="false"
>Gradle</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="sbt-cli-tab"
data-bs-toggle="tab"
data-bs-target="#sbt-cli"
type="button"
role="tab"
aria-controls="sbt-cli"
aria-selected="false"
>SBT</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="ivy-cli-tab"
data-bs-toggle="tab"
data-bs-target="#ivy-cli"
type="button"
role="tab"
aria-controls="ivy-cli"
aria-selected="false"
>Ivy</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="leiningen-cli-tab"
data-bs-toggle="tab"
data-bs-target="#leiningen-cli"
type="button"
role="tab"
aria-controls="leiningen-cli"
aria-selected="false"
>Leiningen</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="buildr-cli-tab"
data-bs-toggle="tab"
data-bs-target="#buildr-cli"
type="button"
role="tab"
aria-controls="buildr-cli"
aria-selected="false"
>Buildr</button>
</li>
</ul>
<div class="tab-content" id="dependency-cli-tab-content">
<div
class="tab-pane fade show active"
id="maven-cli"
role="tabpanel"
aria-labelledby="maven-cli-tab"
>
<pre><code class='xml language-xml'>&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-jakarta-ee&lt;/artifactId&gt;
&lt;version&gt;2.0.0&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
</div>
<div
class="tab-pane fade"
id="gradle-cli"
role="tabpanel"
aria-labelledby="gradle-cli-tab"
>
<pre><code class='groovy language-groovy'>compile 'org.apache.shiro:shiro-jakarta-ee:2.0.0'
</code></pre>
</div>
<div
class="tab-pane fade"
id="sbt-cli"
role="tabpanel"
aria-labelledby="sbt-cli-tab"
>
<pre><code class='scala language-scala'>libraryDependencies += "org.apache.shiro" % "shiro-jakarta-ee" % "2.0.0"
</code></pre>
</div>
<div
class="tab-pane fade"
id="ivy-cli"
role="tabpanel"
aria-labelledby="ivy-cli-tab"
>
<pre><code class='xml language-xml'>&lt;dependency org="org.apache.shiro" name="shiro-jakarta-ee" rev="2.0.0"/&gt;
</code></pre>
</div>
<div
class="tab-pane fade"
id="leiningen-cli"
role="tabpanel"
aria-labelledby="leiningen-cli-tab"
>
<pre><code class='clojure language-clojure'>[org.apache.shiro/shiro-jakarta-ee "2.0.0"]
</code></pre>
</div>
<div
class="tab-pane fade"
id="buildr-cli"
role="tabpanel"
aria-labelledby="buildr-cli-tab"
>
<pre><code class='groovy language-groovy'>'org.apache.shiro:shiro-jakarta-ee:jar:2.0.0'
</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="relationships_between_jakarta_ee_and_cdi_jax_rs_modules">Relationships between Jakarta EE and CDI / Jax-RS modules</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Jakarta EE module depends on CDI and Jax-RS submodules to fully integrate with the complete Jakarta EE API (Web Profile). If that is not desired, CDI and Jax-RS submodules can be used separately.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="features">Features</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Configure Shiro automatically with sensible defaults for Jakarta EE, with minimal, or no configuration aside from shiro.ini.</p>
</li>
<li>
<p>Use shiro.ini as usual to secure web applications, Jax-RS paths and endpoints.</p>
</li>
<li>
<p>Forms are automatically saved if sessions expire and seamlessly submitted upon subsequent login.</p>
</li>
<li>
<p>Use Shiro-secured application behind a load balancer or an SSL-terminating proxy (haproxy, nginx, etc.) easily.</p>
</li>
<li>
<p>Use <code>@Named</code> CDI beans in shiro.ini.</p>
</li>
<li>
<p>Inject Shiro Subject, Principal, Session and SecurityManager into CDI, EJB beans and Jax-RS endpoints.</p>
</li>
<li>
<p>Use Shiro and Jakarta EE Security annotations (i.e. <code>@RequiresRole</code>) to protect CDI, EJB (local and remote) beans (part of CDI module) and Jax-RS endpoints (part of Jax-RS module)</p>
</li>
<li>
<p>Use Jakarta Faces (JSF) tags.</p>
</li>
<li>
<p>Make Shiro&#8217;s login flows Jakarta Faces (JSF) Ajax-aware.</p>
</li>
<li>
<p>Smart redirect flow based on custom code and fallback pages.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="jakarta_ee_security_annotations_jsr_250">Jakarta EE Security Annotations (JSR-250)</h3>
<div class="paragraph">
<p>In addition to all Shiro annotations, Jakarta EE module allows to specify Jakarta EE security annotations such as <code>@RolesAllowed</code>, <code>@DenyAll</code> and <code>@PermitAll</code> on your beans</p>
</div>
</div>
<div class="sect2">
<h3 id="how_to_use_jakarta_9_jakarta_namespace">How to use Jakarta 9+ (jakarta.* namespace)</h3>
<div class="paragraph">
<p>Use the Shiro artifacts with Jakarta classifiers:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-jakarta-ee&lt;/artifactId&gt;
&lt;classifier&gt;jakarta&lt;/classifier&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-cdi&lt;/artifactId&gt;
&lt;classifier&gt;jakarta&lt;/classifier&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-core&lt;/artifactId&gt;
&lt;classifier&gt;jakarta&lt;/classifier&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-web&lt;/artifactId&gt;
&lt;classifier&gt;jakarta&lt;/classifier&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.omnifaces&lt;/groupId&gt;
&lt;artifactId&gt;omnifaces&lt;/artifactId&gt;
&lt;!-- replace LATEST with a version number --&gt;
&lt;version&gt;LATEST&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Import the Shiro BOM as seen below:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;dependencyManagement&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-bom&lt;/artifactId&gt;
&lt;version&gt;2.0.0&lt;/version&gt;
&lt;scope&gt;import&lt;/scope&gt;
&lt;type&gt;pom&lt;/type&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;/dependencyManagement&gt;</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="cdi_features">CDI Features</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Use Shiro and Jakarta Security annotations on any CDI bean, with no additional annotations required:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RequestScoped
@RequiresUser
public class MyBean { }
@RequestScoped
@RolesAllowed("role")
public class MyRoleBean { }</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="configuring_cdi_without_jakarta_ee_module_or_shiro_ini">Configuring CDI without Jakarta EE module or shiro.ini</h3>
<div class="paragraph">
<p>Below is an example of Shiro configuration in Java code with CDI only (no shiro.ini):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@ApplicationScoped
public class MyBean {
private DefaultSecurityManager securityManager;
void configureSecurityManager(@Observes @Initialized(ApplicationScoped.class) Object nothing) {
var realm = new SimpleAccountRealm();
securityManager = new DefaultSecurityManager(realm);
realm.addAccount("powerful", "awesome", "admin");
realm.addAccount("regular", "meh", "user");
SecurityUtils.setSecurityManager(securityManager);
}
void destroySecurityManager(@Observes @Destroyed(ApplicationScoped.class) Object nothing) {
securityManager.destroy();
SecurityUtils.setSecurityManager(null);
}
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="injecting_shiro_components_and_apis">Injecting Shiro components and APIs</h3>
<div class="paragraph">
<p>Shiro APIs can be <code>@Inject</code> into CDI and EJB beans:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@ApplicationScoped
public class MyBean {
@Inject
SecurityManager manager;
@Inject
Subject subject;
@Inject
@Principal
Supplier&lt;MyUserAccount&gt; userAccount;
@Inject
Session session;
@Inject
@NoSessionCreation
Session optionalSession;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>Subject</code>, <code>Session</code> and <code>@Principal</code> are always treated as Request-Scoped beans. They are injectable into any Jakarta EE bean including Jax-RS, Servlet and other CDI beans.<br>
If <code>Session</code> is annotated with <code>@NoSessionCreation</code> and there is no existing session, <code>InvalidSessionException</code> is thrown when accessing the Injected session.<br>
Any Shiro principal object can be injected if annotated by <code>@Principal</code>. It must be injected as <code>Supplier&lt;MyPrincipalClass&gt;</code>, and <code>Supplier.get()</code> may return null if there are no principals available of the injected type.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="jakarta_ee_integration_module">Jakarta EE Integration Module</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Jakarta EE integration module was inspired by this <a href="https://balusc.omnifaces.org/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html">OmniFaces article</a> and brings everything together to seamlessly create secure Jakarta EE applications easily and with minimal configuration. The module works "the Shiro way" and uses shiro.ini in a straight-forward and intuitive way.</p>
</div>
<div class="sect2">
<h3 id="configuration">Configuration</h3>
<div class="sect3">
<h4 id="enabling_rememberme_functionality">Enabling RememberMe functionality</h4>
<div class="paragraph">
<p>RememberMe functionality is disabled by default. You can enable it easily by adding the below to <code>shiro.ini</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-properties hljs" data-lang="properties">authc.useRemembered = true</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="automatic_delay_when_login_failed">Automatic delay when login failed</h4>
<div class="paragraph">
<p>When user fails to log in, Shiro will automatically delay the failure response for a number of seconds. This can be one of the strategies to prevent brute force attacks.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Be careful utilizing this technique, as it could be a vector for a denial-of-service attack. Servers with virtual thread support (Project Loom) will not be affected by the DDOS vector.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Add the below to <code>shiro.ini</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-properties hljs" data-lang="properties">authc.loginFailedWaitTime = 5</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="web_xml"><code>web.xml</code></h4>
<div class="paragraph">
<p>No configuration is required. The module is bootstrapped automatically.
To disable automatic bootstrapping, add the following to <code>web.xml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;org.apache.shiro.ee.disabled&lt;/param-name&gt;
&lt;param-value&gt;true&lt;/param-value&gt;
&lt;/context-param&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The module adds <code>ShiroFilter</code> to the Servlet configuration. For most cases, the filter ordering works correctly out of the box. However, some cases require to reorder filters. Filter ordering follows the order of <code>&lt;filter-mapping&gt;</code> elements in <code>web.xml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;!-- Enforce Filter Ordering (Optional) --&gt;
... other filters ...
&lt;filter-mapping&gt;
&lt;filter-name&gt;ShiroFilter&lt;/filter-name&gt;
&lt;url-pattern/&gt;
&lt;/filter-mapping&gt;
... other filters ...</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="shiro_ini_file_locations">Shiro.ini file locations</h4>
<div class="paragraph">
<p>The module finds shiro.ini in the same manner as <a href="web.html#custom_configuration_locations">Web Configuration</a> (WEB-INF/shiro.ini by default). Additionally, configuration is enhanced to merge two separate configuration files:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;shiroConfigLocations&lt;/param-name&gt;
&lt;param-value&gt;classpath:META-INF/shiro.ini, classpath:META-INF/shiro2.ini&lt;/param-value&gt;
&lt;/context-param&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Only two files are supported. More than two file will result in an error.</p>
</div>
</div>
<div class="sect3">
<h4 id="custom_webenvironment_class">Custom WebEnvironment class</h4>
<div class="paragraph">
<p>Custom class is supported, provided it&#8217;s inherited from <code>org.apache.shiro.ee.listeners.IniEnvironment</code> or has the same functionality.</p>
</div>
</div>
<div class="sect3">
<h4 id="enhanced_ssl_filter">Enhanced SSL filter</h4>
<div class="paragraph">
<p>By default, Shiro enforces a specific ssl port number where the requests go to. However, if the application is behind a load balancer or a proxy (such as haproxy or nginx), the ports may be different for different instances.
In this case, port filter can be turned off to allow SSL traffic to go to any port.
To disable port filter, put the following in your <code>shiro.ini</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-properties hljs" data-lang="properties">ssl.enablePortFilter = false</code></pre>
</div>
</div>
<div class="paragraph">
<p>SSL filter is only enabled in Jakarta Faces production mode (default) and is disabled in Development mode. However, if SSL filter always needs to be enabled, put the following into your <code>shiro.ini</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-properties hljs" data-lang="properties">ssl.alwaysEnabled = true</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="using_enhanced_ssl_filter_with_haproxy_or_other_load_balancers">Using Enhanced SSL filter with HAProxy or other load balancers</h4>
<div class="paragraph">
<p>When behind SSL-terminating proxy, Shiro may not be able to determine if SSL was used.
<code>X-Forwarded-Proto</code> header can mitigate this. You can configure your proxy set this header to <code>https</code> to tell Shiro
when SSL is used. Below is a haproxy configuration excerpt:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs">....
frontend tcp-in
http-request set-header X-Forwarded-Proto https if { ssl_fc }
...</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="using_cdi_beans_in_shiro_ini">Using CDI Beans in shiro.ini</h4>
<div class="paragraph">
<p>Below is an example of using a CDI bean and assign its property to a variable in shiro.ini</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Named
@ApplicationScoped
public class MyBean {
public boolean getMyValue() {
return true;
}
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-properties hljs" data-lang="properties">myBeanInstance = myBean
myVariable = $myBeanInstance.myValue</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="using_cdi_for_custom_rememberme_cipher_key_generation">Using CDI for custom RememberMe cipher key generation</h4>
<div class="paragraph">
<p>Use CDI bean that implements <code>CipherKeySupplier</code> interface to create a custom logic for generating the cipher key.
For convenience, String data type is used, If the String that&#8217;s returned is null or blank (just spaces), the default cipher key generating mechanism is used.</p>
</div>
<div class="paragraph">
<p>For example, you can use MicroProfile Config to get the cipher key:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@ApplicationScoped
public class CipherKeySource implements CipherKeySupplier {
@Inject
@ConfigProperty(name = "my.config.source.cipher-key")
String cipherKey;
@Override
public String get() {
return cipherKey;
}
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="enhanced_login_flow_and_smart_fallback_pages">Enhanced login flow and smart fallback pages</h4>
<div class="paragraph">
<p>Shiro always tries to redirect back to a previous page when a login or logout flow was successful.
However, in some cases this may not be desired, such as when the previous page was a login page itself.
In such cases, a fallback page is provided in shiro.ini (usually index or root page), and it is used
even if the previous page is available. Logic is provided by implementing the <code>FallbackPredicate</code> interface.<br>
Here we use the path check. If previous page is part of the auth folder, fallback path (index / root) page will always be used:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Named
@ApplicationScoped
public class UseFallback implements FallbackPredicate {
@Override
public boolean useFallback(String path, HttpServletRequest request) {
return path.contains("shiro/auth/");
}
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-properties hljs" data-lang="properties">fallbackType = useFallback
authc.loginFallbackType = $fallbackType
authc.logoutFallbackType = $fallbackType</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="automatic_form_submit_upon_subsequent_login">Automatic form submit upon subsequent login</h4>
<div class="paragraph">
<p>Jakarta EE module will automatically resubmit forms when session expires and a subsequent re-login occurs. This will prevent users data from loss due to sessions timing out.</p>
</div>
<div class="listingblock">
<div class="title">To disable this behavior, add the following to <code>web.xml</code>:</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;org.apache.shiro.form-resubmit.disabled&lt;/param-name&gt;
&lt;param-value&gt;true&lt;/param-value&gt;
&lt;/context-param&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>During form resubmissions, the original request is replayed, and the response is relayed back to the browser, along with any cookies genereated. Cookies are set to be secure by default.</p>
</div>
<div class="listingblock">
<div class="title">To disable secure cookie attribute, add the following to <code>web.xml</code>:</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;org.apache.shiro.form-resubmit.secure-cookies&lt;/param-name&gt;
&lt;param-value&gt;false&lt;/param-value&gt;
&lt;/context-param&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, you can set <code>org.apache.shiro.form-resubmit.secure-cookies</code> system property in the same manner as above.</p>
</div>
<div class="paragraph">
<p>By default, form resubmission logic replays the request to the original URI. This works for most cases, but in some deployments, such as certain Docker or Kubernetes, host, port or both need to be modified during resubmission. There are two system properties to allow this: <code>org.apache.shiro.form-resubmit-host</code> (String) and <code>org.apache.shiro.form-resubmit-port</code> (Integer).</p>
</div>
</div>
<div class="sect3">
<h4 id="configuring_for_tomcat_jetty_or_without_jakarta_faces">Configuring for Tomcat / Jetty (or without Jakarta Faces)</h4>
<div class="paragraph">
<p>If Jakarta Faces (JSF) is not available in your environment, you need to put the following into your <code>web.xml</code> to enable proper OmniFaces initialization:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;org.omnifaces.SKIP_DEPLOYMENT_EXCEPTION&lt;/param-name&gt;
&lt;param-value&gt;true&lt;/param-value&gt;
&lt;/context-param&gt;</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="principal_propagation">Principal Propagation (Jakarta EE)</h4>
<div class="paragraph">
<p>By default, Shiro will propagate the Subject to <code>java.security.Principal</code>, which may not always be desired. For example, if calling remote EJBs, the container security mechanism might interpret the principal and will error the remote EJB call as unauthenticated.
To disable this behavior, you can put the following in your <code>web.xml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;org.apache.shiro.web.disable-principal&lt;/param-name&gt;
&lt;param-value&gt;true&lt;/param-value&gt;
&lt;/context-param&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="security_annotations_shiro_and_ee">Security Annotations (Shiro and EE)</h3>
<div class="paragraph">
<p>The module works transparently to enable Shiro (<code>@RequiresRole</code>) and Jakarta Security (<code>@RolesAllowed</code>) annotations,
without any additional annotations or configuration.</p>
</div>
</div>
<div class="sect2">
<h3 id="automatic_form_resubmit_when_logged_out_and_subsequently_logged_in">Automatic form resubmit when logged out and subsequently logged in</h3>
<div class="paragraph">
<p>Users get frustrated when they lose data. For example, while filling out a complicated form,
the user get side-tracked with another browser tab or window. Then lunch. After getting back to the form,
they will fill out the rest of the form and submit it. However, since it took a long time, they are now thrown
back to the login screen. Once they log in, all their data entry vanished!<br>
There are few workarounds for his issue, like a periodic ping of the back-end or something similar, but that causes unnecessary load and memory pressure on the server. These methods are also very brittle.<br>
Jakarta EE module will automatically save the form data into Shiro cache when a user is redirected to a login screen.
The cache is encrypted. And when the user subsequently logs back in, the form is automatically submitted and
the data entry is never lost.<br>
Form resubmission works with JSP, Jakarta Faces partial page rendering (Ajax) and with PrimeFaces components.</p>
</div>
</div>
<div class="sect2">
<h3 id="using_cdi_sessionscoped_and_viewscoped_beans">Using CDI <code>@SessionScoped</code> and <code>@ViewScoped</code> beans</h3>
<div class="paragraph">
<p>Both CDI and OmniFaces Session and ViewScoped beans work correctly and transparently with both web container and Shiro native sessions.</p>
</div>
</div>
<div class="sect2">
<h3 id="jakarta_faces_jsf_features">Jakarta Faces (JSF) features</h3>
<div class="paragraph">
<p>When using Shiro with Jakarta Faces, login and logout flow works transparently and correctly without worrying about <code>ViewExpiredException</code>. This works for both Ajax and standard events.<br>
Both server and client state saving methods are supported.<br>
Shiro&#8217;s <code>FormAuthenticationFilter</code> (<code>authc</code> by default) in shiro.ini works the same way in Faces
as it does in JSP.<br>
It takes named Faces components and uses them to authenticate.
Below, elements named by <code>id</code> are automatically used to authenticate, and any command button without explicit action will trigger the login.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;h:form prependId="false" id="form"&gt;
Username: &lt;h:inputText id="username" p:autofocus="true" title="Username: " required="true" /&gt;
Password: &lt;h:inputText id="password" title="Password: " required="true"/&gt;
Remember Me: &lt;h:selectBooleanCheckbox id="rememberMe" title="Remember Me: "/&gt;
&lt;h:commandButton id="login" value="Login ..."/&gt;
&lt;/h:form&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Logout can be specified via shiro.ini, without having any additional pages or code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-none hljs">/shiro/auth/logout* = ssl, logout</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;h:outputLink value="#{request.contextPath}/shiro/auth/logout"&gt;Logout&lt;/h:outputLink&gt;</code></pre>
</div>
</div>
<div class="sect3">
<h4 id="jakarta_faces_variables_and_actions">Jakarta Faces variables and actions</h4>
<div class="paragraph">
<p>Below are actions and variables available within Facelets.
All actions have zero-argument versions that execute sensible defaults.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;div jsf:rendered="#{authc.sessionExpired}"&gt;
Your Session Has Expired
&lt;/div&gt;
&lt;div jsf:rendered="#{authc.loginFailure}"&gt;
Login Failed
&lt;/div&gt;
&lt;h:commandButton value="Login ..." action="#{authc.login}"/&gt;
&lt;h:commandButton value="Login ..." action="#{authc.login(bean.username, bean.password)}"/&gt;
&lt;h:commandButton value="Login ..." action="#{authc.login(bean.username, bean.password, bean.rememberMe)}"/&gt;
&lt;h:commandButton value="Login ..." action="#{authc.redirectIfLoggedIn('page')}"/&gt;</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="forms_api">Forms API</h4>
<div class="paragraph">
<p><code>Forms</code> class has external-faces API that can be accessed directly from code. See javadoc for further info.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="jax_rs">Jax-RS</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Jakarta EE module uses Jax-RS module to provide support for non-CDI and non-EJB beans.<br>
See <a href="jaxrs.html">Jax-RS documentation</a> for more details.</p>
</div>
<div class="sect2">
<h3 id="principal_propagation_jax_rs">Principal Propagation (Jax-RS)</h3>
<div class="paragraph">
<p>Propagation is enabled or disabled for Jax-RS by the Jakarta EE module. See <a href="jaxrs.html#principal_propagation">Jax-RS Principal Propagation</a></p>
</div>
</div>
</div>
</div>
<hr />
</div>
<div class="footer-padding"></div>
<div class="container-fluid pt-2 border-top" id="custom-footer">
<footer class="row justify-content-between align-items-center">
<div class=" col-md-5">
<div class="copyright-footer justify-content-start">
<a href="https://www.apache.org/foundation/contributing.html">Donate to the ASF</a>&nbsp;|&nbsp;
<a href="https://www.apache.org/licenses/LICENSE-2.0.html">License</a>&nbsp;
<p class="text-muted">Copyright &copy; 2008-2024 The Apache Software Foundation</p>
</div>
</div>
<div class="d-flex justify-content-center col-md-1">
<a class="btn btn-social"><span class="social-icon social-twitter"><i class="bi bi-twitter"></i></span></a>
<a class="btn btn-social"><span class="social-icon social-facebook"><i class="bi bi-facebook"></i></span></a>
<a class="btn btn-social"><span class="social-icon social-linkedin"><i class="bi bi-linkedin"></i></span></a>
</div>
<div class="d-flex justify-content-end col-md-4" id="editThisPage">
<input type="hidden" id="ghEditPage" value="https://github.com/apache/shiro-site/edit/main/src/site/content/jakarta-ee.adoc"/>
</div>
<div class="d-flex col-md-2 justify-content-end" style="position: relative">
<div class="footer-shield"></div>
</div>
</footer>
</div>
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="js/bootstrap.min.js"></script>
<script src="highlight.js-11.2.0/highlight.min.js"></script>
<script src="js/shiro.js"></script>
<script>
docReady(
addPageEditLink()
);
</script>
<script>hljs.highlightAll();</script>
</body>
</html>