Class StrutsParameterAuthorizer
- All Implemented Interfaces:
ParameterAuthorizer
ParameterAuthorizer that checks StrutsParameter annotations on the target
object's members to determine whether a parameter is authorized for injection.
This implementation extracts the authorization logic from ParametersInterceptor so that it can be shared
with other input channels (JSON plugin, REST plugin) without duplicating code.
Unlike ParametersInterceptor, this implementation does NOT perform OGNL ThreadAllowlist side effects.
Those remain specific to the OGNL-based parameter injection path.
- Since:
- 7.2.0
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected booleandeclaresBindablePublicField(Object target, String property, long paramDepth) Whethertargetexposespropertyas a public instance field that this parameter could bind through.protected booleandeclaresProperty(Object target, String property, long paramDepth) Whethertargetcan itself takepropertyat this depth - as a bean property whose relevant accessor exists, the setter for a depth-0 parameter and the getter for a nested one, or as a public instance field.findBindableAccessor(Object target, String property, long paramDepth) The method OGNL would go through to bindpropertyontargetat this depth: the setter for a depth-0 parameter, the getter for a nested one.protected BeanInfogetBeanInfo(Object target) protected StrutsParametergetParameterAnnotation(AnnotatedElement element) protected intprotected booleanhasValidAnnotatedField(Object target, String fieldName, long paramDepth) protected booleanhasValidAnnotatedMember(String rootProperty, Object target, long paramDepth) protected booleanhasValidAnnotatedMethod(Object target, Method method, long paramDepth) protected booleanhasValidAnnotatedPropertyDescriptor(Object target, PropertyDescriptor propDesc, long paramDepth) Deprecated, for removal: This API element is subject to removal in a future version.booleanisAuthorized(String parameterName, Object target, Object action) Determines whether a parameter with the given name is authorized for injection into the given target object.protected booleanisAuthorizedOnModelDrivenAction(String rootProperty, Object model, Object action, long paramDepth) Decides authorization for aModelDrivenaction, whose model is on top of the value stack.resolveTarget(Object action) Resolves the target object whose annotations should be checked for authorization.voidsetDevMode(String mode) voidsetOgnlUtil(OgnlUtil ognlUtil) voidsetProxyService(ProxyService proxyService) voidsetRequireAnnotations(String requireAnnotations) voidsetRequireAnnotationsTransitionMode(String transitionMode) protected Class<?>ultimateClass(Object target)
-
Constructor Details
-
StrutsParameterAuthorizer
public StrutsParameterAuthorizer()
-
-
Method Details
-
setOgnlUtil
-
setProxyService
-
setDevMode
-
setRequireAnnotations
-
setRequireAnnotationsTransitionMode
-
resolveTarget
Description copied from interface:ParameterAuthorizerResolves the target object whose annotations should be checked for authorization. ForModelDrivenactions, the default implementation returns the action itself; the production implementation (StrutsParameterAuthorizer) overrides this to return the model from the value stack.Callers that need both authorization checks AND the resolved target (e.g. for downstream OGNL allowlisting) should call this once and reuse the result.
This is a
defaultmethod to preserve the interface as a functional interface (SAM) for lambda-based test stubs.- Specified by:
resolveTargetin interfaceParameterAuthorizer- Parameters:
action- the action instance- Returns:
- the resolved target — either the action or its model
-
isAuthorized
Description copied from interface:ParameterAuthorizerDetermines whether a parameter with the given name is authorized for injection into the given target object.When
struts.parameters.requireAnnotationsisfalse, this method always returnstruefor backward compatibility.- Specified by:
isAuthorizedin interfaceParameterAuthorizer- Parameters:
parameterName- the parameter name (e.g. "name", "address.city", "items[0].name")target- the object receiving the parameter value (the action, or the model for ModelDriven actions)action- the action instance; used to detect ModelDriven exemption (whentarget != action, the target is the model and is exempt from annotation requirements)- Returns:
trueif the parameter is authorized for injection,falseotherwise
-
isAuthorizedOnModelDrivenAction
protected boolean isAuthorizedOnModelDrivenAction(String rootProperty, Object model, Object action, long paramDepth) Decides authorization for aModelDrivenaction, whose model is on top of the value stack.Returning an object from
getModel()declares that object to be request surface, so anything the model itself can take is exempt from theStrutsParameterrequirement. The exemption stops there: OGNL resolves the parameter name against the whole stack, which also holds the action, so a property declared on the action is still subject to the annotation requirement. Without that distinction a ModelDriven action would silently expose its own members.A property declared on neither is allowed: typically it is bound by a custom OGNL property accessor on the model, such as a Map-backed model. That fallback guarantees less than it may appear to - only that the name reaches no member
declaresProperty(java.lang.Object, java.lang.String, long)can see. OGNL walks the whole stack, so such a name can still land on the action wherever the action absorbs it by a route introspection here does not model, being aMapitself for instance. That is no more permissive than the blanket exemption this scoping replaces.classis the exception to that fallback: it is invisible to introspection here rather than absent, so it is rejected instead of taking the fallback, which keeps a ModelDriven action from handing OGNL aclasspath that the ordinary non-ModelDriven path would have rejected for want of an annotation. -
declaresProperty
Whethertargetcan itself takepropertyat this depth - as a bean property whose relevant accessor exists, the setter for a depth-0 parameter and the getter for a nested one, or as a public instance field. AnyStrutsParameterannotation is irrelevant here; this asks only what the object can absorb.It has to be bindability rather than the name alone, because OGNL walks the stack until an object actually accepts the assignment. A model which merely names the property without being able to take it - a getter-only property under a depth-0 parameter, say - does not absorb that parameter: OGNL moves on to the action, and an exemption granted on the name alone would hand over the action's own member, which is the very thing this scoping exists to prevent. Inherited public fields count for the same reason, that OGNL can set them.
-
findBindableAccessor
The method OGNL would go through to bindpropertyontargetat this depth: the setter for a depth-0 parameter, the getter for a nested one.The setter is matched the way OGNL matches it - a public instance method named
setplus the capitalised property name, taking one argument - and not throughPropertyDescriptor.getWriteMethod(), whichIntrospectoronly fills in for avoidsetter. A fluent setter returningthisis just as bindable to OGNL, so it has to be just as visible here, both to carry aStrutsParameterannotation and to count as declared on aModelDrivenaction.Where several setters qualify, the one declared furthest down the hierarchy wins - an override is what OGNL invokes and what the developer annotated, while the erased setter of a generic superclass is listed alongside it and carries no annotation - and among overloads declared at that level an annotated one, since annotating any overload declares the property request surface.
-
declaresBindablePublicField
Whethertargetexposespropertyas a public instance field that this parameter could bind through.Class.getFields()covers inherited fields as well as declared ones, an inherited public field being just as settable as a declared one. Static fields are not per-instance request surface, and a final field cannot take a depth-0 assignment, so neither counts as absorbing the parameter.Scanning the fields and matching the name here, rather than looking the name up with
getField, keeps the request-derived property name out of a reflection lookup. The two select the same fields. -
hasValidAnnotatedMember
-
hasValidAnnotatedPropertyDescriptor
@Deprecated(since="7.4.0", forRemoval=true) protected boolean hasValidAnnotatedPropertyDescriptor(Object target, PropertyDescriptor propDesc, long paramDepth) Deprecated, for removal: This API element is subject to removal in a future version.aPropertyDescriptorcannot describe every setter OGNL binds through; usefindBindableAccessor(java.lang.Object, java.lang.String, long)withhasValidAnnotatedMethod(java.lang.Object, java.lang.reflect.Method, long)instead -
hasValidAnnotatedMethod
-
hasValidAnnotatedField
-
getPermittedInjectionDepth
-
getParameterAnnotation
-
ultimateClass
-
getBeanInfo
-
PropertyDescriptorcannot describe every setter OGNL binds through; usefindBindableAccessor(java.lang.Object, java.lang.String, long)withhasValidAnnotatedMethod(java.lang.Object, java.lang.reflect.Method, long)instead