This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5626-approach-c
in repository https://gitbox.apache.org/repos/asf/struts.git

commit be5ba541315bac46ef4c2dd6447899d071d7cea3
Author: Lukasz Lenart <[email protected]>
AuthorDate: Mon May 4 16:03:26 2026 +0200

    WW-5626 use AuthorizationAwareContentTypeHandler path when handler supports 
it
---
 .../struts2/rest/ContentTypeInterceptor.java       | 37 +++++++++++++++-------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git 
a/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java
 
b/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java
index 73f3cd7ef..35016467e 100644
--- 
a/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java
+++ 
b/plugins/rest/src/main/java/org/apache/struts2/rest/ContentTypeInterceptor.java
@@ -96,18 +96,33 @@ public class ContentTypeInterceptor extends 
AbstractInterceptor {
             InputStreamReader reader = encoding == null ? new 
InputStreamReader(is) : new InputStreamReader(is, encoding);
 
             if (requireAnnotations) {
-                // Two-phase deserialization: deserialize into a fresh 
instance, then copy only authorized properties.
-                // Requires a public no-arg constructor on the target class.
-                // If absent, body processing is rejected entirely — a 
best-effort scrub cannot guarantee
-                // that every nested unauthorized property is nulled out, so 
the safer choice is to skip.
-                Object freshInstance = createFreshInstance(target.getClass());
-                if (freshInstance != null) {
-                    handler.toObject(invocation, reader, freshInstance);
-                    copyAuthorizedProperties(freshInstance, target, 
invocation.getAction(), target, "");
+                if (handler instanceof 
org.apache.struts2.rest.handler.AuthorizationAwareContentTypeHandler) {
+                    // Handler authorizes per-property during deserialization 
(no two-phase copy needed).
+                    // Bind context so the handler's deserializer can consult 
ParameterAuthorizationContext.
+                    Object action = invocation.getAction();
+                    Object resolvedTarget = 
parameterAuthorizer.resolveTarget(action);
+                    
org.apache.struts2.interceptor.parameter.ParameterAuthorizationContext.bind(
+                            parameterAuthorizer, resolvedTarget, action);
+                    try {
+                        handler.toObject(invocation, reader, target);
+                    } finally {
+                        
org.apache.struts2.interceptor.parameter.ParameterAuthorizationContext.unbind();
+                    }
                 } else {
-                    LOG.warn("REST body rejected: requireAnnotations=true but 
[{}] has no no-arg constructor; "
-                            + "body deserialization skipped to preserve 
@StrutsParameter authorization integrity",
-                            target.getClass().getName());
+                    // Legacy two-phase deserialization for handlers that 
don't authorize themselves.
+                    // Deserialize into a fresh instance, then copy only 
authorized properties.
+                    // Requires a public no-arg constructor on the target 
class.
+                    // If absent, body processing is rejected entirely — a 
best-effort scrub cannot guarantee
+                    // that every nested unauthorized property is nulled out, 
so the safer choice is to skip.
+                    Object freshInstance = 
createFreshInstance(target.getClass());
+                    if (freshInstance != null) {
+                        handler.toObject(invocation, reader, freshInstance);
+                        copyAuthorizedProperties(freshInstance, target, 
invocation.getAction(), target, "");
+                    } else {
+                        LOG.warn("REST body rejected: requireAnnotations=true 
but [{}] has no no-arg constructor; "
+                                + "body deserialization skipped to preserve 
@StrutsParameter authorization integrity",
+                                target.getClass().getName());
+                    }
                 }
             } else {
                 // Direct deserialization (backward compat when 
requireAnnotations is not enabled)

Reply via email to