Author: buildbot
Date: Fri Oct 23 14:42:54 2026
New Revision: 1094341
Log:
Production update by buildbot for cxf
Modified:
websites/production/cxf/content/cache/docs.pageCache
websites/production/cxf/content/docs/jax-rs-token-authorization.html
Modified: websites/production/cxf/content/cache/docs.pageCache
==============================================================================
Binary file (source and/or target). No diff available.
Modified: websites/production/cxf/content/docs/jax-rs-token-authorization.html
==============================================================================
--- websites/production/cxf/content/docs/jax-rs-token-authorization.html
Fri Oct 23 07:35:27 2026 (r1094340)
+++ websites/production/cxf/content/docs/jax-rs-token-authorization.html
Fri Oct 23 14:42:54 2026 (r1094341)
@@ -28,16 +28,6 @@
<meta name="description" content="Apache CXF, Services Framework - JAX-RS
Token Authorization">
-<link type="text/css" rel="stylesheet"
href="/resources/highlighter/styles/shCoreCXF.css">
-<link type="text/css" rel="stylesheet"
href="/resources/highlighter/styles/shThemeCXF.css">
-
-<script src='/resources/highlighter/scripts/shCore.js'></script>
-<script src='/resources/highlighter/scripts/shBrushXml.js'></script>
-<script src='/resources/highlighter/scripts/shBrushJava.js'></script>
-<script>
- SyntaxHighlighter.defaults['toolbar'] = false;
- SyntaxHighlighter.all();
-</script>
<title>
@@ -95,7 +85,8 @@ Apache CXF -- JAX-RS Token Authorization
<div id="wrapper-menu-page-bottom">
<div id="menu-page">
<!-- NavigationBar -->
-<div id="navigation"><ul class="alternate"><li><a shape="rect"
href="overview.html">Overview</a></li><li><a shape="rect"
href="how-tos.html">How-Tos</a></li><li><a shape="rect"
href="frontends.html">Frontends</a></li><li><a shape="rect"
href="databindings.html">DataBindings</a></li><li><a shape="rect"
href="transports.html">Transports</a></li><li><a shape="rect"
href="configuration.html">Configuration</a></li><li><a shape="rect"
href="debugging-and-logging.html">Debugging and Logging</a></li><li><a
shape="rect" href="tools.html">Tools</a></li><li><a shape="rect"
href="restful-services.html">RESTful Services</a></li><li><a shape="rect"
href="wsdl-bindings.html">WSDL Bindings</a></li><li><a shape="rect"
href="service-routing.html">Service Routing</a></li><li><a shape="rect"
href="dynamic-languages.html">Dynamic Languages</a></li><li><a shape="rect"
href="ws-support.html">WS-* Support</a></li><li><a shape="rect"
href="advanced-integration.html">Advanced Integration</a></li><li><a shape
="rect" href="deployment.html">Deployment</a></li><li><a shape="rect"
href="schemas-and-namespaces.html">Use of Schemas and Namespaces</a></li><li><a
shape="rect" href="securing-cxf-services.html">Securing CXF
Services</a></li></ul><hr><ul
class="alternate"><li><p>Search</p></li></ul><iframe frameborder="1"
scrolling="auto" id="searchId"
src="https://cxf.apache.org/resources/search.htm" name="SearchIFrame"
width="200px" style="border:none;" title="Search" height="60px"><p><br
clear="none"></p></iframe>
+<div id="navigation"><ul class="alternate"><li><a shape="rect"
href="overview.html">Overview</a></li><li><a shape="rect"
href="how-tos.html">How-Tos</a></li><li><a shape="rect"
href="frontends.html">Frontends</a></li><li><a shape="rect"
href="databindings.html">DataBindings</a></li><li><a shape="rect"
href="transports.html">Transports</a></li><li><a shape="rect"
href="configuration.html">Configuration</a></li><li><a shape="rect"
href="debugging-and-logging.html">Debugging and Logging</a></li><li><a
shape="rect" href="tools.html">Tools</a></li><li><a shape="rect"
href="restful-services.html">RESTful Services</a></li><li><a shape="rect"
href="wsdl-bindings.html">WSDL Bindings</a></li><li><a shape="rect"
href="service-routing.html">Service Routing</a></li><li><a shape="rect"
href="dynamic-languages.html">Dynamic Languages</a></li><li><a shape="rect"
href="ws-support.html">WS-* Support</a></li><li><a shape="rect"
href="advanced-integration.html">Advanced Integration</a></li><li><a shape
="rect" href="deployment.html">Deployment</a></li><li><a shape="rect"
href="schemas-and-namespaces.html">Use of Schemas and Namespaces</a></li><li><a
shape="rect" href="securing-cxf-services.html">Securing CXF
Services</a></li></ul><hr><ul class="alternate"><li><p>Search</p></li></ul>
+<iframe frameborder="1" scrolling="auto" id="searchId"
src="https://cxf.apache.org/resources/search.htm" sandbox="sandbox"
name="SearchIFrame" width="200px" style="border:none;" title="Search"
height="60px"></iframe>
<hr><ul class="alternate"><li><a shape="rect"
href="http://cxf.apache.org/javadoc/latest-4.0.x/">API 4.0.x
(Javadoc)</a></li><li><a shape="rect"
href="http://cxf.apache.org/javadoc/latest-3.6.x/">API 3.6.x
(Javadoc)</a></li><li><a shape="rect"
href="http://cxf.apache.org/javadoc/latest-3.5.x/">API 3.5.x
(Javadoc)</a></li><li><a shape="rect" href="http://cxf.apache.org/">CXF
Website</a></li></ul><p><br clear="none"></p><p><a shape="rect"
class="external-link" href="https://www.apache.org/events/current-event.html">
<span class="confluence-embedded-file-wrapper"><img
class="confluence-embedded-image confluence-external-resource"
draggable="false" src="https://www.apache.org/events/current-event-125x125.png"
data-image-src="https://www.apache.org/events/current-event-125x125.png"></span>
</a></p></div>
@@ -108,90 +99,83 @@ Apache CXF -- JAX-RS Token Authorization
<td height="100%">
<!-- Content -->
<div class="wiki-content">
-<div id="ConfluenceContent"><p> <span
style="font-size:2em;font-weight:bold">JAX-RS: Token Authorization</span>
+<div id="ConfluenceContent"><p><br clear="none">
+<span style="font-size:2em;font-weight:bold">JAX-RS: Token Authorization</span>
<br clear="none"></p><p><style type="text/css">/*<![CDATA[*/
-div.rbtoc1693928618442 {padding: 0px;}
-div.rbtoc1693928618442 ul {margin-left: 0px;}
-div.rbtoc1693928618442 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1792766567529 {padding: 0px;}
+div.rbtoc1792766567529 ul {margin-left: 0px;}
+div.rbtoc1792766567529 li {margin-left: 0px;padding-left: 0px;}
-/*]]>*/</style></p><div class="toc-macro rbtoc1693928618442">
-<ul class="toc-indentation"><li><a shape="rect"
href="#JAXRSTokenAuthorization-Introduction">Introduction</a></li><li><a
shape="rect"
href="#JAXRSTokenAuthorization-Backwardscompatibilityconfigurationnote">Backwards
compatibility configuration note</a></li><li><a shape="rect"
href="#JAXRSTokenAuthorization-Mavendependencies">Maven
dependencies</a></li><li><a shape="rect"
href="#JAXRSTokenAuthorization-Claimsbasedaccesscontrol">Claims based access
control</a>
+/*]]>*/</style></p><div class="toc-macro rbtoc1792766567529">
+<ul class="toc-indentation"><li><a shape="rect"
href="#JAXRSTokenAuthorization-Introduction">Introduction</a></li><li><a
shape="rect" href="#JAXRSTokenAuthorization-Mavendependencies">Maven
dependencies</a></li><li><a shape="rect"
href="#JAXRSTokenAuthorization-Claimsbasedaccesscontrol">Claims based access
control</a>
<ul class="toc-indentation"><li><a shape="rect"
href="#JAXRSTokenAuthorization-Claimsannotations">Claims
annotations</a></li><li><a shape="rect"
href="#JAXRSTokenAuthorization-EnforcingClaimsauthorization">Enforcing Claims
authorization</a></li></ul>
</li><li><a shape="rect"
href="#JAXRSTokenAuthorization-Rolebasedaccesscontrol">Role based access
control</a>
<ul class="toc-indentation"><li><a shape="rect"
href="#JAXRSTokenAuthorization-SimpleAuthorizingInterceptor">SimpleAuthorizingInterceptor</a></li><li><a
shape="rect" href="#JAXRSTokenAuthorization-Usingannotations">Using
annotations</a></li></ul>
</li></ul>
-</div><h1 id="JAXRSTokenAuthorization-Introduction">Introduction</h1><p>CXF
JAX-RS offers an extension letting users to enforce a new fine-grained Claims
Based Access Control (CBAC) based on <a shape="rect" class="external-link"
href="https://github.com/apache/cxf/blob/master/core/src/main/java/org/apache/cxf/security/claims/authorization/Claim.java"
rel="nofollow">Claim</a> and <a shape="rect" class="external-link"
href="https://github.com/apache/cxf/blob/master/core/src/main/java/org/apache/cxf/security/claims/authorization/Claims.java"
rel="nofollow">Claims</a> annotations as well as <a shape="rect"
class="external-link"
href="https://github.com/apache/cxf/blob/master/core/src/main/java/org/apache/cxf/security/claims/authorization/ClaimMode.java"
rel="nofollow">ClaimMode</a> enum class. It works with SAML tokens and with
JWT tokens (from the 3.3.0 release onwards).</p><p>See also <a shape="rect"
href="jax-rs-xml-security.html">JAX-RS XML Security</a>, <a shape="rect"
href="jax-rs
-saml.html">JAX-RS SAML</a> and <a shape="rect" href="jax-rs-jose.html">JAX-RS
JOSE</a>.</p><h1
id="JAXRSTokenAuthorization-Backwardscompatibilityconfigurationnote">Backwards
compatibility configuration note</h1><p>From Apache CXF 3.1.0, the WS-Security
based configuration tags used to configure XML Signature or Encryption
("ws-security-*") have been changed to just start with "security-". Apart from
this they are exactly the same. Older "ws-security-" values continue to be
accepted in CXF 3.1.0. To use any of the configuration examples in this page
with an older version of CXF, simply add a "ws-" prefix to the configuration
tag.</p><p>The package for Claim, Claims and ClaimMode annotations has changed
from "org.apache.cxf.rs.security.saml.authorization" to
"org.apache.cxf.security.claims.authorization". Starting from CXF 2.7.1, the
default name format for claims is
"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified" instead of "<a
shape="rect" class="external-link" href="http
://schemas.xmlsoap.org/ws/2005/05/identity/claims"
rel="nofollow">http://schemas.xmlsoap.org/ws/2005/05/identity/claims</a>".</p><p>From
the 3.3.0 release, the Claims access control annotations/interceptors <a
shape="rect" class="external-link"
href="https://issues.apache.org/jira/browse/CXF-6727">now work</a> with JWT
tokens (as well as SAML tokens). This resulted in the following package
changes:</p><ul><li>ClaimsAuthorizingInterceptor has moved from the
cxf-rt-security-saml module to the cxf-rt-security module. The package name of
the ClaimsAuthorizingInterceptor has changed: from
org.apache.cxf.rt.security.saml.interceptor.ClaimsAuthorizingInterceptor to
org.apache.cxf.rt.security.claims.interceptor.ClaimsAuthorizingInterceptor.</li><li>ClaimsAuthorizingFilter
has moved from the cxf-rt-rs-security-xml module to the cxf-rt-frontend-jaxrs
module. The package name of the ClaimsAuthorizingFilter  has changed: from
org.apache.cxf.rs.security.saml.authorization.ClaimsAuthorizingF
ilter
to org.apache.cxf.jaxrs.security.ClaimsAuthorizingFilter</li></ul><h1
id="JAXRSTokenAuthorization-Mavendependencies">Maven dependencies</h1><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"><dependency>
+</div><h2 id="JAXRSTokenAuthorization-Introduction">Introduction</h2><p>CXF
JAX-RS offers an extension that lets users enforce fine-grained Claims Based
Access Control (CBAC) using the <code>Claim</code> and <code>Claims</code>
annotations and the <code>ClaimMode</code> enum. It works with both SAML and
JWT tokens.</p><p>See also <a shape="rect"
href="jax-rs-xml-security.html">JAX-RS XML Security</a>, <a shape="rect"
href="jax-rs-saml.html">JAX-RS SAML</a> and <a shape="rect"
href="jax-rs-jose.html">JAX-RS JOSE</a>.</p><h2
id="JAXRSTokenAuthorization-Mavendependencies">Maven
dependencies</h2><pre><code class="language-xml"><dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-security</artifactId>
- <version>3.3.0</version>
+ <version>${cxf.version}</version>
</dependency>
-</pre>
-</div></div><p>In addition, cxf-rt-rs-security-xml is required if you are
working with SAML tokens, and cxf-rt-rs-security-jose-jaxrs is required if you
are working with JWT tokens.</p><h1
id="JAXRSTokenAuthorization-Claimsbasedaccesscontrol">Claims based access
control</h1><h2 id="JAXRSTokenAuthorization-Claimsannotations">Claims
annotations</h2><p>Here is a simple code fragment to secure a service object
using Claims annotations:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default">import
org.apache.cxf.security.claims.authorization.Claim;
+</code></pre><p>In addition, <code>cxf-rt-rs-security-xml</code> is required
if you are working with SAML tokens, and
<code>cxf-rt-rs-security-jose-jaxrs</code> is required if you are working with
JWT tokens. <code>ClaimsAuthorizingFilter</code> and
<code>SimpleAuthorizingFilter</code> are in
<code>cxf-rt-frontend-jaxrs</code>.</p><h2
id="JAXRSTokenAuthorization-Claimsbasedaccesscontrol">Claims based access
control</h2><h3 id="JAXRSTokenAuthorization-Claimsannotations">Claims
annotations</h3><p>The <code>Claim</code>, <code>Claims</code> and
<code>ClaimMode</code> types live in the
<code>org.apache.cxf.security.claims.authorization</code> package. Here is a
simple code fragment that secures a service object using Claims
annotations:</p><pre><code class="language-java">import
org.apache.cxf.security.claims.authorization.Claim;
import org.apache.cxf.security.claims.authorization.Claims;
@Path("/bookstore")
public class SecureClaimBookStore {
-
+
@POST
@Path("/books")
@Produces("application/xml")
@Consumes("application/xml")
- @Claims({
+ @Claims({
@Claim({"admin" }),
- @Claim(name = "http://claims/authentication-format",
- format = "http://claims/authentication",
+ @Claim(name = "http://claims/authentication-format",
+ format = "http://claims/authentication",
value = {"fingertip", "smartcard" })
})
public Book addBook(Book book) {
return book;
}
-
}
-</pre>
-</div></div><p>SecureClaimBookStore.addBook(Book) can only be invoked if
Subject meets the following requirement: it needs to have a Claim with a value
"admin" and another Claim confirming that it got authenticated using either a
'fingertip' or 'smartcard' method. Note that @Claim({"admin"}) has no name and
format classifiers set - it relies on default name and format values, namely
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" and
"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
("http://schemas.xmlsoap.org/ws/2005/05/identity/claims" before CXF 2.7.1)
respectively. These default values may change in the future depending on which
claims are found to be used most often - but as you can see you can always
provide name and format values which will scope a given claim value.</p><p>Note
that in the above example, a Claim with the name
"http://claims/authentication-format" has two values, 'fingertip' and
'smartcard'. By default, in order to meet this Claim, Subjec
t needs to have a Claim which has either a 'fingertip' or 'smartcard' value.
If it is expected that Subject needs to have a Claim which has both 'fingertip'
and 'smartcard' values, then the following change needs to be done:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default">import
org.apache.cxf.security.claims.authorization.Claim;
+</code></pre><p><code>SecureClaimBookStore.addBook(Book)</code> can only be
invoked if the Subject meets the following requirements: it must have a Claim
with the value "admin", and another Claim confirming that it was authenticated
using either the 'fingertip' or the 'smartcard' method.</p><p>Note that
<code>@Claim({"admin"})</code> has no name or format set, so it relies on the
default values:</p><ul><li>name:
<code>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</code></li><li>format:
<code>urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified</code></li></ul><p>You
can always set <code>name</code> and <code>format</code> explicitly to scope a
given claim value.</p><p><strong>SAML vs JWT matching.</strong> For SAML
tokens, a Claim matches a SAML attribute only if both the name and the
NameFormat are equal. For JWT tokens, the format is ignored and the Claim name
is compared with the JWT claim name as it appears in the token. A JWT carrying
<code>"role": "admin"</code
> therefore does <strong>not</strong> match <code>@Claim({"admin"})</code>,
> because the default name is the SAML role URI. Use <code>@Claim(name =
> "role", value = {"admin"})</code>, or map the name with
> <code>nameAliases</code> (see below).</p><p>In the example above, the Claim
> named "http://claims/authentication-format" has two values, 'fingertip' and
> 'smartcard'. By default, to meet this Claim the Subject needs a Claim with
> either value. If the Subject must have both values, set <code>matchAll =
> true</code>:</p><pre><code class="language-java">import
> org.apache.cxf.security.claims.authorization.Claim;
import org.apache.cxf.security.claims.authorization.Claims;
@Path("/bookstore")
public class SecureClaimBookStore {
-
+
@POST
@Path("/books")
@Produces("application/xml")
@Consumes("application/xml")
- @Claims({
+ @Claims({
@Claim({"admin" }),
- @Claim(name = "http://claims/authentication-format",
- format = "http://claims/authentication",
+ @Claim(name = "http://claims/authentication-format",
+ format = "http://claims/authentication",
value = {"fingertip", "smartcard" },
matchAll = true)
})
public Book addBook(Book book) {
return book;
}
-
}
-</pre>
-</div></div><p>Claims can be specified using individual @Claim annotation,
they can be set at the class level and overridden at the method level and
finally a lax mode of check can be specified:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default">import
org.apache.cxf.security.claims.authorization.Claim;
+</code></pre><p>Claims can be specified using an individual
<code>@Claim</code> annotation. They can be set at class level and overridden
at method level, and a lax mode of check can be specified:</p><pre><code
class="language-java">import org.apache.cxf.security.claims.authorization.Claim;
+import org.apache.cxf.security.claims.authorization.ClaimMode;
import org.apache.cxf.security.claims.authorization.Claims;
@Path("/bookstore")
@Claim({"user"})
public class SecureClaimBookStore {
-
+
@POST
@Path("/books")
@Produces("application/xml")
@Consumes("application/xml")
- @Claims({
+ @Claims({
@Claim({"admin" }),
- @Claim(name = "http://claims/authentication-format",
- format = "http://claims/authentication",
+ @Claim(name = "http://claims/authentication-format",
+ format = "http://claims/authentication",
value = {"fingertip", "smartcard" },
matchAll = true)
})
@@ -200,10 +184,10 @@ public class SecureClaimBookStore {
}
@GET
- @Claim(name = "http://claims/authentication-format",
- format = "http://claims/authentication",
- value = {"password" },
- mode = ClaimMode.LAX)
+ @Claim(name = "http://claims/authentication-format",
+ format = "http://claims/authentication",
+ value = {"password" },
+ mode = ClaimMode.LAX)
public Book getBook() {
//...
}
@@ -212,70 +196,117 @@ public class SecureClaimBookStore {
public BookList getBookList() {
//...
}
-
-
}
-</pre>
-</div></div><p>In the above example, getBookList() can be invoked if Subject
has a Claim with the value "user"; addBook() has it overridden - "admin" is
expected and the authentication format Claim too; getBook() can be invoked if
Subject has a Claim with the value "user" and it also must have the
authentication format Claim with the value "password" - or no such Claim at
all.</p><p>org.apache.cxf.rt.security.claims.interceptor.ClaimsAuthorizingInterceptor
("org.apache.cxf.rt.security.saml.interceptor.ClaimsAuthorizingInterceptor"
before CXF 3.3.0) enforces the CBAC rules. This filter can be overridden and
configured with the rules directly which can be useful if no Claim-related
annotations are expected in the code. Map nameAliases and formatAliases
properties are supported to make @Claim annotations look a bit simpler, for
example:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default">@Claim(name =
"auth-format", format = "authentication", value = {"password" })
-</pre>
-</div></div><p>where "auth-format" and "authentication" are aliases for
"http://claims/authentication-format" and "http://claims/authentication"
respectively.</p><h2
id="JAXRSTokenAuthorization-EnforcingClaimsauthorization">Enforcing Claims
authorization</h2><p>Simply adding Claims annotations are per the examples
above is not sufficient to enforce claims based authorization.</p><p>First we
need to configure the appropriate interceptors/filters to authenticate the type
of token we are interested in extracting claims from. See the <a shape="rect"
href="jax-rs-saml.html">JAX-RS SAML</a> page for information on how to
configure SAML, and the <a shape="rect" href="jax-rs-jose.html">JAX-RS JOSE</a>
page for information on how to configure JWT.</p><p>For both SAML and JWT, once
the incoming token is validated, a <a shape="rect" class="external-link"
href="https://github.com/apache/cxf/blob/master/rt/security/src/main/java/org/apache/cxf/rt/security/claims/ClaimsSecurityContext.java"
rel="
nofollow">ClaimsSecurityContext</a> security context will be created
containing the claims contained in the token, as well as the authenticated
subject and role (claims).</p><p>To enforce claims authorization, a <a
shape="rect" class="external-link"
href="https://github.com/apache/cxf/blob/master/rt/security/src/main/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptor.java"
rel="nofollow">ClaimsAuthorizingInterceptor</a> must be set as an
"inInterceptor", passing it a reference to the secured object. There is also a
JAX-RS filter wrapper around ClaimsAuthorizingInterceptor available, which is
called <a shape="rect" class="external-link"
href="https://github.com/apache/cxf/blob/master/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/ClaimsAuthorizingFilter.java"
rel="nofollow">ClaimsAuthorizingFilter</a>.</p><p>An instance of
org.apache.cxf.rs.security.saml.authorization.ClaimsAuthorizingFilter (note
org.apache.cxf.rs.security.claims.ClaimsAut
horizingFilter from CXF 3.3.0) is used to enforce CBAC. It's a simple JAX-RS
filter wrapper around ClaimsAuthorizingInterceptor.</p><p>Here is an example of
enforcing Claims authorization against a JWT token. BookStoreAuthn is the
service object which is annotated with Claims annotations. The
ClaimsAuthorizingFilter is added as a JAX-RS provider to the endpoint, wrapping
the serviceBean. A JwtAuthenticationFilter instance is also added to validate
the received JWT token and to set up the ClaimsSecurityContext. The <a
shape="rect" class="external-link" href="http://rs.security.signature.in"
rel="nofollow">rs.security.signature.in</a>.properties property is used to
verify the signature on the received token.</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"><bean
id="serviceBean"
class="org.apache.cxf.systest.jaxrs.security.jose.jwt.BookStoreAuthn"/>
+</code></pre><p>In the above example:</p><ul><li><code>getBookList()</code>
can be invoked if the Subject has a Claim with the value
"user".</li><li><code>addBook()</code> overrides the class-level Claim: "admin"
is expected instead of "user", together with the authentication format Claim. A
method-level Claim replaces a class-level Claim only when both have the same
name and format; class-level Claims with a different name or format still
apply.</li><li><code>getBook()</code> can be invoked if the Subject has a Claim
with the value "user". In addition, if it has an authentication format Claim,
that Claim must have the value "password". With <code>ClaimMode.LAX</code>, a
missing Claim is accepted; only a Claim that is present with non-matching
values fails.</li></ul><p>Methods that have no Claims annotations, either on
the method or on the class, are not restricted by
<code>ClaimsAuthorizingInterceptor</code>.</p><p><code>org.apache.cxf.rt.security.claims.interceptor.ClaimsAuthorizi
ngInterceptor</code> enforces the CBAC rules. It can also be configured with
the rules directly, using its <code>claims</code> property, which is useful if
no Claim annotations are expected in the code. The <code>nameAliases</code> and
<code>formatAliases</code> map properties are supported to make
<code>@Claim</code> annotations look a bit simpler, for example:</p><pre><code
class="language-java">@Claim(name = "auth-format", format = "authentication",
value = {"password" })
+</code></pre><p>where "auth-format" and "authentication" are aliases for
"http://claims/authentication-format" and "http://claims/authentication"
respectively.</p><p>Aliases are resolved when <code>securedObject</code> is
set, so set <code>nameAliases</code> and <code>formatAliases</code> on the
interceptor <strong>before</strong> <code>securedObject</code>. Otherwise the
aliases are not applied, and rules using them will not match as
intended.</p><h3
id="JAXRSTokenAuthorization-EnforcingClaimsauthorization">Enforcing Claims
authorization</h3><p>Adding Claims annotations as in the examples above is not
enough on its own to enforce claims based authorization.</p><p>First, configure
the interceptors/filters that authenticate the type of token you want to
extract claims from. See the <a shape="rect" href="jax-rs-saml.html">JAX-RS
SAML</a> page for configuring SAML, and the <a shape="rect"
href="jax-rs-jose.html">JAX-RS JOSE</a> page for configuring JWT.</p><p>For
both SAML and JWT, onc
e the incoming token is validated, a <code>ClaimsSecurityContext</code> is
created. It contains the claims from the token, the authenticated subject, and
the roles. For SAML, a security context is only created if the assertion is
signed, unless <code>security.enable.unsigned-saml-assertion.principal</code>
is set to <code>true</code>. If there is no <code>ClaimsSecurityContext</code>,
<code>ClaimsAuthorizingInterceptor</code> rejects the request.</p><p>To enforce
claims authorization, create a <code>ClaimsAuthorizingInterceptor</code> and
pass it a reference to the secured object. Then either add it as an
"inInterceptor", or wrap it in the JAX-RS filter
<code>org.apache.cxf.jaxrs.security.ClaimsAuthorizingFilter</code> by passing
it as a constructor argument. A failed check through the filter returns HTTP
403.</p><p>Here is an example of enforcing Claims authorization against a JWT
token. <code>BookStoreAuthn</code> is the service object annotated with Claims
annotations. The <code>
ClaimsAuthorizingFilter</code> wraps a
<code>ClaimsAuthorizingInterceptor</code> configured with the service bean, and
is added as a JAX-RS provider. A <code>JwtAuthenticationFilter</code> validates
the received JWT token and sets up the <code>ClaimsSecurityContext</code>. The
<code>rs.security.signature.in.properties</code> property is used to verify the
signature on the received token.</p><pre><code class="language-xml"><bean
id="serviceBean"
class="org.apache.cxf.systest.jaxrs.security.jose.jwt.BookStoreAuthn"/>
-<bean id="claimsHandler"
class="org.apache.cxf.jaxrs.security.ClaimsAuthorizingFilter">
+<bean id="claimsInterceptor"
+
class="org.apache.cxf.rt.security.claims.interceptor.ClaimsAuthorizingInterceptor">
<property name="securedObject" ref="serviceBean"/>
</bean>
+<bean id="claimsHandler"
class="org.apache.cxf.jaxrs.security.ClaimsAuthorizingFilter">
+ <constructor-arg ref="claimsInterceptor"/>
+</bean>
+
<bean id="jwtAuthzFilter"
class="org.apache.cxf.rs.security.jose.jaxrs.JwtAuthenticationFilter">
<property name="roleClaim" value="role"/>
</bean>
<jaxrs:server
address="https://localhost:${testutil.ports.jaxrs-jwt-authn-authz}/signedjwtauthz">
- <jaxrs:serviceBeans>
- <ref bean="serviceBean"/>
- </jaxrs:serviceBeans>
- <jaxrs:providers>
- <ref bean="jwtAuthzFilter"/>
- <ref bean="claimsHandler"/>
- </jaxrs:providers>
- <jaxrs:properties>
- <entry key="rs.security.signature.in.properties"
-
value="org/apache/cxf/systest/jaxrs/security/bob.jwk.properties"/>
- </jaxrs:properties>
-</jaxrs:server></pre>
-</div></div><h1 id="JAXRSTokenAuthorization-Rolebasedaccesscontrol">Role based
access control</h1><p>If we have a SAML Assertion or JWT token with claims that
are known to represent roles, then making those claims work with an RBAC system
can be achieved easily.</p><h2
id="JAXRSTokenAuthorization-SimpleAuthorizingInterceptor">SimpleAuthorizingInterceptor</h2><p>One
option is to enforce that only users in a given role can access a method in
the service bean is to use CXF's SimpleAuthorizingInterceptor. It has a
"methodRolesMap" property can maps method names to roles. This interceptor must
then be added to the inInterceptor chain of the service endpoint. For
example:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"><bean
id="serviceBean"
class="org.apache.cxf.systest.jaxrs.security.jose.jwt.BookStoreAuthn"/>
+ <jaxrs:serviceBeans>
+ <ref bean="serviceBean"/>
+ </jaxrs:serviceBeans>
+ <jaxrs:providers>
+ <ref bean="jwtAuthzFilter"/>
+ <ref bean="claimsHandler"/>
+ </jaxrs:providers>
+ <jaxrs:properties>
+ <entry key="rs.security.signature.in.properties"
+
value="org/apache/cxf/systest/jaxrs/security/bob.jwk.properties"/>
+ </jaxrs:properties>
+</jaxrs:server>
+</code></pre><h2 id="JAXRSTokenAuthorization-Rolebasedaccesscontrol">Role
based access control</h2><p>If a SAML Assertion or JWT token has claims that
are known to represent roles, those claims can easily be used with an RBAC
system. For JWT, the <code>roleClaim</code> property of
<code>JwtAuthenticationFilter</code> names the claim holding the roles. Its
value can be a JSON array of strings, or a single comma-separated string such
as <code>"admin,user"</code>. Don't put spaces after the commas, because the
individual values are not trimmed. For SAML, see the role properties described
below.</p><h3
id="JAXRSTokenAuthorization-SimpleAuthorizingInterceptor">SimpleAuthorizingInterceptor</h3><p>One
way to make sure that only users in a given role can access a method of the
service bean is to use CXF's <code>SimpleAuthorizingInterceptor</code>. Its
<code>methodRolesMap</code> property maps methods to space-separated lists of
roles. A key can be either:</p><ul><li>a method name, such as <
code>echoBook</code>, which applies to all overloads of that method;
or</li><li>a full method signature in the form <code>returnType
methodName(paramType1, paramType2)</code>, using <code>Class.getName()</code>
type names, such as <code>void transfer(java.lang.String,
long)</code>.</li></ul><p>The <code>globalRoles</code> property sets the roles
required for methods that have no entry in
<code>methodRolesMap</code>.</p><p>Add the interceptor to the inInterceptor
chain of the service endpoint. For example:</p><pre><code
class="language-xml"><bean id="serviceBean"
class="org.apache.cxf.systest.jaxrs.security.jose.jwt.BookStoreAuthn"/>
<bean id="jwtAuthzFilter"
class="org.apache.cxf.rs.security.jose.jaxrs.JwtAuthenticationFilter">
<property name="roleClaim" value="role"/>
</bean>
-<bean id="authorizationInterceptor"
-
class="org.apache.cxf.interceptor.security.SimpleAuthorizingInterceptor">
+<bean id="authorizationInterceptor"
+
class="org.apache.cxf.interceptor.security.SimpleAuthorizingInterceptor">
<property name="methodRolesMap">
<map>
<entry key="echoBook" value="boss"/>
<entry key="echoBook2" value="boss"/>
</map>
- </property>
+ </property>
</bean>
<jaxrs:server
address="https://localhost:${testutil.ports.jaxrs-jwt-authn-authz}/signedjwtauthz">
- <jaxrs:serviceBeans>
- <ref bean="serviceBean"/>
- </jaxrs:serviceBeans>
- <jaxrs:providers>
- <ref bean="jwtAuthzFilter"/>
- </jaxrs:providers>
- <jaxrs:inInterceptors>
- <ref bean="authorizationInterceptor"/>
- </jaxrs:inInterceptors>
-  <jaxrs:properties>
- <entry key="rs.security.signature.in.properties"
-
value="org/apache/cxf/systest/jaxrs/security/bob.jwk.properties"/>
- </jaxrs:properties>
-</jaxrs:server></pre>
-</div></div><h2 id="JAXRSTokenAuthorization-Usingannotations">Using
annotations</h2><p>Instead of mapping method names to roles using the
SimpleAuthorizingInterceptor, we can instead annotate them in the service bean
with javax.annotation.security.RolesAllowed or
org.springframework.security.annotation.Secured annotations. For
example:</p><div class="table-wrap"><table class="wrapped
confluenceTable"><colgroup span="1"><col span="1"></colgroup><tbody><tr><td
colspan="1" rowspan="1" class="confluenceTd"><p><code class="java
keyword">import</code> <code class="java plain"><a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.springframework.security.annotation.Secured;">org.springframework.security.annotation.Secured;</a></code><br
clear="none"> <br clear="none"><code class="java
color1">@Path</code><code class="java plain">(</code><code class="java
string">"/bookstore"</code><code class="java plain">)</code><br
clear="none"><code class="java keyword">pub
lic</code> <code class="java keyword">class</code> <code class="java
plain">SecureBookStore {</code><br clear="none"><code class="java
spaces">    </code> <br clear="none"><code class="java
spaces">    </code><code class="java
color1">@POST</code><br clear="none"><code class="java
spaces">    </code><code class="java
color1">@Secured</code><code class="java plain">(</code><code class="java
string">"admin"</code><code class="java plain">)</code><br clear="none"><code
class="java spaces">    </code><code class="java
keyword">public</code> <code class="java plain">Book addBook(Book book)
{</code><br clear="none"><code class="java
spaces">        </code><code
class="java keyword">return</code> <code class="java plain">book;</code><br
clear="none"><code class="java spaces">    </code><code
class="java plain">}</code><br clear="none"><code class=
"java plain">}</code></p></td></tr></tbody></table></div><p>where @Secured can
be replaced with @RoledAllowed if needed, the following configuration will do
it:</p><div class="table-wrap"><table class="wrapped confluenceTable"><colgroup
span="1"><col span="1"></colgroup><tbody><tr><td colspan="1" rowspan="1"
class="confluenceTd"><p><code class="java plain"><bean id=</code><code
class="java string">"serviceBeanRoles"</code> <code class="java
keyword">class</code><code class="java plain">=</code><code class="java
string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.systest.jaxrs.security.saml.SecureBookStore">org.apache.cxf.systest.jaxrs.security.saml.SecureBookStore</a>"</code><code
class="java plain">/></code><br clear="none"><code class="java
plain"><bean id=</code><code class="java string">"samlEnvHandler"</code>
<code class="java keyword">class</code><code class="java plain">=</code><code
class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.rs.security.saml.SamlEnvelopedInHandler">org.apache.cxf.rs.security.saml.SamlEnvelopedInHandler</a>"</code><code
class="java plain">></code><br clear="none"><code class="java
spaces"> </code><code class="java plain"><property name=</code><code
class="java string">"securityContextProvider"</code><code class="java
plain">></code><br clear="none"><code class="java
spaces">    </code><code class="java plain"><bean
</code><code class="java keyword">class</code><code class="java
plain">=</code><code class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.systest.jaxrs.security.saml.CustomSecurityContextProvider">org.apache.cxf.systest.jaxrs.security.saml.CustomSecurityContextProvider</a>"</code><code
class="java plain">/></code><br clear="none"><code class="java
spaces"> </code><code class="java plain"></property&g
t;</code><br clear="none"><code class="java plain"></bean></code><br
clear="none"> <br clear="none"><code class="java plain"><bean
id=</code><code class="java string">"authorizationInterceptor"</code> <code
class="java keyword">class</code><code class="java plain">=</code><code
class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor">org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor</a>"</code><code
class="java plain">></code><br clear="none"><code class="java
spaces">    </code><code class="java plain"><property
name=</code><code class="java string">"securedObject"</code> <code class="java
plain">ref=</code><code class="java string">"serviceBean"</code><code
class="java plain">/></code><br clear="none"><code class="java
spaces">    </code><code class="java plain"><property
name=</code><code class="j
ava string">"annotationClassName"</code><br clear="none"><code class="java
spaces">              </code><code
class="java plain">value=</code><code class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.springframework.security.annotation.Secured">org.springframework.security.annotation.Secured</a>"</code><code
class="java plain">/></code><br clear="none"><code class="java
plain"></bean></code><br clear="none"><code class="java
spaces">    </code> <br clear="none"><code class="java
plain"><bean id=</code><code class="java string">"rolesHandler"</code> <code
class="java keyword">class</code><code class="java plain">=</code><code
class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.jaxrs.security.SimpleAuthorizingFilter">org.apache.cxf.jaxrs.security.SimpleAuthorizingFilter</a>"
</code><code class="java plain">></code><br clear="none"><code class="java
spaces">    </code><code class="java plain"><property
name=</code><code class="java string">"interceptor"</code> <code class="java
plain">ref=</code><code class="java
string">"authorizationInterceptor"</code><code class="java
plain">/></code><br clear="none"><code class="java
plain"></bean></code><br clear="none"><code class="java
spaces">    </code> <br clear="none"><code class="java
plain"><jaxrs:server address=</code><code class="java
string">"/saml-roles"</code><code class="java plain">> </code><br
clear="none"><code class="java spaces">  </code><code class="java
plain"><jaxrs:serviceBeans></code><br clear="none"><code class="java
spaces">     </code><code class="java plain"><ref
bean=</code><code class="java string">"serviceBeanRoles"</code><code
class="java plain">/></code><br clear="none"><c
ode class="java spaces">  </code><code class="java
plain"></jaxrs:serviceBeans></code><br clear="none"><code class="java
spaces">  </code><code class="java
plain"><jaxrs:providers></code><br clear="none"><code class="java
spaces">      </code><code class="java
plain"><ref bean=</code><code class="java
string">"samlEnvHandler"</code><code class="java plain">/></code><br
clear="none"><code class="java
spaces">      </code><code class="java
plain"><ref bean=</code><code class="java string">"rolesHandler"</code><code
class="java plain">/></code><br clear="none"><code class="java
spaces">  </code><code class="java
plain"></jaxrs:providers></code><br clear="none"><code class="java
spaces">  </code> <br clear="none"><code class="java
spaces">  </code><code class="java plain"><!-- If </code><code
class="java keyword">default</code> <code class="
java plain">role qualifier and format are not supported: </code><br
clear="none"><code class="java
spaces">       </code> <br
clear="none"><code class="java spaces">  </code><code class="java
plain"><jaxrs:properties></code><br clear="none"><code class="java
spaces">     </code><code class="java plain"><entry
key=</code><code class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.saml.claims.role.nameformat">org.apache.cxf.saml.claims.role.nameformat</a>"</code><br
clear="none"><code class="java
spaces">                </code><code
class="java plain">value=</code><code class="java
string">"urn:oasis:names:tc:SAML:<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/2.0:attrname-format:uri">2.0:attrname-format:uri</a>"</code><code
class="java pla
in">/></code><br clear="none"><code class="java
spaces">     </code><code class="java plain"><entry
key=</code><code class="java string">"<a shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/org.apache.cxf.saml.claims.role.qualifier">org.apache.cxf.saml.claims.role.qualifier</a>"</code><br
clear="none"><code class="java
spaces">                </code><code
class="java plain">value=</code><code class="java string">"urn:oid:<a
shape="rect"
href="https://cwiki.apache.org/confluence/display/CXF20DOC/1.3.6.1.4.1.5923.1.1.1.1">1.3.6.1.4.1.5923.1.1.1.1</a>"</code><code
class="java plain">/></code><br clear="none"><code class="java
spaces">  </code><code class="java
plain"></jaxrs:properties></code><br clear="none"><code class="java
spaces">  </code><code class="java plain">--></code><br
clear="none"><code class="java plain"><
;/jaxrs:server></code></p></td></tr></tbody></table></div><p>That is all
what is needed. Note that in order to help the default SAML
SecurityContextProvider figure out which claims are roles, one can set the two
properties as shown above - this not needed if it's known that claims
identifying roles have NameFormat and Name values with the default values,
which are "<a shape="rect" class="external-link"
href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims"
rel="nofollow">http://schemas.xmlsoap.org/ws/2005/05/identity/claims</a>" and
"<a shape="rect" class="external-link"
href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
rel="nofollow">http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</a>"
respectively at the moment.</p><p>Note that you can have RBAC and CBAC combined
for a more sophisticated access control rules be enforced while still keeping
the existing code relying on @RolesAllowed or @Secured intact. Override
ClaimsAuthorizingFilter and configu
re it with the Claims rules directly and register it alongside
SimpleAuthorizingFilter and here you go.</p><p>Also note how
SecureAnnotationsInterceptor can handle different types of role annotations,
with @RolesAllowed being supported by default.</p></div>
+ <jaxrs:serviceBeans>
+ <ref bean="serviceBean"/>
+ </jaxrs:serviceBeans>
+ <jaxrs:providers>
+ <ref bean="jwtAuthzFilter"/>
+ </jaxrs:providers>
+ <jaxrs:inInterceptors>
+ <ref bean="authorizationInterceptor"/>
+ </jaxrs:inInterceptors>
+ <jaxrs:properties>
+ <entry key="rs.security.signature.in.properties"
+
value="org/apache/cxf/systest/jaxrs/security/bob.jwk.properties"/>
+ </jaxrs:properties>
+</jaxrs:server>
+</code></pre><p><strong>Unlisted methods are not protected.</strong> A method
with no roles configured, either in <code>methodRolesMap</code> or through
<code>globalRoles</code>, is allowed for any authenticated user. It is also
allowed for unauthenticated users, because <code>allowAnonymousUsers</code>
defaults to <code>true</code>. To protect every method, set
<code>globalRoles</code>, and consider setting <code>allowAnonymousUsers</code>
to <code>false</code>.</p><h3
id="JAXRSTokenAuthorization-Usingannotations">Using annotations</h3><p>Instead
of mapping methods to roles in <code>SimpleAuthorizingInterceptor</code>, you
can annotate the methods of the service bean with
<code>jakarta.annotation.security.RolesAllowed</code> (the default) or another
role annotation, such as Spring Security's
<code>org.springframework.security.access.annotation.Secured</code>. For
example:</p><pre><code class="language-java">import
org.springframework.security.access.annotation.Secured;
+
+@Path("/bookstore")
+public class SecureBookStore {
+
+ @POST
+ @Secured("admin")
+ public Book addBook(Book book) {
+ return book;
+ }
+}
+</code></pre><p>Here <code>@Secured</code> can be replaced with
<code>@RolesAllowed</code> if needed. <code>SecureAnnotationsInterceptor</code>
reads the annotations from the secured object; class-level annotations apply to
methods that are not annotated themselves. The following configuration enables
it:</p><pre><code class="language-xml"><bean id="serviceBeanRoles"
class="org.apache.cxf.systest.jaxrs.security.saml.SecureBookStore"/>
+
+<bean id="samlEnvHandler"
class="org.apache.cxf.rs.security.saml.SamlEnvelopedInHandler">
+ <property name="securityContextProvider">
+ <bean
class="org.apache.cxf.systest.jaxrs.security.saml.CustomSecurityContextProvider"/>
+ </property>
+</bean>
+
+<bean id="authorizationInterceptor"
class="org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor">
+ <property name="securedObject" ref="serviceBeanRoles"/>
+ <!-- Only needed when not using the default
jakarta.annotation.security.RolesAllowed -->
+ <property name="annotationClassName"
+
value="org.springframework.security.access.annotation.Secured"/>
+</bean>
+
+<bean id="rolesHandler"
class="org.apache.cxf.jaxrs.security.SimpleAuthorizingFilter">
+ <property name="interceptor" ref="authorizationInterceptor"/>
+</bean>
+
+<jaxrs:server address="/saml-roles">
+ <jaxrs:serviceBeans>
+ <ref bean="serviceBeanRoles"/>
+ </jaxrs:serviceBeans>
+ <jaxrs:providers>
+ <ref bean="samlEnvHandler"/>
+ <ref bean="rolesHandler"/>
+ </jaxrs:providers>
+
+ <!-- If the default role name and format are not used:
+
+ <jaxrs:properties>
+ <entry key="org.apache.cxf.saml.claims.role.nameformat"
+ value="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"/>
+ <entry key="org.apache.cxf.saml.claims.role.qualifier"
+ value="urn:oid:1.3.6.1.4.1.5923.1.1.1.1"/>
+ </jaxrs:properties>
+ -->
+</jaxrs:server>
+</code></pre><p>That is all that is needed. To help the default SAML
<code>SecurityContextProvider</code> work out which attributes are roles, you
can set the two properties shown above. This is not needed if the role
attributes use the default values:</p><ul><li>Name:
<code>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</code></li><li>NameFormat:
<code>urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified</code></li></ul><p>The
role name can also be set with the
<code>security.saml-role-attributename</code> property.</p><p>You can combine
RBAC and CBAC to enforce more sophisticated access control rules, while keeping
existing code that relies on <code>@RolesAllowed</code> or
<code>@Secured</code> intact. Configure a
<code>ClaimsAuthorizingInterceptor</code> with the Claims rules directly, wrap
it in a <code>ClaimsAuthorizingFilter</code>, and register it alongside
<code>SimpleAuthorizingFilter</code>.</p><p><code>SecureAnnotationsInterceptor</code>
can handle differen
t types of role annotations through its <code>annotationClassName</code>
property, with <code>@RolesAllowed</code> supported by default.</p></div>
</div>
<!-- Content -->
</td>