20
20
21
21
import com .opensymphony .xwork2 .ActionContext ;
22
22
import com .opensymphony .xwork2 .ActionInvocation ;
23
+ import com .opensymphony .xwork2 .ModelDriven ;
23
24
import com .opensymphony .xwork2 .inject .Inject ;
24
25
import com .opensymphony .xwork2 .interceptor .MethodFilterInterceptor ;
25
26
import com .opensymphony .xwork2 .security .AcceptedPatternsChecker ;
@@ -258,19 +259,19 @@ protected void batchApplyReflectionContextState(Map<String, Object> context, boo
258
259
259
260
protected ValueStack toNewStack (ValueStack stack ) {
260
261
ValueStack newStack = valueStackFactory .createValueStack (stack );
261
- if (newStack instanceof ClearableValueStack ) {
262
- (( ClearableValueStack ) newStack ) .clearContextValues ();
262
+ if (newStack instanceof ClearableValueStack clearable ) {
263
+ clearable .clearContextValues ();
263
264
newStack .getActionContext ().withLocale (stack .getActionContext ().getLocale ()).withValueStack (stack );
264
265
}
265
266
return newStack ;
266
267
}
267
268
268
269
protected void applyMemberAccessProperties (ValueStack stack ) {
269
- if (!(stack instanceof MemberAccessValueStack )) {
270
+ if (!(stack instanceof MemberAccessValueStack accessValueStack )) {
270
271
return ;
271
272
}
272
- (( MemberAccessValueStack ) stack ) .useAcceptProperties (acceptedPatterns .getAcceptedPatterns ());
273
- (( MemberAccessValueStack ) stack ) .useExcludeProperties (excludedPatterns .getExcludedPatterns ());
273
+ accessValueStack .useAcceptProperties (acceptedPatterns .getAcceptedPatterns ());
274
+ accessValueStack .useExcludeProperties (excludedPatterns .getExcludedPatterns ());
274
275
}
275
276
276
277
protected Map <String , Parameter > toAcceptableParameters (HttpParameters parameters , Object action ) {
@@ -332,7 +333,7 @@ protected boolean isAcceptableParameter(String name, Object action) {
332
333
}
333
334
334
335
protected boolean isAcceptableParameterNameAware (String name , Object action ) {
335
- return !(action instanceof ParameterNameAware ) || (( ParameterNameAware ) action ) .acceptableParameterName (name );
336
+ return !(action instanceof ParameterNameAware nameAware ) || nameAware .acceptableParameterName (name );
336
337
}
337
338
338
339
/**
@@ -348,7 +349,15 @@ protected boolean isParameterAnnotatedAndAllowlist(String name, Object action) {
348
349
}
349
350
350
351
long paramDepth = name .codePoints ().mapToObj (c -> (char ) c ).filter (NESTING_CHARS ::contains ).count ();
352
+
353
+ if (action instanceof ModelDriven <?> && !ActionContext .getContext ().getValueStack ().peek ().equals (action )) {
354
+ LOG .debug ("Model driven Action detected, exempting from @StrutsParameter annotation requirement and OGNL allowlisting model type" );
355
+ // (Exempted by annotation on com.opensymphony.xwork2.ModelDriven#getModel)
356
+ return hasValidAnnotatedMember ("model" , action , paramDepth + 1 );
357
+ }
358
+
351
359
if (requireAnnotationsTransitionMode && paramDepth == 0 ) {
360
+ LOG .debug ("Annotation transition mode enabled, exempting non-nested parameter [{}] from @StrutsParameter annotation requirement" , name );
352
361
return true ;
353
362
}
354
363
@@ -365,6 +374,8 @@ protected boolean isParameterAnnotatedAndAllowlist(String name, Object action) {
365
374
* save computation by checking this last.
366
375
*/
367
376
protected boolean hasValidAnnotatedMember (String rootProperty , Object action , long paramDepth ) {
377
+ LOG .debug ("Checking Action [{}] for a matching, correctly annotated member for property [{}]" ,
378
+ action .getClass ().getSimpleName (), rootProperty );
368
379
BeanInfo beanInfo = getBeanInfo (action );
369
380
if (beanInfo == null ) {
370
381
return hasValidAnnotatedField (action , rootProperty , paramDepth );
@@ -390,7 +401,7 @@ protected boolean hasValidAnnotatedPropertyDescriptor(Object action, PropertyDes
390
401
}
391
402
if (getPermittedInjectionDepth (relevantMethod ) < paramDepth ) {
392
403
String logMessage = format (
393
- "Parameter injection for method [%s] on action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'." ,
404
+ "Parameter injection for method [%s] on Action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'." ,
394
405
relevantMethod .getName (),
395
406
relevantMethod .getDeclaringClass ().getName ());
396
407
if (devMode ) {
@@ -400,8 +411,10 @@ protected boolean hasValidAnnotatedPropertyDescriptor(Object action, PropertyDes
400
411
}
401
412
return false ;
402
413
}
414
+ LOG .debug ("Success: Matching annotated method [{}] found for property [{}] of depth [{}] on Action [{}]" ,
415
+ relevantMethod .getName (), propDesc .getName (), paramDepth , action .getClass ().getSimpleName ());
403
416
if (paramDepth >= 1 ) {
404
- allowlistClass (relevantMethod . getReturnType ());
417
+ allowlistClass (propDesc . getPropertyType ());
405
418
}
406
419
if (paramDepth >= 2 ) {
407
420
allowlistReturnTypeIfParameterized (relevantMethod );
@@ -438,19 +451,23 @@ protected void allowlistClass(Class<?> clazz) {
438
451
}
439
452
440
453
protected boolean hasValidAnnotatedField (Object action , String fieldName , long paramDepth ) {
454
+ LOG .debug ("No matching annotated method found for property [{}] of depth [{}] on Action [{}], now also checking for public field" ,
455
+ fieldName , paramDepth , action .getClass ().getSimpleName ());
441
456
Field field ;
442
457
try {
443
458
field = action .getClass ().getDeclaredField (fieldName );
444
459
} catch (NoSuchFieldException e ) {
460
+ LOG .debug ("Matching field for property [{}] not found on Action [{}]" , fieldName , action .getClass ().getSimpleName ());
445
461
return false ;
446
462
}
447
463
if (!Modifier .isPublic (field .getModifiers ())) {
464
+ LOG .debug ("Matching field [{}] is not public on Action [{}]" , field .getName (), action .getClass ().getSimpleName ());
448
465
return false ;
449
466
}
450
467
if (getPermittedInjectionDepth (field ) < paramDepth ) {
451
468
String logMessage = format (
452
- "Parameter injection for field [%s] on action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'." ,
453
- fieldName ,
469
+ "Parameter injection for field [%s] on Action [%s] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'." ,
470
+ field . getName () ,
454
471
action .getClass ().getName ());
455
472
if (devMode ) {
456
473
notifyDeveloperOfError (LOG , action , logMessage );
@@ -459,6 +476,8 @@ protected boolean hasValidAnnotatedField(Object action, String fieldName, long p
459
476
}
460
477
return false ;
461
478
}
479
+ LOG .debug ("Success: Matching annotated public field [{}] found for property of depth [{}] on Action [{}]" ,
480
+ field .getName (), paramDepth , action .getClass ().getSimpleName ());
462
481
if (paramDepth >= 1 ) {
463
482
allowlistClass (field .getType ());
464
483
}
@@ -512,7 +531,7 @@ protected boolean isAcceptableParameterValue(Parameter param, Object action) {
512
531
}
513
532
514
533
protected boolean isAcceptableParameterValueAware (Parameter param , Object action ) {
515
- return !(action instanceof ParameterValueAware ) || (( ParameterValueAware ) action ) .acceptableParameterValue (param .getValue ());
534
+ return !(action instanceof ParameterValueAware valueAware ) || valueAware .acceptableParameterValue (param .getValue ());
516
535
}
517
536
518
537
/**
@@ -606,7 +625,7 @@ protected boolean isAccepted(String paramName) {
606
625
if (!result .isAccepted ()) {
607
626
if (devMode ) {
608
627
LOG .warn ("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n " +
609
- "https://struts.apache.org/security/#accepted--excluded-patterns" ,
628
+ "https://struts.apache.org/security/#accepted--excluded-patterns" ,
610
629
paramName , result .getAcceptedPattern ());
611
630
} else {
612
631
LOG .debug ("Parameter [{}] didn't match accepted pattern [{}]!" , paramName , result .getAcceptedPattern ());
@@ -621,8 +640,8 @@ protected boolean isExcluded(String paramName) {
621
640
if (result .isExcluded ()) {
622
641
if (devMode ) {
623
642
LOG .warn ("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n " +
624
- "https://struts.apache.org/security/#accepted--excluded-patterns" ,
625
- paramName , result .getExcludedPattern ());
643
+ "https://struts.apache.org/security/#accepted--excluded-patterns" ,
644
+ paramName , result .getExcludedPattern ());
626
645
} else {
627
646
LOG .debug ("Parameter [{}] matches excluded pattern [{}]!" , paramName , result .getExcludedPattern ());
628
647
}
@@ -640,8 +659,8 @@ protected boolean isParamValueExcluded(String value) {
640
659
if (excludedValuePattern .matcher (value ).matches ()) {
641
660
if (devMode ) {
642
661
LOG .warn ("Parameter value [{}] matches excluded pattern [{}]! See Accepting/Excluding parameter values at\n " +
643
- "https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values" ,
644
- value , excludedValuePatterns );
662
+ "https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values" ,
663
+ value , excludedValuePatterns );
645
664
} else {
646
665
LOG .debug ("Parameter value [{}] matches excluded pattern [{}]" , value , excludedValuePattern );
647
666
}
@@ -663,8 +682,8 @@ protected boolean isParamValueAccepted(String value) {
663
682
}
664
683
if (devMode ) {
665
684
LOG .warn ("Parameter value [{}] didn't match accepted pattern [{}]! See Accepting/Excluding parameter values at\n " +
666
- "https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values" ,
667
- value , acceptedValuePatterns );
685
+ "https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values" ,
686
+ value , acceptedValuePatterns );
668
687
} else {
669
688
LOG .debug ("Parameter value [{}] was not accepted!" , value );
670
689
}
@@ -734,7 +753,7 @@ public void setAcceptedValuePatterns(String commaDelimitedPatterns) {
734
753
LOG .debug ("Sets accepted value patterns to [{}], note this may impact the safety of your application!" , patterns );
735
754
} else {
736
755
LOG .warn ("Replacing accepted patterns [{}] with [{}], be aware that this may impact safety of your application!" ,
737
- acceptedValuePatterns , patterns );
756
+ acceptedValuePatterns , patterns );
738
757
}
739
758
acceptedValuePatterns = new HashSet <>(patterns .size ());
740
759
try {
@@ -759,7 +778,7 @@ public void setExcludedValuePatterns(String commaDelimitedPatterns) {
759
778
LOG .debug ("Setting excluded value patterns to [{}]" , patterns );
760
779
} else {
761
780
LOG .warn ("Replacing excluded value patterns [{}] with [{}], be aware that this may impact safety of your application!" ,
762
- excludedValuePatterns , patterns );
781
+ excludedValuePatterns , patterns );
763
782
}
764
783
excludedValuePatterns = new HashSet <>(patterns .size ());
765
784
try {
0 commit comments