1
0
mirror of synced 2026-08-06 10:18:52 +00:00

Compare commits

...

50 Commits

Author SHA1 Message Date
Josh Cummings 33aba4fd64 Release 5.0.19.RELEASE 2020-10-07 10:47:38 -06:00
Eleftheria Stein 7641dc0f3b Update to Hibernate Validator 6.0.21
Closes gh-9069
2020-10-01 19:09:15 +02:00
Eleftheria Stein 66b52c5d5f Update to org.aspectj 1.9.6
Closes gh-9067
2020-10-01 19:08:55 +02:00
Eleftheria Stein d86b1492a2 Update to Jackson Databind 2.9.10.6
Closes gh-9065
2020-10-01 19:08:33 +02:00
Eleftheria Stein 50c1c5e082 Update to Spring Framework 5.0.19
Closes gh-9064
2020-10-01 19:08:06 +02:00
Eleftheria Stein 2a9b41df61 Update to GAE 1.9.82
Closes gh-9066
2020-10-01 19:07:34 +02:00
Malyshau Stanislau 430407ea45 Add try-with-resources to close stream
Closes gh-9041
2020-09-29 08:56:40 -06:00
Artem Grankin 7358eb2b48 Replace expired msdn link with latest web archive copy
Initial link expired in March, 2016. Latest copy found in web archive is from February, 2016
2020-09-28 17:47:25 -06:00
Josh Cummings 50faf5b3f2 Next Development Version 2020-08-05 09:11:50 -06:00
Josh Cummings 1fd4e940f4 Release 5.0.18.RELEASE 2020-08-05 07:47:14 -06:00
Josh Cummings 8a8b389907 Update to Spring Ldap 2.3.3
Closes gh-8933
2020-08-05 07:45:14 -06:00
Josh Cummings d51dd0450d Update to Hibernate Validator 6.0.20
Closes gh-8932
2020-08-05 07:45:09 -06:00
Josh Cummings 5c0b080eb6 Update to Groovy 2.4.20
Closes gh-8931
2020-08-05 07:44:44 -06:00
Josh Cummings b5b3ef979f Update to Google App Engine 1.9.81
Closes gh-8930
2020-08-05 07:44:37 -06:00
Josh Cummings d5c264792a Update to Jackson Databind 2.9.10.5
Closes gh-8929
2020-08-05 07:44:30 -06:00
Josh Cummings f280d6e90e Update to Spring Framework 5.0.18
Closes gh-8928
2020-08-05 07:44:03 -06:00
Josh Cummings 2303ac3d6f Polish WebSecurityConfigurerAdapter JavaDoc
Issue gh-8784
2020-07-20 15:25:39 -06:00
Romil Patel ef442def43 WebSecurityConfigurerAdapter JavaDoc
Closes gh-8784
2020-07-20 15:25:36 -06:00
wangsong 502d28f1b9 Fix ProviderManager Javadoc typo
Closes gh-8800
2020-07-07 17:18:04 -05:00
Ellie Bahadori aa5a42cfbc Use Github Actions workflow for PRs and remove Travis
Closes gh-8716
2020-06-30 05:24:55 -04:00
Rob Winch 5802954130 Better scp Retry Settings 2020-06-25 11:37:09 -05:00
Evgeniy Cheban b4e51e7740 DefaultWebSecurityExpressionHandler uses RoleHierarchy bean
Fixes gh-7059
2020-06-11 08:37:09 -04:00
Eleftheria Stein e0169eaea8 Next development version 2020-06-03 18:36:01 -04:00
Eleftheria Stein bcaad3a51c Release 5.0.17.RELEASE 2020-06-03 18:12:04 -04:00
Josh Cummings 66f8a56b1b Polish setAllowedHostnames
Added JavaDoc to method, including @since attribute

Issue gh-4310
2020-06-03 08:48:46 -06:00
Eddú Meléndez 3e5b65f647 Add support for allowedHostnames in StrictHttpFirewall
Introduce a new method `setAllowedHostnames` which perform the validation
against untrusted hostnames.

Fixes gh-4310
2020-06-03 08:48:38 -06:00
Eleftheria Stein c62789c976 Update to okhttp 3.12.12
Fixes gh-8637
2020-06-02 22:05:05 -04:00
Eleftheria Stein b02cae0a0c Update to Jython 2.5.3
Fixes gh-8638
2020-06-02 22:04:02 -04:00
Eleftheria Stein af278b58b5 Update to mockwebserver 3.12.12
Fixes gh-8636
2020-06-02 22:03:22 -04:00
justmehyp ba81f6a06a Remove unused field 'digester' in Md4PasswordEncoder
`private Digester digester;`  defined in Md4PasswordEncoder is never used. So remove it.

