blob: a41804280afd3ecebd8bad4d41748f48ea2a51f6 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Apache TomEE</title>
<meta name="description"
content="Apache TomEE is a lightweight, yet powerful, JavaEE Application server with feature rich tooling." />
<meta name="keywords" content="tomee,asf,apache,javaee,jee,shade,embedded,test,junit,applicationcomposer,maven,arquillian" />
<meta name="author" content="Luka Cvetinovic for Codrops" />
<link rel="icon" href="../../favicon.ico">
<link rel="icon" type="image/png" href="../../favicon.png">
<meta name="msapplication-TileColor" content="#80287a">
<meta name="theme-color" content="#80287a">
<link rel="stylesheet" type="text/css" href="../../css/normalize.css">
<link rel="stylesheet" type="text/css" href="../../css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="../../css/owl.css">
<link rel="stylesheet" type="text/css" href="../../css/animate.css">
<link rel="stylesheet" type="text/css" href="../../fonts/font-awesome-4.1.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="../../fonts/eleganticons/et-icons.css">
<link rel="stylesheet" type="text/css" href="../../css/jqtree.css">
<link rel="stylesheet" type="text/css" href="../../css/idea.css">
<link rel="stylesheet" type="text/css" href="../../css/cardio.css">
<script type="text/javascript">
<!-- Matomo -->
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_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', '5']);
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);
})();
<!-- End Matomo Code -->
</script>
</head>
<body>
<div class="preloader">
<img src="../../img/loader.gif" alt="Preloader image">
</div>
<nav class="navbar">
<div class="container">
<div class="row"> <div class="col-md-12">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/" title="Apache TomEE">
<span>
<img
src="../../img/apache_tomee-logo.svg"
onerror="this.src='../../img/apache_tomee-logo.jpg'"
height="50"
>
</span>
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right main-nav">
<li><a href="../../docs.html">Documentation</a></li>
<li><a href="../../community/index.html">Community</a></li>
<li><a href="../../security/security.html">Security</a></li>
<li><a class="btn btn-accent accent-orange no-shadow" href="../../download.html">Downloads</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div></div>
</div>
<!-- /.container-fluid -->
</nav>
<div id="main-block" class="container main-block">
<div class="row title">
<div class="col-md-12">
<div class='page-header'>
<h1>Jakarta Security with Tomcat tomcat-users.xml identity store</h1>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>TomEE has its own independent Jakarta Security implementation <a href="https://eclipse-ee4j.github.io/security-api/" class="bare">https://eclipse-ee4j.github.io/security-api/</a> .</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Jakarta Security defines a standard for creating secure Jakarta EE applications in modern application paradigms. It defines an overarching (end-user targeted) Security API for Jakarta EE Applications.</p>
</div>
<div class="paragraph">
<p>Jakarta Security builds on the lower level Security SPIs defined by Jakarta Authentication and Jakarta Authorization, which are both not end-end targeted.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This example focuses in showing how to leverage Jakarta Security in TomEE with Tomcat&#8217;s tomcat-users.xml.
TomEE out of the box supports it as an identity store.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_implement_a_simple_jax_rs_application">Implement a simple JAX-RS application</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This movie example has 2 resources, one of them <code>MovieAdminResource</code> is a protected resource to ensure only admin users can add or delete movies.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;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"
&gt;
&lt;!-- Security constraints --&gt;
&lt;security-constraint&gt;
&lt;web-resource-collection&gt;
&lt;web-resource-name&gt;Protected admin resource/url&lt;/web-resource-name&gt;
&lt;url-pattern&gt;/api/movies/*&lt;/url-pattern&gt;
&lt;http-method-omission&gt;GET&lt;/http-method-omission&gt;
&lt;/web-resource-collection&gt;
&lt;auth-constraint&gt;
&lt;role-name&gt;admin&lt;/role-name&gt;
&lt;/auth-constraint&gt;
&lt;/security-constraint&gt;
&lt;/web-app&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_defining_identity_store_and_authentication_mechanism">Defining identity store and authentication mechanism</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Jakarta Security requires 2 things to authenticate a user</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the identity store (aka <code>tomcat-users.xml</code> in this case): this is basically where users are stored with their user
name, password, and the roles</p>
</li>
<li>
<p>the authentication mechanism: how the credentials are passed in.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In this example, we want to use <code>tomcat-users.xml</code> identity store and basic authentication.
We can define that in the resource itself using 2 annotations</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">@Path("/movies")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@TomcatUserIdentityStoreDefinition
@BasicAuthenticationMechanismDefinition
@ApplicationScoped
public class MovieAdminResource {
private static final Logger LOGGER = Logger.getLogger(MovieAdminResource.class.getName());
@Inject
private MovieStore store;
// JAXRS security context also wired with Jakarta Security
@Context
private javax.ws.rs.core.SecurityContext securityContext;
@POST
public Movie addMovie(final Movie newMovie) {
LOGGER.info(getUserName() + " adding new movie " + newMovie);
return store.addMovie(newMovie);
}
// See source file for full content
private String getUserName() {
if (securityContext.getUserPrincipal() != null) {
return String.format("%s[admin=%s]",
securityContext.getUserPrincipal().getName(),
securityContext.isUserInRole("admin"));
}
return null;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>IMPORTANT:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="paragraph">
<p>In TomEE, Jakarta Security is wired in all layers, you can use</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>javax.ws.rs.core.SecurityContext#getUserPrincipal</code> and <code>isUserInRole</code> to get the User Principal and check if the user has a given role</p>
</li>
<li>
<p><code>javax.security.enterprise.SecurityContext#getCallerPrincipal</code> and <code>isCallerInRole</code> to get the Caller Principal (notice the difference in terms of naming) and check if a caller has a given role</p>
</li>
<li>
<p><code>javax.servlet.http.HttpServletRequest#getUserPrincipal</code> and <code>isUserInRole</code></p>
</li>
<li>
<p><code>javax.ejb.SessionContext#getCallerPrincipal</code> and <code>isCallerInRole</code></p>
</li>
<li>
<p>the <code>Subject</code> from the <code>PolicyContext</code> but this is less used</p>
</li>
</ul>
</div>
</div>
</div>
<div class="paragraph">
<p>A lot of different APIs to retrieve the principal and check whereas it has a given role.
It&#8217;s all wired in and consistent in TomEE. No special configuration is needed.</p>
</div>
<div class="paragraph">
<p>Finally, <code>MovieResource</code> does not require any authentication or user permissions, but for logging purposes in this test, it will use the Jakarta Security <code>SecurityContext</code> to grab the caller principal and do some role checks.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_add_users_to_the_regular_tomcat_users_xml">Add users to the regular <code>tomcat-users.xml</code></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The file location is by default <code>${catalina.base}/conf</code>.
The file can be located anywhere.
If you are not using the default location, make sure to update the <code>server.xml</code> accordingly.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;tomcat-users&gt;
&lt;user name="tomcat" password="tomcat" roles="tomcat"/&gt;
&lt;user name="user" password="user" roles="user"/&gt;
&lt;user name="tom" password="secret1" roles="admin,manager"/&gt;
&lt;user name="emma" password="secret2" roles="admin,employee"/&gt;
&lt;user name="bob" password="secret3" roles="admin"/&gt;
&lt;/tomcat-users&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_running">Running</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Were we to run the above Main class or Test Case we&#8217;d see output like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">INFOS: Service URI: http://localhost:56147/api/movies -&gt; Pojo org.superbiz.movie.MovieAdminResource
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: DELETE http://localhost:56147/api/movies/{id} -&gt; Movie deleteMovie(int)
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: POST http://localhost:56147/api/movies -&gt; Movie addMovie(Movie)
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: Service URI: http://localhost:56147/api/movies -&gt; Pojo org.superbiz.movie.MovieResource
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: GET http://localhost:56147/api/movies -&gt; List&lt;Movie&gt; getAllMovies()
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: GET http://localhost:56147/api/movies/{id} -&gt; Movie getMovie(int)
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: Service URI: http://localhost:56147/api/openapi -&gt; Pojo org.apache.geronimo.microprofile.openapi.jaxrs.OpenAPIEndpoint
juin 15, 2021 3:48:32 PM org.apache.openejb.server.cxf.rs.CxfRsHttpListener logEndpoints
INFOS: GET http://localhost:56147/api/openapi -&gt; OpenAPI get()
juin 15, 2021 3:48:32 PM sun.reflect.DelegatingMethodAccessorImpl invoke
INFOS: Deployment of web application directory [/private/var/folders/03/fjcmr3cs2rnbtfcqd9w1nntc0000gn/T/temp2373416631427015263dir/apache-tomee/webapps/ROOT] has finished in [15,655] ms
juin 15, 2021 3:48:32 PM sun.reflect.DelegatingMethodAccessorImpl invoke
INFOS: Starting ProtocolHandler ["http-nio-56147"]
juin 15, 2021 3:48:32 PM sun.reflect.DelegatingMethodAccessorImpl invoke
INFOS: Server startup in [15904] milliseconds
juin 15, 2021 3:48:32 PM sun.reflect.DelegatingMethodAccessorImpl invoke
INFOS: Full bootstrap in [22621] milliseconds
juin 15, 2021 3:48:33 PM org.superbiz.movie.MovieAdminResource addMovie
INFOS: tom[admin=true] adding new movie Movie{title='Shanghai Noon', director='Tom Dey', genre='Comedy', id=7, year=2000}
juin 15, 2021 3:48:34 PM org.superbiz.movie.MovieResource getAllMovies
INFOS: tomcat[admin=false] reading movies
juin 15, 2021 3:48:34 PM org.superbiz.movie.MovieResource getAllMovies
INFOS: null reading movies
juin 15, 2021 3:48:34 PM org.superbiz.movie.MovieResource getAllMovies
INFOS: emma[admin=true] reading movies
juin 15, 2021 3:48:34 PM org.superbiz.movie.MovieResource getMovie
INFOS: bob[admin=true] reading movie 2 / Movie{title='Starsky &amp; Hutch', director='Todd Phillips', genre='Action', id=2, year=2004}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_apis_used">APIs Used</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="../../tomee-8.0/javadoc/org/apache/tomee/bootstrap/Archive.html">org.apache.tomee.bootstrap.Archive</a></p>
</li>
<li>
<p><a href="../../tomee-8.0/javadoc/org/apache/tomee/bootstrap/Server.html">org.apache.tomee.bootstrap.Server</a></p>
</li>
<li>
<p><a href="../../tomee-8.0/javadoc/org/apache/tomee/security/cdi/TomcatUserIdentityStoreDefinition.html">org.apache.tomee.security.cdi.TomcatUserIdentityStoreDefinition</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/annotation/PostConstruct.html">javax.annotation.PostConstruct</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/annotation/security/DeclareRoles.html">javax.annotation.security.DeclareRoles</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/security/enterprise/SecurityContext.html">javax.security.enterprise.SecurityContext</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/security/enterprise/authentication/mechanism/http/BasicAuthenticationMechanismDefinition.html">javax.security.enterprise.authentication.mechanism.http.BasicAuthenticationMechanismDefinition</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/ApplicationPath.html">javax.ws.rs.ApplicationPath</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/Consumes.html">javax.ws.rs.Consumes</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/DELETE.html">javax.ws.rs.DELETE</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/GET.html">javax.ws.rs.GET</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/POST.html">javax.ws.rs.POST</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/Path.html">javax.ws.rs.Path</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/PathParam.html">javax.ws.rs.PathParam</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/Produces.html">javax.ws.rs.Produces</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/client/ClientBuilder.html">javax.ws.rs.client.ClientBuilder</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/client/ClientRequestContext.html">javax.ws.rs.client.ClientRequestContext</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/client/ClientRequestFilter.html">javax.ws.rs.client.ClientRequestFilter</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/client/Entity.html">javax.ws.rs.client.Entity</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/client/WebTarget.html">javax.ws.rs.client.WebTarget</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/core/Application.html">javax.ws.rs.core.Application</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/core/Context.html">javax.ws.rs.core.Context</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/core/HttpHeaders.html">javax.ws.rs.core.HttpHeaders</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/core/MediaType.html">javax.ws.rs.core.MediaType</a></p>
</li>
<li>
<p><a href="../../jakartaee-8.0/javadoc/javax/ws/rs/core/SecurityContext.html">javax.ws.rs.core.SecurityContext</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="margin-bottom: 30px;"></div>
<footer>
<div class="container">
<div class="row">
<div class="col-sm-6 text-center-mobile">
<h3 class="white">Be simple. Be certified. Be Tomcat.</h3>
<h5 class="light regular light-white">"A good application in a good server"</h5>
<ul class="social-footer">
<li><a href="https://www.facebook.com/ApacheTomEE/"><i class="fa fa-facebook"></i></a></li>
<li><a href="https://twitter.com/apachetomee"><i class="fa fa-twitter"></i></a></li>
</ul>
<h5 class="light regular light-white">
<a href="../../privacy-policy.html" class="white">Privacy Policy</a>
</h5>
</div>
<div class="col-sm-6 text-center-mobile">
<div class="row opening-hours">
<div class="col-sm-3 text-center-mobile">
<h5><a href="../../latest/docs/" class="white">Documentation</a></h5>
<ul class="list-unstyled">
<li><a href="../../latest/docs/admin/configuration/index.html" class="regular light-white">How to configure</a></li>
<li><a href="../../latest/docs/admin/file-layout.html" class="regular light-white">Dir. Structure</a></li>
<li><a href="../../latest/docs/developer/testing/index.html" class="regular light-white">Testing</a></li>
<li><a href="../../latest/docs/admin/cluster/index.html" class="regular light-white">Clustering</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../../latest/examples/" class="white">Examples</a></h5>
<ul class="list-unstyled">
<li><a href="../../latest/examples/simple-cdi-interceptor.html" class="regular light-white">CDI Interceptor</a></li>
<li><a href="../../latest/examples/rest-cdi.html" class="regular light-white">REST with CDI</a></li>
<li><a href="../../latest/examples/ejb-examples.html" class="regular light-white">EJB</a></li>
<li><a href="../../latest/examples/jsf-managedBean-and-ejb.html" class="regular light-white">JSF</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../../community/index.html" class="white">Community</a></h5>
<ul class="list-unstyled">
<li><a href="../../community/contributors.html" class="regular light-white">Contributors</a></li>
<li><a href="../../community/social.html" class="regular light-white">Social</a></li>
<li><a href="../../community/sources.html" class="regular light-white">Sources</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../../security/index.html" class="white">Security</a></h5>
<ul class="list-unstyled">
<li><a href="https://apache.org/security" target="_blank" class="regular light-white">Apache Security</a></li>
<li><a href="https://apache.org/security/projects.html" target="_blank" class="regular light-white">Security Projects</a></li>
<li><a href="https://cve.mitre.org" target="_blank" class="regular light-white">CVE</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="row bottom-footer text-center-mobile">
<div class="col-sm-12 light-white">
<p>Copyright &copy; 1999-2022 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. Apache TomEE, TomEE, Apache, the Apache feather logo, and the Apache TomEE project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.</p>
</div>
</div>
</div>
</footer>
<!-- Holder for mobile navigation -->
<div class="mobile-nav">
<ul>
<li><a hef="../../latest/docs/admin/index.html">Administrators</a>
<li><a hef="../../latest/docs/developer/index.html">Developers</a>
<li><a hef="../../latest/docs/advanced/index.html">Advanced</a>
<li><a hef="../../community/index.html">Community</a>
</ul>
<a href="#" class="close-link"><i class="arrow_up"></i></a>
</div>
<!-- Scripts -->
<script src="../../js/jquery-1.11.1.min.js"></script>
<script src="../../js/owl.carousel.min.js"></script>
<script src="../../js/bootstrap.min.js"></script>
<script src="../../js/wow.min.js"></script>
<script src="../../js/typewriter.js"></script>
<script src="../../js/jquery.onepagenav.js"></script>
<script src="../../js/tree.jquery.js"></script>
<script src="../../js/highlight.pack.js"></script>
<script src="../../js/main.js"></script>
</body>
</html>