Skip to content

Commit be64c67

Browse files
committed
Enable Null checking in spring-security-web via JSpecify
Closes gh-16882
1 parent a58f328 commit be64c67

27 files changed

+237
-36
lines changed

messaging/spring-security-messaging.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
plugins {
2+
id 'security-nullability'
3+
}
4+
15
apply plugin: 'io.spring.convention.spring-module'
26

37
dependencies {

messaging/src/main/java/org/springframework/security/messaging/access/expression/DefaultMessageSecurityExpressionHandler.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.jspecify.annotations.Nullable;
2222

23+
import org.springframework.expression.BeanResolver;
2324
import org.springframework.expression.EvaluationContext;
2425
import org.springframework.expression.spel.support.StandardEvaluationContext;
2526
import org.springframework.messaging.Message;
@@ -49,12 +50,16 @@ public EvaluationContext createEvaluationContext(Supplier<? extends @Nullable Au
4950
Message<T> message) {
5051
MessageSecurityExpressionRoot root = createSecurityExpressionRoot(authentication, message);
5152
StandardEvaluationContext ctx = new StandardEvaluationContext(root);
52-
ctx.setBeanResolver(getBeanResolver());
53+
BeanResolver beanResolver = getBeanResolver();
54+
if (beanResolver != null) {
55+
// https://github.com/spring-projects/spring-framework/issues/35371
56+
ctx.setBeanResolver(beanResolver);
57+
}
5358
return ctx;
5459
}
5560

5661
@Override
57-
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
62+
protected SecurityExpressionOperations createSecurityExpressionRoot(@Nullable Authentication authentication,
5863
Message<T> invocation) {
5964
return createSecurityExpressionRoot(() -> authentication, invocation);
6065
}

messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageAuthorizationContextSecurityExpressionHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public ExpressionParser getExpressionParser() {
5555
}
5656

5757
@Override
58-
public EvaluationContext createEvaluationContext(Authentication authentication,
58+
public EvaluationContext createEvaluationContext(@Nullable Authentication authentication,
5959
MessageAuthorizationContext<?> message) {
6060
return createEvaluationContext(() -> authentication, message);
6161
}

messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionConfigAttribute.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Map;
2020

21+
import org.jspecify.annotations.Nullable;
22+
2123
import org.springframework.expression.EvaluationContext;
2224
import org.springframework.expression.Expression;
2325
import org.springframework.messaging.Message;
@@ -60,7 +62,7 @@ Expression getAuthorizeExpression() {
6062
}
6163

6264
@Override
63-
public String getAttribute() {
65+
public @Nullable String getAttribute() {
6466
return null;
6567
}
6668

messaging/src/main/java/org/springframework/security/messaging/access/expression/MessageExpressionVoter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Collection;
2020

21+
import org.jspecify.annotations.Nullable;
22+
2123
import org.springframework.expression.EvaluationContext;
2224
import org.springframework.messaging.Message;
2325
import org.springframework.security.access.AccessDecisionVoter;
@@ -60,7 +62,7 @@ public int vote(Authentication authentication, Message<T> message, Collection<Co
6062
return ExpressionUtils.evaluateAsBoolean(attr.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED : ACCESS_DENIED;
6163
}
6264

63-
private MessageExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
65+
private @Nullable MessageExpressionConfigAttribute findConfigAttribute(Collection<ConfigAttribute> attributes) {
6466
for (ConfigAttribute attribute : attributes) {
6567
if (attribute instanceof MessageExpressionConfigAttribute) {
6668
return (MessageExpressionConfigAttribute) attribute;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Security expression support for {@link org.springframework.messaging.Message}.
19+
*/
20+
@NullMarked
21+
package org.springframework.security.messaging.access.expression;
22+
23+
import org.jspecify.annotations.NullMarked;

messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.apache.commons.logging.Log;
2222
import org.apache.commons.logging.LogFactory;
23+
import org.jspecify.annotations.Nullable;
2324

2425
import org.springframework.core.log.LogMessage;
2526
import org.springframework.messaging.Message;
@@ -110,7 +111,7 @@ private static class NoopAuthorizationEventPublisher implements AuthorizationEve
110111

111112
@Override
112113
public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
113-
AuthorizationResult result) {
114+
@Nullable AuthorizationResult result) {
114115

115116
}
116117

messaging/src/main/java/org/springframework/security/messaging/access/intercept/ChannelSecurityInterceptor.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.messaging.access.intercept;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
import org.springframework.messaging.Message;
2022
import org.springframework.messaging.MessageChannel;
2123
import org.springframework.messaging.support.ChannelInterceptor;
@@ -83,7 +85,7 @@ public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
8385
}
8486

8587
@Override
86-
public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex) {
88+
public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, @Nullable Exception ex) {
8789
InterceptorStatusToken token = clearToken();
8890
finallyInvocation(token);
8991
}
@@ -99,7 +101,7 @@ public Message<?> postReceive(Message<?> message, MessageChannel channel) {
99101
}
100102

101103
@Override
102-
public void afterReceiveCompletion(Message<?> message, MessageChannel channel, Exception ex) {
104+
public void afterReceiveCompletion(@Nullable Message<?> message, MessageChannel channel, @Nullable Exception ex) {
103105
}
104106

105107
private InterceptorStatusToken clearToken() {

messaging/src/main/java/org/springframework/security/messaging/access/intercept/DefaultMessageSecurityMetadataSource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.security.messaging.access.intercept;
1818

1919
import java.util.Collection;
20+
import java.util.Collections;
2021
import java.util.HashSet;
2122
import java.util.LinkedHashMap;
2223
import java.util.Map;
@@ -61,7 +62,7 @@ public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalAr
6162
return entry.getValue();
6263
}
6364
}
64-
return null;
65+
return Collections.emptyList();
6566
}
6667

6768
@Override

messaging/src/main/java/org/springframework/security/messaging/access/intercept/MessageMatcherDelegatingAuthorizationManager.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ private MessageMatcherDelegatingAuthorizationManager(
5555
}
5656

5757
@Override
58-
public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
58+
public @Nullable AuthorizationResult authorize(Supplier<? extends @Nullable Authentication> authentication,
5959
Message<?> message) {
6060
if (this.logger.isTraceEnabled()) {
6161
this.logger.trace(LogMessage.format("Authorizing message"));
@@ -75,7 +75,8 @@ public AuthorizationResult authorize(Supplier<? extends @Nullable Authentication
7575
return null;
7676
}
7777

78-
private MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> matcher, Message<?> message) {
78+
private @Nullable MessageAuthorizationContext<?> authorizationContext(MessageMatcher<?> matcher,
79+
Message<?> message) {
7980
MessageMatcher.MatchResult matchResult = matcher.matcher((Message) message);
8081
if (!matchResult.isMatch()) {
8182
return null;
@@ -179,7 +180,7 @@ public Builder.Constraint simpSubscribeDestMatchers(String... patterns) {
179180
* @return the {@link Builder.Constraint} that is associated to the
180181
* {@link MessageMatcher}
181182
*/
182-
private Builder.Constraint simpDestMatchers(SimpMessageType type, String... patterns) {
183+
private Builder.Constraint simpDestMatchers(@Nullable SimpMessageType type, String... patterns) {
183184
List<MessageMatcher<?>> matchers = new ArrayList<>(patterns.length);
184185
for (String pattern : patterns) {
185186
MessageMatcher<Object> matcher = this.messageMatcherBuilder.matcher(type, pattern);

0 commit comments

Comments
 (0)