Closes gh-8553
2020-05-21 11:21:58 -05:00
Maksim Vinogradov a39efaf883 Prevent StackOverflowError for AccessControlEntryImpl.hashCode
Getting StackOverflowError when invoke AclImpl.hashCode because of
cross-references between AclImpl and AccessControlEntryImpl

Remove from AccessControlEntryImpl.hashCode method invocation of
acl.hashCode

fixes gh-5401
2020-05-21 10:09:22 -05:00
Rob Winch 7d5e032e25 Revert "Create the CSRF token on the bounded elactic scheduler"
This reverts commit e21ef422e7.
2020-05-18 11:09:41 -05:00
cbornet e21ef422e7 Create the CSRF token on the bounded elactic scheduler
The CSRF token is created with a call to UUID.randomUUID which is blocking.
This change ensures this blocking call is done on the bounded elastic scheduler which supports blocking calls.

Fixes gh-8128
2020-05-18 11:07:41 -05:00
Artyom Tarynin 66f923dab7 Update AntPathRequestMatcher.java
Fixes gh-8512
2020-05-14 10:58:32 -04:00
Dávid Kovács e8daeacd89 Document NoOpPasswordEncoder will not be removed
This commit adds extension to deprecation notice.

Fixes gh-8506
2020-05-13 12:57:04 -05:00
Rob Winch 27f30b04cd Remove Broken Test
Issue gh-8518
2020-05-12 13:38:42 -05:00
Rob Winch baa238e339 Fix non-standard HTTP method for CsrfWebFilter
Closes gh-8452
2020-05-12 13:22:04 -05:00
Eleftheria Stein cf5bd52121 Next development version 2020-05-06 16:40:35 -04:00
Eleftheria Stein ef78626045 Release 5.0.16.RELEASE 2020-05-06 16:25:17 -04:00
Eleftheria Stein 7f8efb7680 Update to GAE 1.9.80
Closes gh-8479
2020-05-06 12:27:50 -04:00
Eleftheria Stein 2c4d13ddef Update to org.powermock 2.0.7
Closes gh-8478
2020-05-06 12:26:42 -04:00
Eleftheria Stein ed2a646a69 Update to Spring Framework 5.0.17.RELEASE
Closes gh-8477
2020-05-06 12:25:59 -04:00
Eleftheria Stein f8f4d960b5 Clean up Javadoc
Fixes gh-8480
2020-05-05 17:34:53 -04:00
Rob Winch 76a4df0461 Add ROLE_INFRASTRUCTURE to infrastructure beans
Closes gh-8407
2020-04-27 09:23:40 -05:00
Dávid Kovács 7eee6b102f ActiveDirectoryLdapAuthenticationProvider uses InternalAuthenticationServiceException
Closes gh-2884
2020-04-24 10:44:21 -05:00
Rob Winch d69288e665 Fix example in javadoc of FilterChainProxy
Closes gh-8344
2020-04-08 09:15:03 -05:00
Alan Czajkowski 62bc17ea3f BCryptPasswordEncoder rawPassword cannot be null
Closes gh-8317
2020-04-07 13:48:07 -05:00
hotire fd2798ca95 Fix typo in Javadoc of ServerHttpSecurity#hasAuthority
Closes gh-8336
2020-04-06 14:21:16 -05:00
Eleftheria Stein 173660c6ef Fix HttpSecurity Javadoc
Fixes gh-4404
2020-04-02 12:04:24 -04:00
Eleftheria Stein d6aa6a2246 Next Development Version 2020-04-01 16:29:44 -04:00
34 changed files with 290 additions and 84 deletions
+22
View File
@@ -0,0 +1,22 @@
name: PR Build
on: pull_request
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '8'
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Build with Gradle
run: ./gradlew clean build --continue
-16
View File
@@ -1,16 +0,0 @@
language: java
jdk:
- openjdk8
os:
- linux
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
script: ./gradlew build --refresh-dependencies --no-daemon --continue
-2
View File
@@ -1,7 +1,5 @@
image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
image:https://travis-ci.org/spring-projects/spring-security.svg?branch=master["Build Status", link="https://travis-ci.org/spring-projects/spring-security"]
= Spring Security
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 5.0 requires Spring 5.0 as
@@ -1,5 +1,5 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
* Copyright 2002-2016 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.
@@ -131,10 +131,9 @@ public class AccessControlEntryImpl implements AccessControlEntry,
@Override
public int hashCode() {
int result = this.acl.hashCode();
result = 31 * result + this.permission.hashCode();
int result = this.permission.hashCode();
result = 31 * result + (this.id != null ? this.id.hashCode() : 0);
result = 31 * result + this.sid.hashCode();
result = 31 * result + (this.sid.hashCode());
result = 31 * result + (this.auditFailure ? 1 : 0);
result = 31 * result + (this.auditSuccess ? 1 : 0);
result = 31 * result + (this.granting ? 1 : 0);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2019 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.
@@ -560,6 +560,25 @@ public class AclImplTests {
childAcl.setParent(changeParentAcl);
}
@Test
public void hashCodeWithoutStackOverFlow() throws Exception {
//given
Sid sid = new PrincipalSid("pSid");
ObjectIdentity oid = new ObjectIdentityImpl("type", 1);
AclAuthorizationStrategy authStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("role"));
PermissionGrantingStrategy grantingStrategy = new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
AclImpl acl = new AclImpl(oid, 1L, authStrategy, grantingStrategy, null, null, false, sid);
AccessControlEntryImpl ace = new AccessControlEntryImpl(1L, acl, sid, BasePermission.READ, true, true, true);
Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
fieldAces.setAccessible(true);
List<AccessControlEntryImpl> aces = (List<AccessControlEntryImpl>) fieldAces.get(acl);
aces.add(ace);
//when - then none StackOverFlowError been raised
ace.hashCode();
}
// ~ Inner Classes
// ==================================================================================================
@@ -16,8 +16,10 @@
package org.springframework.security.config.annotation.configuration;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -34,9 +36,11 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
* @since 3.2
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ObjectPostProcessorConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ObjectPostProcessor<Object> objectPostProcessor(
AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
@@ -28,8 +28,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
@@ -80,6 +82,7 @@ import org.springframework.util.Assert;
* @see EnableGlobalMethodSecurity
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class GlobalMethodSecurityConfiguration
implements ImportAware, SmartInitializingSingleton {
private static final Log logger = LogFactory
@@ -15,14 +15,18 @@
*/
package org.springframework.security.config.annotation.method.configuration;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
class Jsr250MetadataSourceConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource() {
return new Jsr250MethodSecurityMetadataSource();
}
@@ -49,6 +49,7 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public DelegatingMethodSecurityMetadataSource methodMetadataSource() {
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
new DefaultMethodSecurityExpressionHandler());
@@ -69,6 +70,7 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
@@ -584,6 +584,7 @@ public final class HttpSecurity extends
/**
* Allows restricting access based upon the {@link HttpServletRequest} using
* {@link RequestMatcher} implementations (i.e. via URL patterns).
*
* <h2>Example Configurations</h2>
*
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2020 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.
@@ -31,6 +31,7 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityBuilder;
@@ -74,6 +75,7 @@ import org.springframework.web.filter.DelegatingFilterProxy;
* @see WebSecurityConfiguration
*
* @author Rob Winch
* @author Evgeniy Cheban
* @since 3.2
*/
public final class WebSecurity extends
@@ -383,6 +385,11 @@ public final class WebSecurity extends
throws BeansException {
this.defaultWebSecurityExpressionHandler
.setApplicationContext(applicationContext);
try {
this.defaultWebSecurityExpressionHandler.setRoleHierarchy(applicationContext.getBean(RoleHierarchy.class));
} catch (NoSuchBeanDefinitionException e) {}
try {
this.defaultWebSecurityExpressionHandler.setPermissionEvaluator(applicationContext.getBean(
PermissionEvaluator.class));
@@ -332,6 +332,13 @@ public abstract class WebSecurityConfigurerAdapter implements
/**
* Override this method to configure {@link WebSecurity}. For example, if you wish to
* ignore certain requests.
*
* Endpoints specified in this method will be ignored by Spring Security, meaning it
* will not protect them from CSRF, XSS, Clickjacking, and so on.
*
* Instead, if you want to protect endpoints against common vulnerabilities, then see
* {@link #configure(HttpSecurity)} and the {@link HttpSecurity#authorizeRequests}
* configuration method.
*/
public void configure(WebSecurity web) throws Exception {
}
@@ -345,6 +352,10 @@ public abstract class WebSecurityConfigurerAdapter implements
* http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
* </pre>
*
* Any endpoint that requires defense against common vulnerabilities can be specified here, including public ones.
* See {@link HttpSecurity#authorizeRequests} and the `permitAll()` authorization rule
* for more details on public endpoints.
*
* @param http the {@link HttpSecurity} to modify
* @throws Exception if an error occurs
*/
@@ -160,7 +160,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
*
* <p>
* Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
* "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
* "https://web.archive.org/web/20160201174302/https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
* >X-XSS-Protection header</a>
* </p>
*
@@ -675,7 +675,7 @@ public class ServerHttpSecurity {
/**
* Require a specific authority.
* @param authority the authority to require (i.e. "USER" woudl require authority of "USER").
* @param authority the authority to require (i.e. "USER" would require authority of "USER").
* @return the {@link AuthorizeExchangeSpec} to configure
*/
public AuthorizeExchangeSpec hasAuthority(String authority) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@@ -45,6 +45,8 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -68,6 +70,7 @@ import org.springframework.web.bind.annotation.RestController;
*
* @author Rob Winch
* @author Joe Grandja
* @author Evgeniy Cheban
*/
public class WebSecurityConfigurationTests {
@Rule
@@ -270,6 +273,31 @@ public class WebSecurityConfigurationTests {
}
}
@Test
public void securityExpressionHandlerWhenRoleHierarchyBeanThenRoleHierarchyUsed() {
this.spring.register(WebSecurityExpressionHandlerRoleHierarchyBeanConfig.class).autowire();
TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "notused", "ROLE_ADMIN");
FilterInvocation invocation = new FilterInvocation(new MockHttpServletRequest("GET", ""),
new MockHttpServletResponse(), new MockFilterChain());
AbstractSecurityExpressionHandler handler = this.spring.getContext().getBean(AbstractSecurityExpressionHandler.class);
EvaluationContext evaluationContext = handler.createEvaluationContext(authentication, invocation);
Expression expression = handler.getExpressionParser()
.parseExpression("hasRole('ROLE_USER')");
boolean granted = expression.getValue(evaluationContext, Boolean.class);
assertThat(granted).isTrue();
}
@EnableWebSecurity
static class WebSecurityExpressionHandlerRoleHierarchyBeanConfig extends WebSecurityConfigurerAdapter {
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
return roleHierarchy;
}
}
@Test
public void securityExpressionHandlerWhenPermissionEvaluatorBeanThenPermissionEvaluatorUsed() throws Exception {
this.spring.register(WebSecurityExpressionHandlerPermissionEvaluatorBeanConfig.class).autowire();
@@ -218,7 +218,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
((CredentialsContainer) result).eraseCredentials();
}
// If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent
// If the parent AuthenticationManager was attempted and successful then it will publish an AuthenticationSuccessEvent
// This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
if (parentResult == null) {
eventPublisher.publishAuthenticationSuccess(result);
@@ -235,7 +235,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
"No AuthenticationProvider found for {0}"));
}
// If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent
// If the parent AuthenticationManager was attempted and failed then it will publish an AbstractAuthenticationFailureEvent
// This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
if (parentException == null) {
prepareException(lastException, authentication);
@@ -21,6 +21,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.SpringVersion;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
@@ -108,8 +109,9 @@ public class SpringSecurityCoreVersion {
*/
private static String getSpringVersion() {
Properties properties = new Properties();
try {
properties.load(SpringSecurityCoreVersion.class.getClassLoader().getResourceAsStream("META-INF/spring-security.versions"));
try (InputStream is = SpringSecurityCoreVersion.class.getClassLoader()
.getResourceAsStream("META-INF/spring-security.versions")) {
properties.load(is);
} catch (IOException e) {
return null;
}
@@ -31,6 +31,7 @@ DigestAuthenticationFilter.usernameNotFound=Username {0} not found
JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
JdbcDaoImpl.notFound=User {0} not found
LdapAuthenticationProvider.badCredentials=Bad credentials
LdapAuthenticationProvider.badLdapConnection=Connection to LDAP server failed
LdapAuthenticationProvider.credentialsExpired=User credentials have expired
LdapAuthenticationProvider.disabled=User is disabled
LdapAuthenticationProvider.expired=User account has expired
@@ -65,6 +65,10 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
}
public String encode(CharSequence rawPassword) {
if (rawPassword == null) {
throw new IllegalArgumentException("rawPassword cannot be null");
}
String salt;
if (strength > 0) {
if (random != null) {
@@ -81,6 +85,10 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (rawPassword == null) {
throw new IllegalArgumentException("rawPassword cannot be null");
}
if (encodedPassword == null || encodedPassword.length() == 0) {
logger.warn("Empty encoded password");
return false;
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2016 the original author or authors.
* Copyright 2011-2020 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.
@@ -32,7 +32,7 @@ public class Encryptors {
* (Password-Based Key Derivation Function #2). Salts the password to prevent
* dictionary attacks against the key. The provided salt is expected to be
* hex-encoded; it should be random and at least 8 bytes in length. Also applies a
* random 16 byte initialization vector to ensure each encrypted message will be
* random 16-byte initialization vector to ensure each encrypted message will be
* unique. Requires Java 6.
*
* @param password the password used to generate the encryptor's secret key; should
@@ -50,7 +50,7 @@ public class Encryptors {
* Derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation
* Function #2). Salts the password to prevent dictionary attacks against the key. The
* provided salt is expected to be hex-encoded; it should be random and at least 8
* bytes in length. Also applies a random 16 byte initialization vector to ensure each
* bytes in length. Also applies a random 16-byte initialization vector to ensure each
* encrypted message will be unique. Requires Java 6.
* NOTE: This mode is not
* <a href="https://en.wikipedia.org/wiki/Authenticated_encryption">authenticated</a>
@@ -63,7 +63,7 @@ public class Encryptors {
* @param salt a hex-encoded, random, site-global salt value to use to generate the
* key
*
* @see #stronger(CharSequence, CharSequence) which uses the significatly more secure
* @see #stronger(CharSequence, CharSequence), which uses the significatly more secure
* GCM (instead of CBC)
*/
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
@@ -105,7 +105,10 @@ public class Encryptors {
* not be shared
* @param salt a hex-encoded, random, site-global salt value to use to generate the
* secret key
* @deprecated This encryptor is not secure. Instead, look to your data store for a
* mechanism to query encrypted data.
*/
@Deprecated
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(),
salt));
@@ -83,8 +83,6 @@ public class Md4PasswordEncoder implements PasswordEncoder {
private StringKeyGenerator saltGenerator = new Base64StringKeyGenerator();
private boolean encodeHashAsBase64;
private Digester digester;
public void setEncodeHashAsBase64(boolean encodeHashAsBase64) {
this.encodeHashAsBase64 = encodeHashAsBase64;
@@ -26,7 +26,8 @@ package org.springframework.security.crypto.password;
* @deprecated This PasswordEncoder is not secure. Instead use an
* adaptive one way function like BCryptPasswordEncoder, Pbkdf2PasswordEncoder, or
* SCryptPasswordEncoder. Even better use {@link DelegatingPasswordEncoder} which supports
* password upgrades.
* password upgrades. There are no plans to remove this support. It is deprecated to indicate that
* this is a legacy implementation and using it is considered insecure.
*/
@Deprecated
public final class NoOpPasswordEncoder implements PasswordEncoder {
@@ -92,4 +92,15 @@ public class BCryptPasswordEncoderTests {
assertThat(encoder.matches("password", "012345678901234567890123456789")).isFalse();
}
@Test(expected = IllegalArgumentException.class)
public void encodeNullRawPassword() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
encoder.encode(null);
}
@Test(expected = IllegalArgumentException.class)
public void matchNullRawPassword() {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
encoder.matches(null, "does-not-matter");
}
}
@@ -10,6 +10,13 @@ asciidoctor {
'gh-samples-url': "$ghUrl/samples"
}
remotes {
docs {
retryCount = 5 // retry 5 times (default is 0)
retryWaitSec = 10 // wait 10 seconds between retries (default is 0)
}
}
docsZip {
from(project(':spring-security-docs-guides').asciidoctor) {
into 'guides'
+2 -2
View File
@@ -1,3 +1,3 @@
gaeVersion=1.9.79
gaeVersion=1.9.82
springBootVersion=2.0.9.RELEASE
version=5.0.15.RELEASE
version=5.0.19.RELEASE
+24 -24
View File
@@ -1,22 +1,22 @@
dependencyManagement {
imports {
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR17'
mavenBom 'org.springframework:spring-framework-bom:5.0.16.RELEASE'
mavenBom 'org.springframework:spring-framework-bom:5.0.19.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR14'
}
dependencies {
dependency 'cglib:cglib-nodep:3.2.12'
dependency 'com.squareup.okhttp3:mockwebserver:3.12.10'
dependency 'com.squareup.okhttp3:mockwebserver:3.12.12'
dependency 'opensymphony:sitemesh:2.4.2'
dependency 'org.gebish:geb-spock:0.10.0'
dependency 'org.jasig.cas:cas-server-webapp:4.2.7'
dependency 'org.powermock:powermock-api-mockito2:2.0.6'
dependency 'org.powermock:powermock-api-support:2.0.6'
dependency 'org.powermock:powermock-core:2.0.6'
dependency 'org.powermock:powermock-module-junit4-common:2.0.6'
dependency 'org.powermock:powermock-module-junit4:2.0.6'
dependency 'org.powermock:powermock-reflect:2.0.6'
dependency 'org.python:jython:2.5.0'
dependency 'org.powermock:powermock-api-mockito2:2.0.7'
dependency 'org.powermock:powermock-api-support:2.0.7'
dependency 'org.powermock:powermock-core:2.0.7'
dependency 'org.powermock:powermock-module-junit4-common:2.0.7'
dependency 'org.powermock:powermock-module-junit4:2.0.7'
dependency 'org.powermock:powermock-reflect:2.0.7'
dependency 'org.python:jython:2.5.3'
dependency 'org.spockframework:spock-core:1.0-groovy-2.4'
dependency 'org.spockframework:spock-spring:1.0-groovy-2.4'
}
@@ -30,21 +30,21 @@ dependencyManagement {
dependency 'ch.qos.logback:logback-core:1.2.3'
dependency 'com.fasterxml.jackson.core:jackson-annotations:2.9.10'
dependency 'com.fasterxml.jackson.core:jackson-core:2.9.10'
dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.10.2'
dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.10.6'
dependency 'com.fasterxml:classmate:1.3.4'
dependency 'com.github.stephenc.jcip:jcip-annotations:1.0-1'
dependency 'com.google.appengine:appengine-api-1.0-sdk:1.9.76'
dependency 'com.google.appengine:appengine-api-labs:1.9.76'
dependency 'com.google.appengine:appengine-api-stubs:1.9.76'
dependency 'com.google.appengine:appengine-testing:1.9.76'
dependency 'com.google.appengine:appengine:1.9.76'
dependency 'com.google.appengine:appengine-api-1.0-sdk:1.9.82'
dependency 'com.google.appengine:appengine-api-labs:1.9.82'
dependency 'com.google.appengine:appengine-api-stubs:1.9.82'
dependency 'com.google.appengine:appengine-testing:1.9.82'
dependency 'com.google.appengine:appengine:1.9.82'
dependency 'com.google.code.gson:gson:2.8.2'
dependency 'com.google.guava:guava:20.0'
dependency 'com.google.inject:guice:3.0'
dependency 'com.nimbusds:lang-tag:1.4.3'
dependency 'com.nimbusds:nimbus-jose-jwt:5.14'
dependency 'com.nimbusds:oauth2-oidc-sdk:5.64.4'
dependency 'com.squareup.okhttp3:okhttp:3.12.10'
dependency 'com.squareup.okhttp3:okhttp:3.12.12'
dependency 'com.squareup.okio:okio:1.13.0'
dependency 'com.sun.xml.bind:jaxb-core:2.3.0.1'
dependency 'com.sun.xml.bind:jaxb-impl:2.3.0.1'
@@ -128,16 +128,16 @@ dependencyManagement {
dependency 'org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.0.44'
dependency 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.23'
dependency 'org.apache.tomcat:tomcat-annotations-api:8.5.23'
dependency 'org.aspectj:aspectjrt:1.9.5'
dependency 'org.aspectj:aspectjtools:1.9.5'
dependency 'org.aspectj:aspectjweaver:1.9.5'
dependency 'org.aspectj:aspectjrt:1.9.6'
dependency 'org.aspectj:aspectjtools:1.9.6'
dependency 'org.aspectj:aspectjweaver:1.9.6'
dependency 'org.assertj:assertj-core:3.11.1'
dependency 'org.attoparser:attoparser:2.0.4.RELEASE'
dependency 'org.bouncycastle:bcpkix-jdk15on:1.64'
dependency 'org.bouncycastle:bcprov-jdk15on:1.64'
dependency 'org.codehaus.groovy:groovy-all:2.4.19'
dependency 'org.codehaus.groovy:groovy-json:2.4.19'
dependency 'org.codehaus.groovy:groovy:2.4.19'
dependency 'org.codehaus.groovy:groovy-all:2.4.20'
dependency 'org.codehaus.groovy:groovy-json:2.4.20'
dependency 'org.codehaus.groovy:groovy:2.4.20'
dependency 'org.eclipse.jdt:ecj:3.12.3'
dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.7.v20170914'
dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.7.v20170914'
@@ -160,7 +160,7 @@ dependencyManagement {
dependency 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
dependency 'org.hibernate:hibernate-core:5.2.18.Final'
dependency 'org.hibernate:hibernate-entitymanager:5.2.18.Final'
dependency 'org.hibernate:hibernate-validator:6.0.19.Final'
dependency 'org.hibernate:hibernate-validator:6.0.21.Final'
dependency 'org.hsqldb:hsqldb:2.4.1'
dependency 'org.jasig.cas.client:cas-client-core:3.5.1'
dependency 'org.javassist:javassist:3.22.0-CR2'
@@ -183,7 +183,7 @@ dependencyManagement {
dependency 'org.slf4j:slf4j-api:1.7.30'
dependency 'org.slf4j:slf4j-nop:1.7.30'
dependency 'org.sonatype.sisu.inject:cglib:2.2.1-v20090111'
dependency 'org.springframework.ldap:spring-ldap-core:2.3.2.RELEASE'
dependency 'org.springframework.ldap:spring-ldap-core:2.3.3.RELEASE'
dependency 'org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE'
dependency 'org.unbescape:unbescape:1.1.5.RELEASE'
dependency 'org.w3c.css:sac:1.3'
@@ -16,6 +16,7 @@
package org.springframework.security.ldap.authentication.ad;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.ldap.CommunicationException;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
@@ -24,6 +25,7 @@ import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
@@ -141,12 +143,15 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
UsernamePasswordAuthenticationToken auth) {
String username = auth.getName();
String password = (String) auth.getCredentials();
DirContext ctx = bindAsUser(username, password);
DirContext ctx = null;
try {
ctx = bindAsUser(username, password);
return searchForUser(ctx, username);
}
catch (CommunicationException e) {
throw badLdapConnection(e);
}
catch (NamingException e) {
logger.error("Failed to locate directory entry for authenticated user: "
+ username, e);
@@ -208,8 +213,7 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
|| (e instanceof OperationNotSupportedException)) {
handleBindException(bindPrincipal, e);
throw badCredentials(e);
}
else {
} else {
throw LdapUtils.convertLdapException(e);
}
}
@@ -311,6 +315,12 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
return (BadCredentialsException) badCredentials().initCause(cause);
}
private InternalAuthenticationServiceException badLdapConnection(Throwable cause) {
return new InternalAuthenticationServiceException(messages.getMessage(
"LdapAuthenticationProvider.badLdapConnection",
"Connection to LDAP server failed."), cause);
}
private DirContextOperations searchForUser(DirContext context, String username)
throws NamingException {
SearchControls searchControls = new SearchControls();
@@ -325,6 +335,9 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
searchControls, searchRoot, searchFilter,
new Object[] { bindPrincipal, username });
}
catch (CommunicationException ldapCommunicationException) {
throw badLdapConnection(ldapCommunicationException);
}
catch (IncorrectResultSizeDataAccessException incorrectResults) {
// Search should never return multiple results if properly configured - just
// rethrow
@@ -32,6 +32,7 @@ import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@@ -58,6 +59,9 @@ import static org.springframework.security.ldap.authentication.ad.ActiveDirector
* @author Rob Winch
*/
public class ActiveDirectoryLdapAuthenticationProviderTests {
public static final String EXISTING_LDAP_PROVIDER = "ldap://192.168.1.200/";
public static final String NON_EXISTING_LDAP_PROVIDER = "ldap://192.168.1.201/";
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -378,17 +382,29 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
}
@Test(expected = org.springframework.ldap.CommunicationException.class)
public void nonAuthenticationExceptionIsConvertedToSpringLdapException()
throws Exception {
provider.contextFactory = createContextFactoryThrowing(new CommunicationException(
msg));
provider.authenticate(joe);
public void nonAuthenticationExceptionIsConvertedToSpringLdapException() throws Throwable {
try {
provider.contextFactory = createContextFactoryThrowing(new CommunicationException(
msg));
provider.authenticate(joe);
} catch (InternalAuthenticationServiceException e) {
// Since GH-8418 ldap communication exception is wrapped into InternalAuthenticationServiceException.
// This test is about the wrapped exception, so we throw it.
throw e.getCause();
}
}
@Test(expected = org.springframework.security.authentication.InternalAuthenticationServiceException.class )
public void connectionExceptionIsWrappedInInternalException() throws Exception {
ActiveDirectoryLdapAuthenticationProvider noneReachableProvider = new ActiveDirectoryLdapAuthenticationProvider(
"mydomain.eu", NON_EXISTING_LDAP_PROVIDER, "dc=ad,dc=eu,dc=mydomain");
noneReachableProvider.doAuthentication(joe);
}
@Test
public void rootDnProvidedSeparatelyFromDomainAlsoWorks() throws Exception {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
"mydomain.eu", "ldap://192.168.1.200/", "dc=ad,dc=eu,dc=mydomain");
"mydomain.eu", EXISTING_LDAP_PROVIDER, "dc=ad,dc=eu,dc=mydomain");
checkAuthentication("dc=ad,dc=eu,dc=mydomain", provider);
}
@@ -60,7 +60,7 @@ import java.util.*;
* requests which match the pattern. An example configuration might look like this:
*
* <pre>
* &lt;bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy"&gt;
* &lt;bean id="myfilterChainProxy" class="org.springframework.security.web.FilterChainProxy"&gt;
* &lt;constructor-arg&gt;
* &lt;util:list&gt;
* &lt;security:filter-chain pattern="/do/not/filter*" filters="none"/&gt;
@@ -228,10 +228,15 @@ class DummyRequest extends HttpServletRequestWrapper {
public void setQueryString(String queryString) {
this.queryString = queryString;
}
@Override
public String getServerName() {
return null;
}
}
final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw new UnsupportedOperationException(method + " is not supported");
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2020 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.
@@ -16,14 +16,15 @@
package org.springframework.security.web.firewall;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* <p>
@@ -59,10 +60,15 @@ import java.util.Set;
* Rejects URLs that contain a URL encoded percent. See
* {@link #setAllowUrlEncodedPercent(boolean)}
* </li>
* <li>
* Rejects hosts that are not allowed. See
* {@link #setAllowedHostnames(Predicate)}
* </li>
* </ul>
*
* @see DefaultHttpFirewall
* @author Rob Winch
* @author Eddú Meléndez
* @since 5.0.1
*/
public class StrictHttpFirewall implements HttpFirewall {
@@ -82,6 +88,8 @@ public class StrictHttpFirewall implements HttpFirewall {
private Set<String> decodedUrlBlacklist = new HashSet<String>();
private Predicate<String> allowedHostnames = hostname -> true;
public StrictHttpFirewall() {
urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
@@ -230,6 +238,21 @@ public class StrictHttpFirewall implements HttpFirewall {
}
}
/**
* <p>
* Determines which hostnames should be allowed. The default is to allow any hostname.
* </p>
*
* @param allowedHostnames the predicate for testing hostnames
* @since 5.0.17
*/
public void setAllowedHostnames(Predicate<String> allowedHostnames) {
if (allowedHostnames == null) {
throw new IllegalArgumentException("allowedHostnames cannot be null");
}
this.allowedHostnames = allowedHostnames;
}
private void urlBlacklistsAddAll(Collection<String> values) {
this.encodedUrlBlacklist.addAll(values);
this.decodedUrlBlacklist.addAll(values);
@@ -243,6 +266,7 @@ public class StrictHttpFirewall implements HttpFirewall {
@Override
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
rejectedBlacklistedUrls(request);
rejectedUntrustedHosts(request);
if (!isNormalized(request)) {
throw new RequestRejectedException("The request was rejected because the URL was not normalized.");
@@ -272,6 +296,13 @@ public class StrictHttpFirewall implements HttpFirewall {
}
}
private void rejectedUntrustedHosts(HttpServletRequest request) {
String serverName = request.getServerName();
if (serverName != null && !this.allowedHostnames.test(serverName)) {
throw new RequestRejectedException("The request was rejected because the domain " + serverName + " is untrusted.");
}
}
@Override
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
return new FirewalledResponse(response);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 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.
@@ -54,6 +54,7 @@ import java.util.Set;
* </p>
*
* @author Rob Winch
* @author Parikshit Dutta
* @since 5.0
*/
public class CsrfWebFilter implements WebFilter {
@@ -133,7 +134,7 @@ public class CsrfWebFilter implements WebFilter {
@Override
public Mono<MatchResult> matches(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest())
.map(r -> r.getMethod())
.flatMap(r -> Mono.justOrEmpty(r.getMethod()))
.filter(m -> ALLOWED_METHODS.contains(m))
.flatMap(m -> MatchResult.notMatch())
.switchIfEmpty(MatchResult.match());
@@ -67,7 +67,7 @@ public final class AntPathRequestMatcher
/**
* Creates a matcher with the specific pattern which will match all HTTP methods in a
* case insensitive manner.
* case sensitive manner.
*
* @param pattern the ant pattern to use for matching
*/
@@ -76,7 +76,7 @@ public final class AntPathRequestMatcher
}
/**
* Creates a matcher with the supplied pattern and HTTP method in a case insensitive
* Creates a matcher with the supplied pattern and HTTP method in a case sensitive
* manner.
*
* @param pattern the ant pattern to use for matching
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2020 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.
@@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.fail;
/**
* @author Rob Winch
* @author Eddú Meléndez
*/
public class StrictHttpFirewallTests {
public String[] unnormalizedPaths = { "/..", "/./path/", "/path/path/.", "/path/path//.", "./path/../path//.",
@@ -373,4 +374,30 @@ public class StrictHttpFirewallTests {
this.firewall.getFirewalledRequest(request);
}
@Test
public void getFirewalledRequestWhenTrustedDomainThenNoException() {
String host = "example.org";
this.request.addHeader("Host", host);
this.firewall.setAllowedHostnames(hostname -> hostname.equals("example.org"));
try {
this.firewall.getFirewalledRequest(this.request);
} catch (RequestRejectedException fail) {
fail("Host " + host + " was rejected");
}
}
@Test
public void getFirewalledRequestWhenUntrustedDomainThenException() {
String host = "example.org";
this.request.addHeader("Host", host);
this.firewall.setAllowedHostnames(hostname -> hostname.equals("myexample.org"));
try {
this.firewall.getFirewalledRequest(this.request);
fail("Host " + host + " was accepted");
} catch (RequestRejectedException expected) {
}
}
}