mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-24 19:28:45 +00:00 
			
		
		
		
	Enable Null checking in spring-security-web via JSpecify
Closes gh-16882
This commit is contained in:
		
							parent
							
								
									a58f3282d9
								
							
						
					
					
						commit
						be64c67af5
					
				| @ -1,3 +1,7 @@ | |||||||
|  | plugins { | ||||||
|  | 	id 'security-nullability' | ||||||
|  | } | ||||||
|  | 
 | ||||||
| apply plugin: 'io.spring.convention.spring-module' | apply plugin: 'io.spring.convention.spring-module' | ||||||
| 
 | 
 | ||||||
| dependencies { | dependencies { | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ import java.util.function.Supplier; | |||||||
| 
 | 
 | ||||||
| import org.jspecify.annotations.Nullable; | import org.jspecify.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
|  | import org.springframework.expression.BeanResolver; | ||||||
| import org.springframework.expression.EvaluationContext; | import org.springframework.expression.EvaluationContext; | ||||||
| import org.springframework.expression.spel.support.StandardEvaluationContext; | import org.springframework.expression.spel.support.StandardEvaluationContext; | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| @ -49,12 +50,16 @@ public class DefaultMessageSecurityExpressionHandler<T> extends AbstractSecurity | |||||||
| 			Message<T> message) { | 			Message<T> message) { | ||||||
| 		MessageSecurityExpressionRoot root = createSecurityExpressionRoot(authentication, message); | 		MessageSecurityExpressionRoot root = createSecurityExpressionRoot(authentication, message); | ||||||
| 		StandardEvaluationContext ctx = new StandardEvaluationContext(root); | 		StandardEvaluationContext ctx = new StandardEvaluationContext(root); | ||||||
| 		ctx.setBeanResolver(getBeanResolver()); | 		BeanResolver beanResolver = getBeanResolver(); | ||||||
|  | 		if (beanResolver != null) { | ||||||
|  | 			// https://github.com/spring-projects/spring-framework/issues/35371 | ||||||
|  | 			ctx.setBeanResolver(beanResolver); | ||||||
|  | 		} | ||||||
| 		return ctx; | 		return ctx; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, | 	protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication, | ||||||
| 			Message<T> invocation) { | 			Message<T> invocation) { | ||||||
| 		return createSecurityExpressionRoot(() -> authentication, invocation); | 		return createSecurityExpressionRoot(() -> authentication, invocation); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ public final class MessageAuthorizationContextSecurityExpressionHandler | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public EvaluationContext createEvaluationContext(Authentication authentication, | 	public EvaluationContext createEvaluationContext(@Nullable Authentication authentication, | ||||||
| 			MessageAuthorizationContext<?> message) { | 			MessageAuthorizationContext<?> message) { | ||||||
| 		return createEvaluationContext(() -> authentication, message); | 		return createEvaluationContext(() -> authentication, message); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.access.expression; | |||||||
| 
 | 
 | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.expression.EvaluationContext; | import org.springframework.expression.EvaluationContext; | ||||||
| import org.springframework.expression.Expression; | import org.springframework.expression.Expression; | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| @ -60,7 +62,7 @@ class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationCon | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public String getAttribute() { | 	public @Nullable String getAttribute() { | ||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.access.expression; | |||||||
| 
 | 
 | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.expression.EvaluationContext; | import org.springframework.expression.EvaluationContext; | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| import org.springframework.security.access.AccessDecisionVoter; | import org.springframework.security.access.AccessDecisionVoter; | ||||||
| @ -60,7 +62,7 @@ public class MessageExpressionVoter<T> implements AccessDecisionVoter<Message<T> | |||||||
| 		return ExpressionUtils.evaluateAsBoolean(attr.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED : ACCESS_DENIED; | 		return ExpressionUtils.evaluateAsBoolean(attr.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED : ACCESS_DENIED; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private MessageExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) { | 	private @Nullable MessageExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) { | ||||||
| 		for (ConfigAttribute attribute : attributes) { | 		for (ConfigAttribute attribute : attributes) { | ||||||
| 			if (attribute instanceof MessageExpressionConfigAttribute) { | 			if (attribute instanceof MessageExpressionConfigAttribute) { | ||||||
| 				return (MessageExpressionConfigAttribute) attribute; | 				return (MessageExpressionConfigAttribute) attribute; | ||||||
|  | |||||||
| @ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Security expression support for {@link org.springframework.messaging.Message}. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.access.expression; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -20,6 +20,7 @@ import java.util.function.Supplier; | |||||||
| 
 | 
 | ||||||
| import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||||
| import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import org.springframework.core.log.LogMessage; | import org.springframework.core.log.LogMessage; | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| @ -110,7 +111,7 @@ public final class AuthorizationChannelInterceptor implements ChannelInterceptor | |||||||
| 
 | 
 | ||||||
| 		@Override | 		@Override | ||||||
| 		public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object, | 		public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object, | ||||||
| 				AuthorizationResult result) { | 				@Nullable AuthorizationResult result) { | ||||||
| 
 | 
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,8 @@ | |||||||
| 
 | 
 | ||||||
| package org.springframework.security.messaging.access.intercept; | package org.springframework.security.messaging.access.intercept; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| import org.springframework.messaging.MessageChannel; | import org.springframework.messaging.MessageChannel; | ||||||
| import org.springframework.messaging.support.ChannelInterceptor; | import org.springframework.messaging.support.ChannelInterceptor; | ||||||
| @ -83,7 +85,7 @@ public final class ChannelSecurityInterceptor extends AbstractSecurityIntercepto | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex) { | 	public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, @Nullable Exception ex) { | ||||||
| 		InterceptorStatusToken token = clearToken(); | 		InterceptorStatusToken token = clearToken(); | ||||||
| 		finallyInvocation(token); | 		finallyInvocation(token); | ||||||
| 	} | 	} | ||||||
| @ -99,7 +101,7 @@ public final class ChannelSecurityInterceptor extends AbstractSecurityIntercepto | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void afterReceiveCompletion(Message<?> message, MessageChannel channel, Exception ex) { | 	public void afterReceiveCompletion(@Nullable Message<?> message, MessageChannel channel, @Nullable Exception ex) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private InterceptorStatusToken clearToken() { | 	private InterceptorStatusToken clearToken() { | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ | |||||||
| package org.springframework.security.messaging.access.intercept; | package org.springframework.security.messaging.access.intercept; | ||||||
| 
 | 
 | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| @ -61,7 +62,7 @@ public final class DefaultMessageSecurityMetadataSource implements MessageSecuri | |||||||
| 				return entry.getValue(); | 				return entry.getValue(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return null; | 		return Collections.emptyList(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication, | 	public @Nullable AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication, | ||||||
| 			Message<?> message) { | 			Message<?> message) { | ||||||
| 		if (this.logger.isTraceEnabled()) { | 		if (this.logger.isTraceEnabled()) { | ||||||
| 			this.logger.trace(LogMessage.format("Authorizing message")); | 			this.logger.trace(LogMessage.format("Authorizing message")); | ||||||
| @ -75,7 +75,8 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho | |||||||
| 		return null; | 		return null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> matcher, Message<?> message) { | 	private @Nullable MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> matcher, | ||||||
|  | 			Message<?> message) { | ||||||
| 		MessageMatcher.MatchResult matchResult = matcher.matcher((Message) message); | 		MessageMatcher.MatchResult matchResult = matcher.matcher((Message) message); | ||||||
| 		if (!matchResult.isMatch()) { | 		if (!matchResult.isMatch()) { | ||||||
| 			return null; | 			return null; | ||||||
| @ -179,7 +180,7 @@ public final class MessageMatcherDelegatingAuthorizationManager implements Autho | |||||||
| 		 * @return the {@link Builder.Constraint} that is associated to the | 		 * @return the {@link Builder.Constraint} that is associated to the | ||||||
| 		 * {@link MessageMatcher} | 		 * {@link MessageMatcher} | ||||||
| 		 */ | 		 */ | ||||||
| 		private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patterns) { | 		private Builder.Constraint simpDestMatchers(@Nullable SimpMessageType type, String... patterns) { | ||||||
| 			List<MessageMatcher<?>> matchers = new ArrayList<>(patterns.length); | 			List<MessageMatcher<?>> matchers = new ArrayList<>(patterns.length); | ||||||
| 			for (String pattern : patterns) { | 			for (String pattern : patterns) { | ||||||
| 				MessageMatcher<Object> matcher = this.messageMatcherBuilder.matcher(type, pattern); | 				MessageMatcher<Object> matcher = this.messageMatcherBuilder.matcher(type, pattern); | ||||||
|  | |||||||
| @ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Authorization support for {@link org.springframework.messaging.Message}. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.access.intercept; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.context; | |||||||
| 
 | 
 | ||||||
| import java.lang.annotation.Annotation; | import java.lang.annotation.Annotation; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.core.MethodParameter; | import org.springframework.core.MethodParameter; | ||||||
| import org.springframework.core.annotation.AnnotationUtils; | import org.springframework.core.annotation.AnnotationUtils; | ||||||
| import org.springframework.core.annotation.MergedAnnotations; | import org.springframework.core.annotation.MergedAnnotations; | ||||||
| @ -110,13 +112,14 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public Object resolveArgument(MethodParameter parameter, Message<?> message) { | 	public @Nullable Object resolveArgument(MethodParameter parameter, Message<?> message) { | ||||||
| 		Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); | 		Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication(); | ||||||
| 		if (authentication == null) { | 		if (authentication == null) { | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
| 		Object principal = authentication.getPrincipal(); | 		Object principal = authentication.getPrincipal(); | ||||||
| 		AuthenticationPrincipal authPrincipal = findMethodAnnotation(parameter); | 		AuthenticationPrincipal authPrincipal = findMethodAnnotation(parameter); | ||||||
|  | 		Assert.notNull(authPrincipal, "AuthenticationPrincipal must not be null. Run supports first"); | ||||||
| 		String expressionToParse = authPrincipal.expression(); | 		String expressionToParse = authPrincipal.expression(); | ||||||
| 		if (StringUtils.hasLength(expressionToParse)) { | 		if (StringUtils.hasLength(expressionToParse)) { | ||||||
| 			StandardEvaluationContext context = new StandardEvaluationContext(); | 			StandardEvaluationContext context = new StandardEvaluationContext(); | ||||||
| @ -165,7 +168,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet | |||||||
| 	 * @param parameter the {@link MethodParameter} to search for an {@link Annotation} | 	 * @param parameter the {@link MethodParameter} to search for an {@link Annotation} | ||||||
| 	 * @return the {@link Annotation} that was found or null. | 	 * @return the {@link Annotation} that was found or null. | ||||||
| 	 */ | 	 */ | ||||||
| 	private AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) { | 	private @Nullable AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) { | ||||||
| 		if (this.useAnnotationTemplate) { | 		if (this.useAnnotationTemplate) { | ||||||
| 			return this.scanner.scan(parameter.getParameter()); | 			return this.scanner.scan(parameter.getParameter()); | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.context; | |||||||
| 
 | 
 | ||||||
| import java.util.Stack; | import java.util.Stack; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| import org.springframework.messaging.MessageChannel; | import org.springframework.messaging.MessageChannel; | ||||||
| import org.springframework.messaging.MessageHandler; | import org.springframework.messaging.MessageHandler; | ||||||
| @ -96,7 +98,7 @@ public final class SecurityContextChannelInterceptor implements ExecutorChannelI | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex) { | 	public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, @Nullable Exception ex) { | ||||||
| 		cleanup(); | 		cleanup(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -107,7 +109,8 @@ public final class SecurityContextChannelInterceptor implements ExecutorChannelI | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void afterMessageHandled(Message<?> message, MessageChannel channel, MessageHandler handler, Exception ex) { | 	public void afterMessageHandled(Message<?> message, MessageChannel channel, MessageHandler handler, | ||||||
|  | 			@Nullable Exception ex) { | ||||||
| 		cleanup(); | 		cleanup(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -131,7 +134,7 @@ public final class SecurityContextChannelInterceptor implements ExecutorChannelI | |||||||
| 		this.securityContextHolderStrategy.setContext(context); | 		this.securityContextHolderStrategy.setContext(context); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private Authentication getAuthentication(Object user) { | 	private Authentication getAuthentication(@Nullable Object user) { | ||||||
| 		if ((user instanceof Authentication)) { | 		if ((user instanceof Authentication)) { | ||||||
| 			return (Authentication) user; | 			return (Authentication) user; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.context; | |||||||
| 
 | 
 | ||||||
| import java.util.Stack; | import java.util.Stack; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| import org.springframework.messaging.MessageChannel; | import org.springframework.messaging.MessageChannel; | ||||||
| import org.springframework.messaging.MessageHandler; | import org.springframework.messaging.MessageHandler; | ||||||
| @ -121,7 +123,8 @@ public final class SecurityContextPropagationChannelInterceptor implements Execu | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void afterMessageHandled(Message<?> message, MessageChannel channel, MessageHandler handler, Exception ex) { | 	public void afterMessageHandled(Message<?> message, MessageChannel channel, MessageHandler handler, | ||||||
|  | 			@Nullable Exception ex) { | ||||||
| 		cleanup(); | 		cleanup(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -0,0 +1,24 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Support for establishing the | ||||||
|  |  * {@link org.springframework.security.core.context.SecurityContext} within messaging. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.context; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.handler.invocation.reactive; | |||||||
| 
 | 
 | ||||||
| import java.lang.annotation.Annotation; | import java.lang.annotation.Annotation; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.NullUnmarked; | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
| import org.reactivestreams.Publisher; | import org.reactivestreams.Publisher; | ||||||
| import reactor.core.publisher.Mono; | import reactor.core.publisher.Mono; | ||||||
| 
 | 
 | ||||||
| @ -108,7 +110,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg | |||||||
| 
 | 
 | ||||||
| 	private boolean useAnnotationTemplate = false; | 	private boolean useAnnotationTemplate = false; | ||||||
| 
 | 
 | ||||||
| 	private BeanResolver beanResolver; | 	private @Nullable BeanResolver beanResolver; | ||||||
| 
 | 
 | ||||||
| 	private ReactiveAdapterRegistry adapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); | 	private ReactiveAdapterRegistry adapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); | ||||||
| 
 | 
 | ||||||
| @ -149,7 +151,8 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg | |||||||
| 		// @formatter:on | 		// @formatter:on | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private Object resolvePrincipal(MethodParameter parameter, Object principal) { | 	@NullUnmarked | ||||||
|  | 	private @Nullable Object resolvePrincipal(MethodParameter parameter, @Nullable Object principal) { | ||||||
| 		AuthenticationPrincipal authPrincipal = findMethodAnnotation(parameter); | 		AuthenticationPrincipal authPrincipal = findMethodAnnotation(parameter); | ||||||
| 		String expressionToParse = authPrincipal.expression(); | 		String expressionToParse = authPrincipal.expression(); | ||||||
| 		if (StringUtils.hasLength(expressionToParse)) { | 		if (StringUtils.hasLength(expressionToParse)) { | ||||||
| @ -169,7 +172,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg | |||||||
| 		return principal; | 		return principal; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private boolean isInvalidType(MethodParameter parameter, Object principal) { | 	private boolean isInvalidType(MethodParameter parameter, @Nullable Object principal) { | ||||||
| 		if (principal == null) { | 		if (principal == null) { | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| @ -206,7 +209,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg | |||||||
| 	 * @param parameter the {@link MethodParameter} to search for an {@link Annotation} | 	 * @param parameter the {@link MethodParameter} to search for an {@link Annotation} | ||||||
| 	 * @return the {@link Annotation} that was found or null. | 	 * @return the {@link Annotation} that was found or null. | ||||||
| 	 */ | 	 */ | ||||||
| 	private AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) { | 	private @Nullable AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) { | ||||||
| 		if (this.useAnnotationTemplate) { | 		if (this.useAnnotationTemplate) { | ||||||
| 			return this.scanner.scan(parameter.getParameter()); | 			return this.scanner.scan(parameter.getParameter()); | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ package org.springframework.security.messaging.handler.invocation.reactive; | |||||||
| 
 | 
 | ||||||
| import java.lang.annotation.Annotation; | import java.lang.annotation.Annotation; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
| import org.reactivestreams.Publisher; | import org.reactivestreams.Publisher; | ||||||
| import reactor.core.publisher.Mono; | import reactor.core.publisher.Mono; | ||||||
| 
 | 
 | ||||||
| @ -106,7 +107,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu | |||||||
| 
 | 
 | ||||||
| 	private boolean useAnnotationTemplate = false; | 	private boolean useAnnotationTemplate = false; | ||||||
| 
 | 
 | ||||||
| 	private BeanResolver beanResolver; | 	private @Nullable BeanResolver beanResolver; | ||||||
| 
 | 
 | ||||||
| 	private ReactiveAdapterRegistry adapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); | 	private ReactiveAdapterRegistry adapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); | ||||||
| 
 | 
 | ||||||
| @ -159,7 +160,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu | |||||||
| 		// @formatter:on | 		// @formatter:on | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private Object resolveSecurityContext(MethodParameter parameter, Object securityContext) { | 	private @Nullable Object resolveSecurityContext(MethodParameter parameter, Object securityContext) { | ||||||
| 		CurrentSecurityContext contextAnno = findMethodAnnotation(parameter); | 		CurrentSecurityContext contextAnno = findMethodAnnotation(parameter); | ||||||
| 		if (contextAnno != null) { | 		if (contextAnno != null) { | ||||||
| 			return resolveSecurityContextFromAnnotation(contextAnno, parameter, securityContext); | 			return resolveSecurityContextFromAnnotation(contextAnno, parameter, securityContext); | ||||||
| @ -167,14 +168,17 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu | |||||||
| 		return securityContext; | 		return securityContext; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private Object resolveSecurityContextFromAnnotation(CurrentSecurityContext contextAnno, MethodParameter parameter, | 	private @Nullable Object resolveSecurityContextFromAnnotation(CurrentSecurityContext contextAnno, | ||||||
| 			Object securityContext) { | 			MethodParameter parameter, Object securityContext) { | ||||||
| 		String expressionToParse = contextAnno.expression(); | 		String expressionToParse = contextAnno.expression(); | ||||||
| 		if (StringUtils.hasLength(expressionToParse)) { | 		if (StringUtils.hasLength(expressionToParse)) { | ||||||
| 			StandardEvaluationContext context = new StandardEvaluationContext(); | 			StandardEvaluationContext context = new StandardEvaluationContext(); | ||||||
| 			context.setRootObject(securityContext); | 			context.setRootObject(securityContext); | ||||||
| 			context.setVariable("this", securityContext); | 			context.setVariable("this", securityContext); | ||||||
| 			context.setBeanResolver(this.beanResolver); | 			if (this.beanResolver != null) { | ||||||
|  | 				// https://github.com/spring-projects/spring-framework/issues/35371 | ||||||
|  | 				context.setBeanResolver(this.beanResolver); | ||||||
|  | 			} | ||||||
| 			Expression expression = this.parser.parseExpression(expressionToParse); | 			Expression expression = this.parser.parseExpression(expressionToParse); | ||||||
| 			securityContext = expression.getValue(context); | 			securityContext = expression.getValue(context); | ||||||
| 		} | 		} | ||||||
| @ -187,7 +191,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu | |||||||
| 		return securityContext; | 		return securityContext; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private boolean isInvalidType(MethodParameter parameter, Object value) { | 	private boolean isInvalidType(MethodParameter parameter, @Nullable Object value) { | ||||||
| 		if (value == null) { | 		if (value == null) { | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| @ -223,7 +227,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu | |||||||
| 	 * @param parameter the {@link MethodParameter} to search for an {@link Annotation} | 	 * @param parameter the {@link MethodParameter} to search for an {@link Annotation} | ||||||
| 	 * @return the {@link Annotation} that was found or null. | 	 * @return the {@link Annotation} that was found or null. | ||||||
| 	 */ | 	 */ | ||||||
| 	private CurrentSecurityContext findMethodAnnotation(MethodParameter parameter) { | 	private @Nullable CurrentSecurityContext findMethodAnnotation(MethodParameter parameter) { | ||||||
| 		if (this.useAnnotationTemplate) { | 		if (this.useAnnotationTemplate) { | ||||||
| 			return this.scanner.scan(parameter.getParameter()); | 			return this.scanner.scan(parameter.getParameter()); | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Reactive support for resolving security related arguments. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.handler.invocation.reactive; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -107,7 +107,7 @@ public final class PathPatternMessageMatcher implements MessageMatcher<Object> { | |||||||
| 		return (pathMatchInfo != null) ? MatchResult.match(pathMatchInfo.getUriVariables()) : MatchResult.notMatch(); | 		return (pathMatchInfo != null) ? MatchResult.match(pathMatchInfo.getUriVariables()) : MatchResult.notMatch(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static String getDestination(Message<?> message) { | 	private static @Nullable String getDestination(Message<?> message) { | ||||||
| 		return SimpMessageHeaderAccessor.getDestination(message.getHeaders()); | 		return SimpMessageHeaderAccessor.getDestination(message.getHeaders()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Support for matching messages. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.util.matcher; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -19,6 +19,8 @@ package org.springframework.security.messaging.web.csrf; | |||||||
| import java.security.MessageDigest; | import java.security.MessageDigest; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.messaging.Message; | import org.springframework.messaging.Message; | ||||||
| import org.springframework.messaging.MessageChannel; | import org.springframework.messaging.MessageChannel; | ||||||
| import org.springframework.messaging.simp.SimpMessageHeaderAccessor; | import org.springframework.messaging.simp.SimpMessageHeaderAccessor; | ||||||
| @ -70,7 +72,7 @@ public final class XorCsrfChannelInterceptor implements ChannelInterceptor { | |||||||
| 	 * @param actual | 	 * @param actual | ||||||
| 	 * @return | 	 * @return | ||||||
| 	 */ | 	 */ | ||||||
| 	private static boolean equalsConstantTime(String expected, String actual) { | 	private static boolean equalsConstantTime(String expected, @Nullable String actual) { | ||||||
| 		if (expected == actual) { | 		if (expected == actual) { | ||||||
| 			return true; | 			return true; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ package org.springframework.security.messaging.web.csrf; | |||||||
| 
 | 
 | ||||||
| import java.util.Base64; | import java.util.Base64; | ||||||
| 
 | 
 | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
|  | 
 | ||||||
| import org.springframework.security.crypto.codec.Utf8; | import org.springframework.security.crypto.codec.Utf8; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| 
 | 
 | ||||||
| @ -33,7 +35,7 @@ final class XorCsrfTokenUtils { | |||||||
| 	private XorCsrfTokenUtils() { | 	private XorCsrfTokenUtils() { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static String getTokenValue(String actualToken, String token) { | 	static @Nullable String getTokenValue(@Nullable String actualToken, String token) { | ||||||
| 		byte[] actualBytes; | 		byte[] actualBytes; | ||||||
| 		try { | 		try { | ||||||
| 			actualBytes = Base64.getUrlDecoder().decode(actualToken); | 			actualBytes = Base64.getUrlDecoder().decode(actualToken); | ||||||
|  | |||||||
| @ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Support CSRF protection in messages. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.web.csrf; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -19,6 +19,7 @@ package org.springframework.security.messaging.web.socket.server; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
| 
 | 
 | ||||||
| import jakarta.servlet.http.HttpServletRequest; | import jakarta.servlet.http.HttpServletRequest; | ||||||
|  | import org.jspecify.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import org.springframework.http.server.ServerHttpRequest; | import org.springframework.http.server.ServerHttpRequest; | ||||||
| import org.springframework.http.server.ServerHttpResponse; | import org.springframework.http.server.ServerHttpResponse; | ||||||
| @ -62,7 +63,7 @@ public final class CsrfTokenHandshakeInterceptor implements HandshakeInterceptor | |||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, | 	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, | ||||||
| 			Exception exception) { | 			@Nullable Exception exception) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,23 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2004-present the original author or authors. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Reactive Security CSRF protection. | ||||||
|  |  */ | ||||||
|  | @NullMarked | ||||||
|  | package org.springframework.security.messaging.web.socket.server; | ||||||
|  | 
 | ||||||
|  | import org.jspecify.annotations.NullMarked; | ||||||
| @ -74,7 +74,7 @@ public class ExpressionBasedMessageSecurityMetadataSourceFactoryTests { | |||||||
| 	@Test | 	@Test | ||||||
| 	public void createExpressionMessageMetadataSourceNoMatch() { | 	public void createExpressionMessageMetadataSourceNoMatch() { | ||||||
| 		Collection<ConfigAttribute> attrs = this.source.getAttributes(this.message); | 		Collection<ConfigAttribute> attrs = this.source.getAttributes(this.message); | ||||||
| 		assertThat(attrs).isNull(); | 		assertThat(attrs).isEmpty(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  | |||||||
| @ -67,8 +67,8 @@ public class DefaultMessageSecurityMetadataSourceTests { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void getAttributesNull() { | 	public void getAttributesEmpty() { | ||||||
| 		assertThat(this.source.getAttributes(this.message)).isNull(); | 		assertThat(this.source.getAttributes(this.message)).isEmpty(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user