I'm doing some testing on a Spring 6 upgrade and when we promoted to an environment with a public access pattern, a PreAuthorize decorator is failing.
@PreAuthorize("hasAnyAuthority('IS_APPLICANT', 'IS_ADMIN') and " + AuthorizationHelper.IS_STATUS_VALID)
@RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(@ModelAttribute SomeModel sm, WebRequest request,
HttpSession session, AuthorizationDto authDto) {
// do page logic
return some page view;
}
I have confirmed that the ArgumentResolver is correctly registered and that the authDto is correctly initialized. In this one environment, when the AuthorizationHelper isStatusValid method is invoked through what I believe is a Spring SpEl expression, the authDto is as null. I am new with this application and looking for some help on why that might happen. My research suggests it may be a problem with the environment configuration, but I want to know what I am looking for to fail. This is what the AuthorizationHelper code looks like.
@Component
public class AuthorizationHelper {
// constructor
@Autowired
public AuthorizationHelper(){
// init any services needed
}
public static final String IS_STATUS_VALID = "@authorizationHelper.isStatusValid(#authDto)";
public boolean isStatusValid(AuthorizationDto authDto) {
logger.info("AuthorizationHelper :: authDto: " + authDto); // is null
// do logic
return result;
}
}
And for good measure, I will post the aurgement resolver code as well, although i have confirmed this is working.
@Component("authResolver")
public class CustomAuthorizationResolver implements HandlerMethodArgumentResolver {
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
AuthorizationDto authDto = new AuthorizationDto();
// some logic
logger.info("AuthorizationDto after setting properties: {}", authDto); // not null. is invoked when the /save endpoint is hit, before the PreAuthorize code is executed
return authDto;
}
}
Again, I will start digging into any environment configuration differences. The biggest one I'm aware of is this environment has a different access pattern than the dev environment. My initial research indicated it could be a proxy issue. I appreciate any help! Here is the relevant snippet of the stack trace
java.lang.NullPointerException: Cannot invoke "org.example.app.dto.AuthorizationDto.doSomeValidation()" because "authDto" is null
at org.example.app.web.helpers.AuthorizationHelper.isStatusValid(AuthorizationHelper.java:49)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:142)
at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:125)
at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:401)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:97)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:222)
at org.springframework.expression.spel.ast.OpAnd.getBooleanValue(OpAnd.java:57)
at org.springframework.expression.spel.ast.OpAnd.getValueInternal(OpAnd.java:52)
at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:119)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:309)
at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:30)
at org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager.check(PreAuthorizeAuthorizationManager.java:68)
at org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager.check(PreAuthorizeAuthorizationManager.java:40)
at org.springframework.security.config.annotation.method.configuration.DeferringObservationAuthorizationManager.check(DeferringObservationAuthorizationManager.java:47)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.attemptAuthorization(AuthorizationManagerBeforeMethodInterceptor.java:251)
at org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor.invoke(AuthorizationManagerBeforeMethodInterceptor.java:197)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720)
at org.example.app.web.controllers.ApplicantController$$SpringCGLIB$$0.save(<generated>)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(D
The issue was our new relic jar needed to be updated. It was incompatible with the other spring updates we did and we didn't use it in the lower environments.