Răsfoiți Sursa

Enable Null checking in spring-security-taglibs via JSpecify

Closes gh-17828
Rob Winch 1 săptămână în urmă
părinte
comite
5370f1190f

+ 4 - 0
taglibs/spring-security-taglibs.gradle

@@ -1,3 +1,7 @@
+plugins {
+	id 'apply-nullability'
+}
+
 apply plugin: 'io.spring.convention.spring-module'
 
 dependencies {

+ 20 - 8
taglibs/src/main/java/org/springframework/security/taglibs/authz/AbstractAuthorizeTag.java

@@ -24,6 +24,8 @@ import jakarta.servlet.ServletContext;
 import jakarta.servlet.ServletRequest;
 import jakarta.servlet.ServletResponse;
 import jakarta.servlet.http.HttpServletRequest;
+import org.jspecify.annotations.NullUnmarked;
+import org.jspecify.annotations.Nullable;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.GenericTypeResolver;
@@ -40,6 +42,7 @@ import org.springframework.security.web.FilterInvocation;
 import org.springframework.security.web.WebAttributes;
 import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
 import org.springframework.security.web.context.support.SecurityWebApplicationContextUtils;
+import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
 /**
@@ -60,11 +63,13 @@ import org.springframework.util.StringUtils;
  */
 public abstract class AbstractAuthorizeTag {
 
-	private String access;
+	@SuppressWarnings("NullAway.Init")
+	private @Nullable String access;
 
-	private String url;
+	@SuppressWarnings("NullAway.Init")
+	private @Nullable String url;
 
-	private String method = "GET";
+	private @Nullable String method = "GET";
 
 	/**
 	 * This method allows subclasses to provide a way to access the ServletRequest
@@ -112,14 +117,17 @@ public abstract class AbstractAuthorizeTag {
 	 * @return the result of the authorization decision
 	 * @throws IOException
 	 */
+	@SuppressWarnings("NullAway") // Dataflow analysis limitation
 	public boolean authorizeUsingAccessExpression() throws IOException {
 		if (getContext().getAuthentication() == null) {
 			return false;
 		}
+		String access = getAccess();
+		Assert.notNull(access, "access cannot be null");
 		SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler();
 		Expression accessExpression;
 		try {
-			accessExpression = handler.getExpressionParser().parseExpression(getAccess());
+			accessExpression = handler.getExpressionParser().parseExpression(access);
 		}
 		catch (ParseException ex) {
 			throw new IOException(ex);
@@ -143,13 +151,16 @@ public abstract class AbstractAuthorizeTag {
 	 * @return the result of the authorization decision
 	 * @throws IOException
 	 */
+	@SuppressWarnings("NullAway") // Dataflow analysis limitation
 	public boolean authorizeUsingUrlCheck() throws IOException {
+		String url = getUrl();
+		Assert.notNull(url, "url cannot be null");
 		String contextPath = ((HttpServletRequest) getRequest()).getContextPath();
 		Authentication currentUser = getContext().getAuthentication();
-		return getPrivilegeEvaluator().isAllowed(contextPath, getUrl(), getMethod(), currentUser);
+		return getPrivilegeEvaluator().isAllowed(contextPath, url, getMethod(), currentUser);
 	}
 
-	public String getAccess() {
+	public @Nullable String getAccess() {
 		return this.access;
 	}
 
@@ -157,7 +168,7 @@ public abstract class AbstractAuthorizeTag {
 		this.access = access;
 	}
 
-	public String getUrl() {
+	public @Nullable String getUrl() {
 		return this.url;
 	}
 
@@ -165,10 +176,11 @@ public abstract class AbstractAuthorizeTag {
 		this.url = url;
 	}
 
-	public String getMethod() {
+	public @Nullable String getMethod() {
 		return this.method;
 	}
 
+	@NullUnmarked
 	public void setMethod(String method) {
 		this.method = (method != null) ? method.toUpperCase(Locale.ENGLISH) : null;
 	}

+ 9 - 2
taglibs/src/main/java/org/springframework/security/taglibs/authz/AccessControlListTag.java

@@ -19,6 +19,7 @@ package org.springframework.security.taglibs.authz;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import jakarta.servlet.ServletContext;
 import jakarta.servlet.jsp.JspException;
@@ -27,6 +28,7 @@ import jakarta.servlet.jsp.tagext.Tag;
 import jakarta.servlet.jsp.tagext.TagSupport;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.jspecify.annotations.Nullable;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.security.access.PermissionEvaluator;
@@ -60,14 +62,18 @@ public class AccessControlListTag extends TagSupport {
 	private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
 		.getContextHolderStrategy();
 
+	@SuppressWarnings("NullAway.Init")
 	private ApplicationContext applicationContext;
 
+	@SuppressWarnings("NullAway.Init")
 	private Object domainObject;
 
+	@SuppressWarnings("NullAway.Init")
 	private PermissionEvaluator permissionEvaluator;
 
 	private String hasPermission = "";
 
+	@SuppressWarnings("NullAway.Init")
 	private String var;
 
 	@Override
@@ -148,7 +154,8 @@ public class AccessControlListTag extends TagSupport {
 			return;
 		}
 		this.applicationContext = getContext(this.pageContext);
-		this.permissionEvaluator = getBeanOfType(PermissionEvaluator.class);
+		this.permissionEvaluator = Objects.requireNonNull(getBeanOfType(PermissionEvaluator.class),
+				"PermissionEvaluator Bean is required");
 		String[] names = this.applicationContext.getBeanNamesForType(SecurityContextHolderStrategy.class);
 		if (names.length == 1) {
 			SecurityContextHolderStrategy strategy = this.applicationContext
@@ -157,7 +164,7 @@ public class AccessControlListTag extends TagSupport {
 		}
 	}
 
-	private <T> T getBeanOfType(Class<T> type) throws JspException {
+	private <T> @Nullable T getBeanOfType(Class<T> type) throws JspException {
 		Map<String, T> map = this.applicationContext.getBeansOfType(type);
 		for (ApplicationContext context = this.applicationContext.getParent(); context != null; context = context
 			.getParent()) {

+ 3 - 2
taglibs/src/main/java/org/springframework/security/taglibs/authz/AuthenticationTag.java

@@ -23,6 +23,7 @@ import jakarta.servlet.jsp.JspException;
 import jakarta.servlet.jsp.PageContext;
 import jakarta.servlet.jsp.tagext.Tag;
 import jakarta.servlet.jsp.tagext.TagSupport;
+import org.jspecify.annotations.Nullable;
 
 import org.springframework.beans.BeanWrapperImpl;
 import org.springframework.beans.BeansException;
@@ -49,9 +50,9 @@ public class AuthenticationTag extends TagSupport {
 	private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
 		.getContextHolderStrategy();
 
-	private String var;
+	private @Nullable String var;
 
-	private String property;
+	private @Nullable String property;
 
 	private int scope;
 

+ 12 - 8
taglibs/src/main/java/org/springframework/security/taglibs/authz/JspAuthorizeTag.java

@@ -25,6 +25,7 @@ import jakarta.servlet.ServletResponse;
 import jakarta.servlet.jsp.JspException;
 import jakarta.servlet.jsp.PageContext;
 import jakarta.servlet.jsp.tagext.Tag;
+import org.jspecify.annotations.Nullable;
 
 import org.springframework.expression.BeanResolver;
 import org.springframework.expression.ConstructorResolver;
@@ -49,13 +50,16 @@ import org.springframework.security.web.FilterInvocation;
  */
 public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
 
-	private Tag parent;
+	@SuppressWarnings("NullAway.Init")
+	private @Nullable Tag parent;
 
+	@SuppressWarnings("NullAway.Init")
 	protected PageContext pageContext;
 
-	protected String id;
+	protected @Nullable String id;
 
-	private String var;
+	@SuppressWarnings("NullAway.Init")
+	private @Nullable String var;
 
 	private boolean authorized;
 
@@ -104,7 +108,7 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
 		return EVAL_PAGE;
 	}
 
-	public String getId() {
+	public @Nullable String getId() {
 		return this.id;
 	}
 
@@ -113,7 +117,7 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
 	}
 
 	@Override
-	public Tag getParent() {
+	public @Nullable Tag getParent() {
 		return this.parent;
 	}
 
@@ -122,7 +126,7 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
 		this.parent = parent;
 	}
 
-	public String getVar() {
+	public @Nullable String getVar() {
 		return this.var;
 	}
 
@@ -205,12 +209,12 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
 		}
 
 		@Override
-		public BeanResolver getBeanResolver() {
+		public @Nullable BeanResolver getBeanResolver() {
 			return this.delegate.getBeanResolver();
 		}
 
 		@Override
-		public void setVariable(String name, Object value) {
+		public void setVariable(String name, @Nullable Object value) {
 			this.delegate.setVariable(name, value);
 		}
 

+ 3 - 0
taglibs/src/main/java/org/springframework/security/taglibs/authz/package-info.java

@@ -17,4 +17,7 @@
 /**
  * JSP Security tag library implementation.
  */
+@NullMarked
 package org.springframework.security.taglibs.authz;
+
+import org.jspecify.annotations.NullMarked;

+ 23 - 0
taglibs/src/main/java/org/springframework/security/taglibs/csrf/package-info.java

@@ -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.
+ */
+
+/**
+ * JSP Security tag library integration with CSRF protection.
+ */
+@NullMarked
+package org.springframework.security.taglibs.csrf;
+
+import org.jspecify.annotations.NullMarked;

+ 3 - 0
taglibs/src/main/java/org/springframework/security/taglibs/package-info.java

@@ -17,4 +17,7 @@
 /**
  * Security related tag libraries that can be used in JSPs and templates.
  */
+@NullMarked
 package org.springframework.security.taglibs;
+
+import org.jspecify.annotations.NullMarked;