diff --git a/access/src/main/java/org/springframework/security/access/annotation/Jsr250MethodSecurityMetadataSource.java b/access/src/main/java/org/springframework/security/access/annotation/Jsr250MethodSecurityMetadataSource.java index fc19138609..2e946e664d 100644 --- a/access/src/main/java/org/springframework/security/access/annotation/Jsr250MethodSecurityMetadataSource.java +++ b/access/src/main/java/org/springframework/security/access/annotation/Jsr250MethodSecurityMetadataSource.java @@ -31,6 +31,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.method.AbstractFallbackMethodSecurityMetadataSource; +import org.springframework.util.StringUtils; /** * Sources method security metadata from major JSR 250 security annotations. @@ -108,7 +109,7 @@ private String getRoleWithDefaultPrefix(String role) { if (role == null) { return role; } - if (this.defaultRolePrefix == null || this.defaultRolePrefix.length() == 0) { + if (!StringUtils.hasLength(this.defaultRolePrefix)) { return role; } if (role.startsWith(this.defaultRolePrefix)) { diff --git a/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java b/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java index cbfe9825cc..ba77e0ce2b 100644 --- a/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java +++ b/cas/src/main/java/org/springframework/security/cas/web/authentication/DefaultServiceAuthenticationDetails.java @@ -34,6 +34,7 @@ * and using the current URL minus the artifact and the corresponding value. * * @author Rob Winch + * @author Ngoc Nhan */ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails implements ServiceAuthenticationDetails { @@ -74,10 +75,9 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) { + if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails that)) { return false; } - ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj; return this.serviceUrl.equals(that.getServiceUrl()); } @@ -101,7 +101,11 @@ public String toString() { /** * If present, removes the artifactParameterName and the corresponding value from the * query String. - * @param request + * @param request the current {@link HttpServletRequest} to obtain the + * {@link #getServiceUrl()} from. + * @param artifactPattern the {@link Pattern} that will be used to clean up the query + * string from containing the artifact name and value. This can be created using + * {@link #createArtifactPattern(String)}. * @return the query String minus the artifactParameterName and the corresponding * value. */ @@ -111,7 +115,7 @@ public String toString() { return null; } String result = artifactPattern.matcher(query).replaceFirst(""); - if (result.length() == 0) { + if (result.isEmpty()) { return null; } // strip off the trailing & only if the artifact was the first query param @@ -122,8 +126,9 @@ public String toString() { * Creates a {@link Pattern} that can be passed into the constructor. This allows the * {@link Pattern} to be reused for every instance of * {@link DefaultServiceAuthenticationDetails}. - * @param artifactParameterName - * @return + * @param artifactParameterName the artifactParameterName that is removed from the + * current URL. The result becomes the service url. Cannot be null or an empty String. + * @return a {@link Pattern} */ static Pattern createArtifactPattern(String artifactParameterName) { Assert.hasLength(artifactParameterName, "artifactParameterName is expected to have a length"); diff --git a/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java b/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java index e0c35f7c2d..7aa5f50ac0 100644 --- a/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java +++ b/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java @@ -208,7 +208,8 @@ private boolean isGranted(AuthorizationManager authorizationManager) { /** * Convenience method to access {@link Authentication#getPrincipal()} from * {@link #getAuthentication()} - * @return + * @return the {@code Principal} being authenticated or the authenticated principal + * after authentication. */ public @Nullable Object getPrincipal() { return getAuthentication().getPrincipal(); diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/AbstractValidatingPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/AbstractValidatingPasswordEncoder.java index 930770e4b2..22db6fcc84 100644 --- a/crypto/src/main/java/org/springframework/security/crypto/password/AbstractValidatingPasswordEncoder.java +++ b/crypto/src/main/java/org/springframework/security/crypto/password/AbstractValidatingPasswordEncoder.java @@ -18,6 +18,18 @@ import org.jspecify.annotations.Nullable; +import org.springframework.util.StringUtils; + +/** + * An abstract {@link PasswordEncoder} that implementers can use for expecting the + * password to be non-{@code null}. Each common password API method is accompanied with an + * abstract method with a {@code NonNull} prefix. By implementing this, the concrete class + * is specifying what to do with the password when it is non-{@code null}, allowing this + * class to handle the {@code null} case. + * + * @author Rob Winch + * @since 7.0 + */ public abstract class AbstractValidatingPasswordEncoder implements PasswordEncoder { @Override @@ -32,18 +44,17 @@ public abstract class AbstractValidatingPasswordEncoder implements PasswordEncod @Override public final boolean matches(@Nullable CharSequence rawPassword, @Nullable String encodedPassword) { - if (rawPassword == null || rawPassword.length() == 0 || encodedPassword == null - || encodedPassword.length() == 0) { - return false; + if (StringUtils.hasLength(rawPassword) && StringUtils.hasLength(encodedPassword)) { + return matchesNonNull(rawPassword.toString(), encodedPassword); } - return matchesNonNull(rawPassword.toString(), encodedPassword); + return false; } protected abstract boolean matchesNonNull(String rawPassword, String encodedPassword); @Override public final boolean upgradeEncoding(@Nullable String encodedPassword) { - if (encodedPassword == null || encodedPassword.length() == 0) { + if (!StringUtils.hasLength(encodedPassword)) { return false; } return upgradeEncodingNonNull(encodedPassword); diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java index bf21ce6a54..f3ebed73a6 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java @@ -16,7 +16,6 @@ package org.springframework.security.web.authentication.rememberme; -import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -60,6 +59,7 @@ * @author Rob Winch * @author EddĂș MelĂ©ndez * @author Onur Kagan Ozcan + * @author Ngoc Nhan * @since 2.0 */ public abstract class AbstractRememberMeServices @@ -130,7 +130,7 @@ public void afterPropertiesSet() { return null; } this.logger.debug("Remember-me cookie detected"); - if (rememberMeCookie.length() == 0) { + if (rememberMeCookie.isEmpty()) { this.logger.debug("Cookie was empty"); cancelCookie(request, response); return null; @@ -171,7 +171,7 @@ public void afterPropertiesSet() { */ protected @Nullable String extractRememberMeCookie(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); - if ((cookies == null) || (cookies.length == 0)) { + if (cookies == null) { return null; } for (Cookie cookie : cookies) { @@ -221,12 +221,7 @@ protected String[] decodeCookie(String cookieValue) throws InvalidCookieExceptio } String[] tokens = StringUtils.delimitedListToStringArray(cookieAsPlainText, DELIMITER); for (int i = 0; i < tokens.length; i++) { - try { - tokens[i] = URLDecoder.decode(tokens[i], StandardCharsets.UTF_8.toString()); - } - catch (UnsupportedEncodingException ex) { - this.logger.error(ex.getMessage(), ex); - } + tokens[i] = URLDecoder.decode(tokens[i], StandardCharsets.UTF_8); } return tokens; } @@ -239,12 +234,7 @@ protected String[] decodeCookie(String cookieValue) throws InvalidCookieExceptio protected String encodeCookie(String[] cookieTokens) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < cookieTokens.length; i++) { - try { - sb.append(URLEncoder.encode(cookieTokens[i], StandardCharsets.UTF_8.toString())); - } - catch (UnsupportedEncodingException ex) { - this.logger.error(ex.getMessage(), ex); - } + sb.append(URLEncoder.encode(cookieTokens[i], StandardCharsets.UTF_8)); if (i < cookieTokens.length - 1) { sb.append(DELIMITER); } @@ -383,7 +373,7 @@ protected void setCookie(String[] tokens, int maxAge, HttpServletRequest request private String getCookiePath(HttpServletRequest request) { String contextPath = request.getContextPath(); - return (contextPath.length() > 0) ? contextPath : "/"; + return contextPath.isEmpty() ? "/" : contextPath; } /** diff --git a/web/src/main/java/org/springframework/security/web/firewall/RequestWrapper.java b/web/src/main/java/org/springframework/security/web/firewall/RequestWrapper.java index 59cbab7559..95aa9e7102 100644 --- a/web/src/main/java/org/springframework/security/web/firewall/RequestWrapper.java +++ b/web/src/main/java/org/springframework/security/web/firewall/RequestWrapper.java @@ -26,6 +26,8 @@ import jakarta.servlet.http.HttpServletRequest; import org.jspecify.annotations.Nullable; +import org.springframework.util.StringUtils; + /** * Request wrapper which ensures values of {@code servletPath} and {@code pathInfo} are * returned which are suitable for pattern matching against. It strips out path parameters @@ -44,6 +46,7 @@ * bypassed by the malicious addition of parameters to the path component. * * @author Luke Taylor + * @author Ngoc Nhan */ final class RequestWrapper extends FirewalledRequest { @@ -57,7 +60,7 @@ final class RequestWrapper extends FirewalledRequest { super(request); this.strippedServletPath = strip(request.getServletPath()); String pathInfo = strip(request.getPathInfo()); - if (pathInfo != null && pathInfo.length() == 0) { + if (!StringUtils.hasLength(pathInfo)) { pathInfo = null; } this.strippedPathInfo = pathInfo; diff --git a/web/src/main/java/org/springframework/security/web/savedrequest/DefaultSavedRequest.java b/web/src/main/java/org/springframework/security/web/savedrequest/DefaultSavedRequest.java index a20ade9de3..3f66fe2810 100644 --- a/web/src/main/java/org/springframework/security/web/savedrequest/DefaultSavedRequest.java +++ b/web/src/main/java/org/springframework/security/web/savedrequest/DefaultSavedRequest.java @@ -36,6 +36,7 @@ import org.springframework.security.web.util.UrlUtils; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponentsBuilder; /** @@ -100,7 +101,7 @@ public class DefaultSavedRequest implements SavedRequest { private final @Nullable String matchingRequestParameterName; public DefaultSavedRequest(HttpServletRequest request) { - this(request, (String) null); + this(request, null); } public DefaultSavedRequest(HttpServletRequest request, @Nullable String matchingRequestParameterName) { @@ -193,21 +194,17 @@ private void addLocale(Locale locale) { * @since 4.2 */ private void addParameters(Map parameters) { - if (!ObjectUtils.isEmpty(parameters)) { - for (String paramName : parameters.keySet()) { - Object paramValues = parameters.get(paramName); - if (paramValues instanceof String[]) { - this.addParameter(paramName, (String[]) paramValues); - } - else { - logger.warn("ServletRequest.getParameterMap() returned non-String array"); - } - } + if (ObjectUtils.isEmpty(parameters)) { + return; } - } - private void addParameter(String name, String[] values) { - this.parameters.put(name, values); + for (Map.Entry entry : parameters.entrySet()) { + String name = entry.getKey(); + String[] values = entry.getValue(); + if (values != null) { + this.parameters.put(name, values); + } + } } public @Nullable String getContextPath() { @@ -301,16 +298,6 @@ public int getServerPort() { return this.servletPath; } - private boolean propertyEquals(@Nullable Object arg1, Object arg2) { - if ((arg1 == null) && (arg2 == null)) { - return true; - } - if (arg1 == null || arg2 == null) { - return false; - } - return arg1.equals(arg2); - } - @Override public String toString() { return "DefaultSavedRequest [" + getRedirectUrl() + "]"; @@ -321,7 +308,7 @@ public String toString() { if (matchingRequestParameterName == null) { return queryString; } - if (queryString == null || queryString.length() == 0) { + if (!StringUtils.hasLength(queryString)) { return matchingRequestParameterName; } return UriComponentsBuilder.newInstance() diff --git a/web/src/main/java/org/springframework/security/web/util/TextEscapeUtils.java b/web/src/main/java/org/springframework/security/web/util/TextEscapeUtils.java index cdca910549..242c409e96 100644 --- a/web/src/main/java/org/springframework/security/web/util/TextEscapeUtils.java +++ b/web/src/main/java/org/springframework/security/web/util/TextEscapeUtils.java @@ -16,6 +16,8 @@ package org.springframework.security.web.util; +import org.springframework.util.StringUtils; + /** * Internal utility for escaping characters in HTML strings. * @@ -25,7 +27,7 @@ public abstract class TextEscapeUtils { public static String escapeEntities(String s) { - if (s == null || s.length() == 0) { + if (!StringUtils.hasLength(s)) { return s; } StringBuilder sb = new StringBuilder(); diff --git a/web/src/test/java/org/springframework/security/web/firewall/RequestWrapperTests.java b/web/src/test/java/org/springframework/security/web/firewall/RequestWrapperTests.java index c9294e4187..df14f37c1c 100644 --- a/web/src/test/java/org/springframework/security/web/firewall/RequestWrapperTests.java +++ b/web/src/test/java/org/springframework/security/web/firewall/RequestWrapperTests.java @@ -73,7 +73,7 @@ public void pathParametersAreRemovedFromPathInfo() { String path = entry.getKey(); String expectedResult = entry.getValue(); // Should be null when stripped value is empty - if (expectedResult.length() == 0) { + if (expectedResult.isEmpty()) { expectedResult = null; } request.setPathInfo(path);