Merge Formatting Changes

Issue gh-8945
This commit is contained in:
Rob Winch
2020-08-24 16:38:12 -05:00
2779 changed files with 82438 additions and 91751 deletions

View File

@@ -16,8 +16,16 @@
package org.springframework.security.config.annotation.authentication.ldap;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Collections;
import java.util.List;
import javax.naming.directory.SearchControls;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -39,16 +47,14 @@ import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.List;
import javax.naming.directory.SearchControls;
import static java.util.Collections.singleton;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
static Integer port;
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -72,37 +78,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("ROLE_");
}
@EnableWebSecurity
static class DefaultLdapConfig extends BaseLdapProviderConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people");
}
// @formatter:on
}
@Test
public void groupRolesCustom() {
this.spring.register(GroupRolesConfig.class).autowire();
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute")).isEqualTo("group");
}
@EnableWebSecurity
static class GroupRolesConfig extends BaseLdapProviderConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupRoleAttribute("group");
}
// @formatter:on
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute"))
.isEqualTo("group");
}
@Test
@@ -110,20 +92,8 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
this.spring.register(GroupSearchConfig.class).autowire();
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter")).isEqualTo("ou=groupName");
}
@EnableWebSecurity
static class GroupSearchConfig extends BaseLdapProviderConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName");
}
// @formatter:on
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter"))
.isEqualTo("ou=groupName");
}
@Test
@@ -135,20 +105,6 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.extracting("searchScope").isEqualTo(SearchControls.SUBTREE_SCOPE);
}
@EnableWebSecurity
static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName")
.groupSearchSubtree(true);
}
// @formatter:on
}
@Test
public void rolePrefixCustom() {
this.spring.register(RolePrefixConfig.class).autowire();
@@ -157,39 +113,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("role_");
}
@EnableWebSecurity
static class RolePrefixConfig extends BaseLdapProviderConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.rolePrefix("role_");
}
// @formatter:on
}
@Test
public void bindAuthentication() throws Exception {
this.spring.register(BindAuthenticationConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
@EnableWebSecurity
static class BindAuthenticationConfig extends BaseLdapServerConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
// @formatter:on
.andExpect(authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
// SEC-2472
@@ -198,26 +128,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
this.spring.register(PasswordEncoderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
@EnableWebSecurity
static class PasswordEncoderConfig extends BaseLdapServerConfig {
// @formatter:off
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.passwordEncoder(new BCryptPasswordEncoder())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
// @formatter:on
.andExpect(authenticated().withUsername("bcrypt")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
private LdapAuthenticationProvider ldapProvider() {
return ((List<LdapAuthenticationProvider>) ReflectionTestUtils.getField(authenticationManager, "providers")).get(0);
return ((List<LdapAuthenticationProvider>) ReflectionTestUtils.getField(this.authenticationManager,
"providers")).get(0);
}
private LdapAuthoritiesPopulator getAuthoritiesPopulator(LdapAuthenticationProvider provider) {
@@ -228,23 +145,150 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
return (GrantedAuthoritiesMapper) ReflectionTestUtils.getField(provider, "authoritiesMapper");
}
static int getPort() throws IOException {
if (port == null) {
ServerSocket socket = new ServerSocket(0);
port = socket.getLocalPort();
socket.close();
}
return port;
}
@EnableWebSecurity
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
static class DefaultLdapConfig extends BaseLdapProviderConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
@EnableWebSecurity
static class GroupRolesConfig extends BaseLdapProviderConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupRoleAttribute("group");
// @formatter:on
}
}
@EnableWebSecurity
static class GroupSearchConfig extends BaseLdapProviderConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName");
// @formatter:on
}
}
@EnableWebSecurity
static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName")
.groupSearchSubtree(true);
// @formatter:on
}
}
@EnableWebSecurity
static class RolePrefixConfig extends BaseLdapProviderConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.rolePrefix("role_");
// @formatter:on
}
}
@EnableWebSecurity
static class BindAuthenticationConfig extends BaseLdapServerConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
@EnableWebSecurity
static class PasswordEncoderConfig extends BaseLdapServerConfig {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.contextSource(contextSource())
.passwordEncoder(new BCryptPasswordEncoder())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
@EnableWebSecurity
abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig {
@Bean
public ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org",
"classpath:/test-server.ldif");
apacheDSContainer.setPort(getPort());
return apacheDSContainer;
}
}
@EnableWebSecurity
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration.class)
static abstract class BaseLdapProviderConfig extends WebSecurityConfigurerAdapter {
abstract static class BaseLdapProviderConfig extends WebSecurityConfigurerAdapter {
@Bean
public BaseLdapPathContextSource contextSource() throws Exception {
BaseLdapPathContextSource contextSource() throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://127.0.0.1:" + getPort() + "/dc=springframework,dc=org");
contextSource.setUserDn("uid=admin,ou=system");
@@ -254,22 +298,14 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception {
AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception {
configure(auth);
return auth.build();
}
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception;
@Override
protected abstract void configure(AuthenticationManagerBuilder auth) throws Exception;
}
static Integer port;
static int getPort() throws IOException {
if (port == null) {
ServerSocket socket = new ServerSocket(0);
port = socket.getLocalPort();
socket.close();
}
return port;
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.security.config.annotation.authentication.ldap;
import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
@@ -27,13 +29,15 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import static java.util.Collections.singleton;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
public class LdapAuthenticationProviderConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -41,7 +45,8 @@ public class LdapAuthenticationProviderConfigurerTests {
private MockMvc mockMvc;
@Test
public void authenticationManagerSupportMultipleDefaultLdapContextsWithPortsDynamicallyAllocated() throws Exception {
public void authenticationManagerSupportMultipleDefaultLdapContextsWithPortsDynamicallyAllocated()
throws Exception {
this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
@@ -52,39 +57,68 @@ public class LdapAuthenticationProviderConfigurerTests {
public void authenticationManagerSupportMultipleLdapContextWithDefaultRolePrefix() throws Exception {
this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bob")
.password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated()
.withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")));
// @formatter:on
this.mockMvc.perform(request).andExpect(expectedUser);
}
@Test
public void authenticationManagerSupportMultipleLdapContextWithCustomRolePrefix() throws Exception {
this.spring.register(MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS"))));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bob")
.password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated()
.withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS")));
// @formatter:on
this.mockMvc.perform(request).andExpect(expectedUser);
}
@Test
public void authenticationManagerWhenPortZeroThenAuthenticates() throws Exception {
this.spring.register(LdapWithRandomPortConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bob")
.password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated()
.withUsername("bob");
// @formatter:on
this.mockMvc.perform(request).andExpect(expectedUser);
}
@Test
public void authenticationManagerWhenSearchSubtreeThenNestedGroupFound() throws Exception {
this.spring.register(GroupSubtreeSearchConfig.class).autowire();
this.mockMvc.perform(formLogin().user("ben").password("benspassword"))
.andExpect(authenticated().withUsername("ben").withAuthorities(
AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS")));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("ben")
.password("benspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated()
.withUsername("ben")
.withAuthorities(
AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS"));
// @formatter:on
this.mockMvc.perform(request).andExpect(expectedUser);
}
@EnableWebSecurity
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
@@ -95,14 +129,17 @@ public class LdapAuthenticationProviderConfigurerTests {
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
// @formatter:on
}
@EnableWebSecurity
static class MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
@@ -115,14 +152,17 @@ public class LdapAuthenticationProviderConfigurerTests {
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people")
.rolePrefix("RUOLO_");
// @formatter:on
}
// @formatter:on
}
@EnableWebSecurity
static class LdapWithRandomPortConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
@@ -130,20 +170,26 @@ public class LdapAuthenticationProviderConfigurerTests {
.userDnPatterns("uid={0},ou=people")
.contextSource()
.port(0);
// @formatter:on
}
}
@EnableWebSecurity
static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.groupSearchSubtree(true)
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
// @formatter:on
}
}

View File

@@ -16,8 +16,13 @@
package org.springframework.security.config.annotation.authentication.ldap;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.support.LdapContextSource;
@@ -31,13 +36,11 @@ import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -56,22 +59,35 @@ public class NamespaceLdapAuthenticationProviderTests {
public void ldapAuthenticationProvider() throws Exception {
this.spring.register(LdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bob")
.password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated()
.withUsername("bob");
// @formatter:on
this.mockMvc.perform(request).andExpect(user);
}
@Test
public void ldapAuthenticationProviderCustom() throws Exception {
this.spring.register(CustomLdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS"))));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bob")
.password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated()
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS")));
// @formatter:on
this.mockMvc.perform(request).andExpect(user);
}
// SEC-2490
@Test
public void ldapAuthenticationProviderCustomLdapAuthoritiesPopulator() throws Exception {
LdapContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://blah.example.com:789/dc=springframework,dc=org");
LdapContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://blah.example.com:789/dc=springframework,dc=org");
CustomAuthoritiesPopulatorConfig.LAP = new DefaultLdapAuthoritiesPopulator(contextSource, null) {
@Override
protected Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) {
@@ -81,15 +97,27 @@ public class NamespaceLdapAuthenticationProviderTests {
this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA"))));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bob")
.password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated()
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA")));
// @formatter:on
this.mockMvc.perform(request).andExpect(user);
}
@Test
public void ldapAuthenticationProviderPasswordCompare() throws Exception {
this.spring.register(PasswordCompareLdapConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt"));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin()
.user("bcrypt")
.password("password");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("bcrypt");
// @formatter:on
this.mockMvc.perform(request).andExpect(user);
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.ldap;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -27,23 +28,28 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
*
*/
public class NamespaceLdapAuthenticationProviderTestsConfigs {
@EnableWebSecurity
static class LdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people"); // ldap-server@user-dn-pattern
// @formatter:on
}
// @formatter:on
}
@EnableWebSecurity
static class CustomLdapAuthenticationProviderConfig extends
WebSecurityConfigurerAdapter {
// @formatter:off
static class CustomLdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupRoleAttribute("cn") // ldap-authentication-provider@group-role-attribute
@@ -60,31 +66,36 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.managerDn("uid=admin,ou=system") // ldap-server@manager-dn
.managerPassword("secret") // ldap-server@manager-password
.port(33399) // ldap-server@port
.root("dc=springframework,dc=org") // ldap-server@root
.root("dc=springframework,dc=org"); // ldap-server@root
// .url("ldap://localhost:33389/dc-springframework,dc=org") this overrides root and port and is used for external
;
// @formatter:on
}
// @formatter:on
}
@EnableWebSecurity
static class CustomAuthoritiesPopulatorConfig extends WebSecurityConfigurerAdapter {
static LdapAuthoritiesPopulator LAP;
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.userSearchFilter("(uid={0})")
.ldapAuthoritiesPopulator(LAP);
// @formatter:on
}
// @formatter:on
}
@EnableWebSecurity
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
@@ -92,7 +103,9 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.passwordCompare()
.passwordEncoder(new BCryptPasswordEncoder()) // ldap-authentication-provider/password-compare/password-encoder@ref
.passwordAttribute("userPassword"); // ldap-authentication-provider/password-compare@password-attribute
// @formatter:on
}
// @formatter:on
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.rsocket;
import io.rsocket.ConnectionSetupPayload;
@@ -26,15 +27,15 @@ public class HelloHandler implements SocketAcceptor {
@Override
public Mono<RSocket> accept(ConnectionSetupPayload setup, RSocket sendingSocket) {
return Mono.just(
new RSocket() {
@Override
public Mono<Payload> requestResponse(Payload payload) {
String data = payload.getDataUtf8();
payload.release();
System.out.println("Got " + data);
return Mono.just(ByteBufPayload.create("Hello " + data));
}
});
return Mono.just(new RSocket() {
@Override
public Mono<Payload> requestResponse(Payload payload) {
String data = payload.getDataUtf8();
payload.release();
System.out.println("Got " + data);
return Mono.just(ByteBufPayload.create("Hello " + data));
}
});
}
}

View File

@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List;
import io.rsocket.core.RSocketServer;
import io.rsocket.exceptions.RejectedSetupException;
import io.rsocket.frame.decoder.PayloadDecoder;
import io.rsocket.transport.netty.server.CloseableChannel;
import io.rsocket.transport.netty.server.TcpServerTransport;
@@ -46,7 +47,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Rob Winch
@@ -54,6 +55,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class HelloRSocketITests {
@Autowired
RSocketMessageHandler handler;
@@ -69,14 +71,16 @@ public class HelloRSocketITests {
@Before
public void setup() {
// @formatter:off
this.server = RSocketServer.create()
.payloadDecoder(PayloadDecoder.ZERO_COPY)
.interceptors((registry) -> {
registry.forSocketAcceptor(this.interceptor);
})
.interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
)
.acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0))
.block();
// @formatter:on
}
@After
@@ -88,38 +92,45 @@ public class HelloRSocketITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
// @formatter:off
this.requester = RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.isNotNull();
// @formatter:off
assertThatExceptionOfType(Exception.class).isThrownBy(
() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.matches((ex) -> ex instanceof RejectedSetupException
|| ex.getClass().toString().contains("ReactiveException"));
// @formatter:on
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void retrieveMonoWhenAuthorizedThenGranted() throws Exception {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
// @formatter:off
this.requester = RSocketRequester.builder()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
// @formatter:off
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}
@@ -129,37 +140,39 @@ public class HelloRSocketITests {
static class Config {
@Bean
public ServerController controller() {
ServerController controller() {
return new ServerController();
}
@Bean
public RSocketMessageHandler messageHandler() {
RSocketMessageHandler messageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setRSocketStrategies(rsocketStrategies());
return handler;
}
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BasicAuthenticationEncoder())
.build();
RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder().encoder(new BasicAuthenticationEncoder()).build();
}
@Bean
MapReactiveUserDetailsService uds() {
// @formatter:off
UserDetails rob = User.withDefaultPasswordEncoder()
.username("rob")
.password("password")
.roles("USER", "ADMIN")
.build();
// @formatter:on
return new MapReactiveUserDetailsService(rob);
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
@@ -171,6 +184,7 @@ public class HelloRSocketITests {
private void add(String p) {
this.payloads.add(p);
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.rsocket;
import java.util.ArrayList;
@@ -21,6 +22,7 @@ import java.util.List;
import io.rsocket.core.RSocketServer;
import io.rsocket.frame.decoder.PayloadDecoder;
import io.rsocket.metadata.WellKnownMimeType;
import io.rsocket.transport.netty.server.CloseableChannel;
import io.rsocket.transport.netty.server.TcpServerTransport;
import org.junit.After;
@@ -51,11 +53,10 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import static io.rsocket.metadata.WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Rob Winch
@@ -63,6 +64,7 @@ import static org.mockito.Mockito.when;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class JwtITests {
@Autowired
RSocketMessageHandler handler;
@@ -81,14 +83,16 @@ public class JwtITests {
@Before
public void setup() {
// @formatter:off
this.server = RSocketServer.create()
.payloadDecoder(PayloadDecoder.ZERO_COPY)
.interceptors((registry) -> {
registry.forSocketAcceptor(this.interceptor);
})
.acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0))
.block();
.payloadDecoder(PayloadDecoder.ZERO_COPY)
.interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
)
.acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0))
.block();
// @formatter:on
}
@After
@@ -100,88 +104,72 @@ public class JwtITests {
@Test
public void routeWhenBearerThenAuthorized() {
BearerTokenMetadata credentials =
new BearerTokenMetadata("token");
when(this.decoder.decode(any())).thenReturn(Mono.just(jwt()));
BearerTokenMetadata credentials = new BearerTokenMetadata("token");
given(this.decoder.decode(any())).willReturn(Mono.just(jwt()));
// @formatter:off
this.requester = requester()
.setupMetadata(credentials.getToken(), BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
.setupMetadata(credentials.getToken(), BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void routeWhenAuthenticationBearerThenAuthorized() {
MimeType authenticationMimeType = MimeTypeUtils.parseMimeType(MESSAGE_RSOCKET_AUTHENTICATION.getString());
BearerTokenMetadata credentials =
new BearerTokenMetadata("token");
when(this.decoder.decode(any())).thenReturn(Mono.just(jwt()));
this.requester = requester()
.setupMetadata(credentials, authenticationMimeType)
MimeType authenticationMimeType = MimeTypeUtils
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
BearerTokenMetadata credentials = new BearerTokenMetadata("token");
given(this.decoder.decode(any())).willReturn(Mono.just(jwt()));
// @formatter:off
this.requester = requester().setupMetadata(credentials, authenticationMimeType)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
.retrieveMono(String.class).block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
private Jwt jwt() {
return TestJwts.jwt()
.claim(IdTokenClaimNames.ISS, "https://issuer.example.com")
.claim(IdTokenClaimNames.SUB, "rob")
.claim(IdTokenClaimNames.AUD, Arrays.asList("client-id"))
.build();
return TestJwts.jwt().claim(IdTokenClaimNames.ISS, "https://issuer.example.com")
.claim(IdTokenClaimNames.SUB, "rob").claim(IdTokenClaimNames.AUD, Arrays.asList("client-id")).build();
}
private RSocketRequester.Builder requester() {
return RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies());
return RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies());
}
@Configuration
@EnableRSocketSecurity
static class Config {
@Bean
public ServerController controller() {
ServerController controller() {
return new ServerController();
}
@Bean
public RSocketMessageHandler messageHandler() {
RSocketMessageHandler messageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setRSocketStrategies(rsocketStrategies());
return handler;
}
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BearerTokenAuthenticationEncoder())
.build();
RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder().encoder(new BearerTokenAuthenticationEncoder()).build();
}
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize ->
authorize
.anyRequest().authenticated()
.anyExchange().permitAll()
)
.jwt(Customizer.withDefaults());
rsocket.authorizePayload((authorize) -> authorize.anyRequest().authenticated().anyExchange().permitAll())
.jwt(Customizer.withDefaults());
return rsocket.build();
}
@@ -189,16 +177,19 @@ public class JwtITests {
ReactiveJwtDecoder jwtDecoder() {
return mock(ReactiveJwtDecoder.class);
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
String connect(String payload) {
return "Hi " + payload;
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.rsocket;
import java.util.ArrayList;
@@ -20,6 +21,7 @@ import java.util.List;
import io.rsocket.core.RSocketServer;
import io.rsocket.exceptions.ApplicationErrorException;
import io.rsocket.exceptions.RejectedSetupException;
import io.rsocket.frame.decoder.PayloadDecoder;
import io.rsocket.transport.netty.server.CloseableChannel;
import io.rsocket.transport.netty.server.TcpServerTransport;
@@ -48,7 +50,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Rob Winch
@@ -60,6 +62,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class RSocketMessageHandlerConnectionITests {
@Autowired
RSocketMessageHandler handler;
@@ -75,14 +78,16 @@ public class RSocketMessageHandlerConnectionITests {
@Before
public void setup() {
// @formatter:off
this.server = RSocketServer.create()
.payloadDecoder(PayloadDecoder.ZERO_COPY)
.interceptors((registry) -> {
registry.forSocketAcceptor(this.interceptor);
})
.interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
)
.acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0))
.block();
// @formatter:on
}
@After
@@ -94,182 +99,179 @@ public class RSocketMessageHandlerConnectionITests {
@Test
public void routeWhenAuthorized() {
UsernamePasswordMetadata credentials =
new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void routeWhenNotAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatCode(() -> this.requester.route("secure.admin.retrieve-mono")
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatExceptionOfType(ApplicationErrorException.class).isThrownBy(() -> this.requester
.route("secure.admin.retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block())
.isInstanceOf(ApplicationErrorException.class);
.block()
);
// @formatter:on
}
@Test
public void routeWhenStreamCredentialsAuthorized() {
UsernamePasswordMetadata connectCredentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
// @formatter:off
this.requester = requester().setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.admin.retrieve-mono")
.metadata(new UsernamePasswordMetadata("admin", "password"), UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("rob")
.retrieveMono(String.class)
.block();
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void routeWhenStreamCredentialsHaveAuthority() {
UsernamePasswordMetadata connectCredentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
// @formatter:off
this.requester = requester().setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiUser = this.requester.route("secure.authority.retrieve-mono")
.metadata(new UsernamePasswordMetadata("admin", "password"), UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("Felipe")
.retrieveMono(String.class)
.block();
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("Felipe")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiUser).isEqualTo("Hi Felipe");
}
@Test
public void connectWhenNotAuthenticated() {
this.requester = requester()
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
// @formatter:off
this.requester = requester().connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatCode(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block())
.isNotNull();
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block()
)
.matches((ex) -> ex instanceof RejectedSetupException
|| ex.getClass().toString().contains("ReactiveException"));
// @formatter:on
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
}
@Test
public void connectWhenNotAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("evil", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatCode(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block())
.isNotNull();
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block()
)
.matches((ex) -> ex instanceof RejectedSetupException
|| ex.getClass().toString().contains("ReactiveException"));
// @formatter:on
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
}
@Test
public void connectionDenied() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatCode(() -> this.requester.route("prohibit")
.data("data")
.retrieveMono(String.class)
.block())
.isInstanceOf(ApplicationErrorException.class);
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("prohibit")
.data("data")
.retrieveMono(String.class)
.block()
);
// @formatter:on
}
@Test
public void connectWithAnyRole() {
UsernamePasswordMetadata credentials =
new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("anyroute")
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void connectWithAnyAuthority() {
UsernamePasswordMetadata credentials =
new UsernamePasswordMetadata("admin", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("admin", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiEbert = this.requester.route("management.users")
.data("admin")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiEbert).isEqualTo("Hi admin");
}
private RSocketRequester.Builder requester() {
return RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies());
return RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies());
}
@Configuration
@EnableRSocketSecurity
static class Config {
@Bean
public ServerController controller() {
ServerController controller() {
return new ServerController();
}
@Bean
public RSocketMessageHandler messageHandler() {
RSocketMessageHandler messageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setRSocketStrategies(rsocketStrategies());
return handler;
}
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BasicAuthenticationEncoder())
.build();
RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder().encoder(new BasicAuthenticationEncoder()).build();
}
@Bean
MapReactiveUserDetailsService uds() {
// @formatter:off
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
@@ -280,41 +282,44 @@ public class RSocketMessageHandlerConnectionITests {
.password("password")
.roles("USER", "SETUP")
.build();
UserDetails evil = User.withDefaultPasswordEncoder()
.username("evil")
.password("password")
.roles("EVIL")
.build();
// @formatter:on
return new MapReactiveUserDetailsService(admin, user, evil);
}
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize ->
authorize
.setup().hasRole("SETUP")
.route("secure.admin.*").hasRole("ADMIN")
.route("secure.**").hasRole("USER")
.route("secure.authority.*").hasAuthority("ROLE_USER")
.route("management.*").hasAnyAuthority("ROLE_ADMIN")
.route("prohibit").denyAll()
.anyRequest().permitAll()
)
.basicAuthentication(Customizer.withDefaults());
// @formatter:off
rsocket.authorizePayload((authorize) -> authorize
.setup().hasRole("SETUP")
.route("secure.admin.*").hasRole("ADMIN")
.route("secure.**").hasRole("USER")
.route("secure.authority.*").hasAuthority("ROLE_USER")
.route("management.*").hasAnyAuthority("ROLE_ADMIN")
.route("prohibit").denyAll()
.anyRequest().permitAll()
)
.basicAuthentication(Customizer.withDefaults());
// @formatter:on
return rsocket.build();
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
String connect(String payload) {
return "Hi " + payload;
}
}
}

View File

@@ -52,7 +52,7 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Rob Winch
@@ -60,6 +60,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class RSocketMessageHandlerITests {
@Autowired
RSocketMessageHandler handler;
@@ -75,20 +76,22 @@ public class RSocketMessageHandlerITests {
@Before
public void setup() {
// @formatter:off
this.server = RSocketServer.create()
.payloadDecoder(PayloadDecoder.ZERO_COPY)
.interceptors((registry) -> {
registry.forSocketAcceptor(this.interceptor);
})
.interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
)
.acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0))
.block();
this.requester = RSocketRequester.builder()
// .rsocketFactory(factory -> factory.addRequesterPlugin(payloadInterceptor))
// .rsocketFactory((factory) ->
// factory.addRequesterPlugin(payloadInterceptor))
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
}
@After
@@ -101,13 +104,15 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
String data = "rob";
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class).isThrownBy(
() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.withMessageContaining("Access Denied");
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@@ -115,14 +120,15 @@ public class RSocketMessageHandlerITests {
public void retrieveMonoWhenAuthenticationFailedThenException() throws Exception {
String data = "rob";
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("invalid", "password");
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class)
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Invalid Credentials");
)
.withMessageContaining("Invalid Credentials");
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@@ -130,12 +136,13 @@ public class RSocketMessageHandlerITests {
public void retrieveMonoWhenAuthorizedThenGranted() throws Exception {
String data = "rob";
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
// @formatter:off
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}
@@ -143,11 +150,12 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveMonoWhenPublicThenGranted() throws Exception {
String data = "rob";
// @formatter:off
String hiRob = this.requester.route("retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block();
.data(data)
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}
@@ -155,26 +163,29 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveFluxWhenDataFluxAndSecureThenDenied() throws Exception {
Flux<String> data = Flux.just("a", "b", "c");
assertThatCode(() -> this.requester.route("secure.retrieve-flux")
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("secure.retrieve-flux")
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
)
.withMessageContaining("Access Denied");
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void retrieveFluxWhenDataFluxAndPublicThenGranted() throws Exception {
Flux<String> data = Flux.just("a", "b", "c");
// @formatter:off
List<String> hi = this.requester.route("retrieve-flux")
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block();
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block();
// @formatter:on
assertThat(hi).containsOnly("hello a", "hello b", "hello c");
assertThat(this.controller.payloads).containsOnlyElementsOf(data.collectList().block());
}
@@ -182,35 +193,33 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveFluxWhenDataStringAndSecureThenDenied() throws Exception {
String data = "a";
assertThatCode(() -> this.requester.route("secure.hello")
.data(data)
.retrieveFlux(String.class)
.collectList()
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
assertThatExceptionOfType(ApplicationErrorException.class).isThrownBy(
() -> this.requester.route("secure.hello").data(data).retrieveFlux(String.class).collectList().block())
.withMessageContaining("Access Denied");
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void sendWhenSecureThenDenied() throws Exception {
String data = "hi";
// @formatter:off
this.requester.route("secure.send")
.data(data)
.send()
.block();
.data(data)
.send()
.block();
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void sendWhenPublicThenGranted() throws Exception {
String data = "hi";
// @formatter:off
this.requester.route("send")
.data(data)
.send()
.block();
.data(data)
.send()
.block();
// @formatter:on
assertThat(this.controller.awaitPayloads()).containsOnly("hi");
}
@@ -219,26 +228,25 @@ public class RSocketMessageHandlerITests {
static class Config {
@Bean
public ServerController controller() {
ServerController controller() {
return new ServerController();
}
@Bean
public RSocketMessageHandler messageHandler() {
RSocketMessageHandler messageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setRSocketStrategies(rsocketStrategies());
return handler;
}
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BasicAuthenticationEncoder())
.build();
RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder().encoder(new BasicAuthenticationEncoder()).build();
}
@Bean
MapReactiveUserDetailsService uds() {
// @formatter:off
UserDetails rob = User.withDefaultPasswordEncoder()
.username("rob")
.password("password")
@@ -249,45 +257,44 @@ public class RSocketMessageHandlerITests {
.password("password")
.roles("USER")
.build();
// @formatter:on
return new MapReactiveUserDetailsService(rob, rossen);
}
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize -> {
authorize
.route("secure.*").authenticated()
.anyExchange().permitAll();
})
.basicAuthentication(Customizer.withDefaults());
// @formatter:off
rsocket.authorizePayload(
(authorize) -> authorize
.route("secure.*").authenticated()
.anyExchange().permitAll()
)
.basicAuthentication(Customizer.withDefaults());
// @formatter:on
return rsocket.build();
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping({"secure.retrieve-mono", "retrieve-mono"})
@MessageMapping({ "secure.retrieve-mono", "retrieve-mono" })
String retrieveMono(String payload) {
add(payload);
return "Hi " + payload;
}
@MessageMapping({"secure.retrieve-flux", "retrieve-flux"})
@MessageMapping({ "secure.retrieve-flux", "retrieve-flux" })
Flux<String> retrieveFlux(Flux<String> payload) {
return payload.doOnNext(this::add)
.map(p -> "hello " + p);
return payload.doOnNext(this::add).map((p) -> "hello " + p);
}
@MessageMapping({"secure.send", "send"})
@MessageMapping({ "secure.send", "send" })
Mono<Void> send(Mono<String> payload) {
return payload
.doOnNext(this::add)
.then(Mono.fromRunnable(() -> {
doNotifyAll();
}));
return payload.doOnNext(this::add).then(Mono.fromRunnable(() -> doNotifyAll()));
}
private synchronized void doNotifyAll() {
@@ -302,6 +309,7 @@ public class RSocketMessageHandlerITests {
private void add(String p) {
this.payloads.add(p);
}
}
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
import io.rsocket.core.RSocketServer;
import io.rsocket.exceptions.ApplicationErrorException;
import io.rsocket.frame.decoder.PayloadDecoder;
import io.rsocket.metadata.WellKnownMimeType;
import io.rsocket.transport.netty.server.CloseableChannel;
import io.rsocket.transport.netty.server.TcpServerTransport;
import org.junit.After;
@@ -50,9 +51,8 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import static io.rsocket.metadata.WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Rob Winch
@@ -60,6 +60,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class SimpleAuthenticationITests {
@Autowired
RSocketMessageHandler handler;
@@ -75,14 +76,16 @@ public class SimpleAuthenticationITests {
@Before
public void setup() {
// @formatter:off
this.server = RSocketServer.create()
.payloadDecoder(PayloadDecoder.ZERO_COPY)
.interceptors((registry) -> {
registry.forSocketAcceptor(this.interceptor);
})
.interceptors((registry) ->
registry.forSocketAcceptor(this.interceptor)
)
.acceptor(this.handler.responder())
.bind(TcpServerTransport.create("localhost", 0))
.block();
// @formatter:on
}
@After
@@ -94,38 +97,42 @@ public class SimpleAuthenticationITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
// @formatter:off
this.requester = RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("secure.retrieve-mono")
.data(data).retrieveMono(String.class)
.block()
)
.isInstanceOf(ApplicationErrorException.class);
);
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void retrieveMonoWhenAuthorizedThenGranted() {
MimeType authenticationMimeType = MimeTypeUtils.parseMimeType(MESSAGE_RSOCKET_AUTHENTICATION.getString());
MimeType authenticationMimeType = MimeTypeUtils
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
// @formatter:off
this.requester = RSocketRequester.builder()
.setupMetadata(credentials, authenticationMimeType)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.setupMetadata(credentials, authenticationMimeType)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
// @formatter:off
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, authenticationMimeType)
.data(data)
.retrieveMono(String.class)
.block();
.metadata(credentials, authenticationMimeType)
.data(data).retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}
@@ -135,49 +142,46 @@ public class SimpleAuthenticationITests {
static class Config {
@Bean
public ServerController controller() {
ServerController controller() {
return new ServerController();
}
@Bean
public RSocketMessageHandler messageHandler() {
RSocketMessageHandler messageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setRSocketStrategies(rsocketStrategies());
return handler;
}
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new SimpleAuthenticationEncoder())
.build();
RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder().encoder(new SimpleAuthenticationEncoder()).build();
}
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize ->
authorize
.anyRequest().authenticated()
.anyExchange().permitAll()
)
rsocket.authorizePayload((authorize) -> authorize.anyRequest().authenticated().anyExchange().permitAll())
.simpleAuthentication(Customizer.withDefaults());
return rsocket.build();
}
@Bean
MapReactiveUserDetailsService uds() {
// @formatter:off
UserDetails rob = User.withDefaultPasswordEncoder()
.username("rob")
.password("password")
.roles("USER", "ADMIN")
.build();
// @formatter:on
return new MapReactiveUserDetailsService(rob);
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
@@ -189,6 +193,7 @@ public class SimpleAuthenticationITests {
private void add(String p) {
this.payloads.add(p);
}
}
}

View File

@@ -35,84 +35,74 @@ import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
import static org.assertj.core.api.Assertions.assertThat;
public class LdapProviderBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
if (this.appCtx != null) {
this.appCtx.close();
this.appCtx = null;
}
}
@Test
public void simpleProviderAuthenticatesCorrectly() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider group-search-filter='member={0}' />"
+ "</authentication-manager>"
);
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>" + " <ldap-authentication-provider group-search-filter='member={0}' />"
+ "</authentication-manager>");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
UserDetails ben = (UserDetails) auth.getPrincipal();
assertThat(ben.getAuthorities()).hasSize(3);
}
@Test
public void multipleProvidersAreSupported() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider group-search-filter='member={0}' />"
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>" + " <ldap-authentication-provider group-search-filter='member={0}' />"
+ " <ldap-authentication-provider group-search-filter='uniqueMember={0}' />"
+ "</authentication-manager>"
);
+ "</authentication-manager>");
ProviderManager providerManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
ProviderManager providerManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
assertThat(providerManager.getProviders()).hasSize(2);
assertThat(providerManager.getProviders())
.extracting("authoritiesPopulator.groupSearchFilter")
assertThat(providerManager.getProviders()).extracting("authoritiesPopulator.groupSearchFilter")
.containsExactly("member={0}", "uniqueMember={0}");
}
@Test(expected = ApplicationContextException.class)
public void missingServerEltCausesConfigException() {
new InMemoryXmlApplicationContext("<authentication-manager>"
+ " <ldap-authentication-provider />"
+ "</authentication-manager>"
);
new InMemoryXmlApplicationContext(
"<authentication-manager>" + " <ldap-authentication-provider />" + "</authentication-manager>");
}
@Test
public void supportsPasswordComparisonAuthentication() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare />"
+ " </ldap-authentication-provider>"
+ "</authentication-manager>"
);
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>" + " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare />" + " </ldap-authentication-provider>" + "</authentication-manager>");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
assertThat(auth).isNotNull();
}
@Test
public void supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare password-attribute='uid'>"
+ " <password-encoder ref='passwordEncoder' />"
+ " </password-compare>"
+ " </ldap-authentication-provider>"
+ "</authentication-manager>"
+ "<b:bean id='passwordEncoder' class='org.springframework.security.crypto.password.NoOpPasswordEncoder' factory-method='getInstance' />"
);
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>" + " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare password-attribute='uid'>" + " <password-encoder ref='passwordEncoder' />"
+ " </password-compare>" + " </ldap-authentication-provider>" + "</authentication-manager>"
+ "<b:bean id='passwordEncoder' class='org.springframework.security.crypto.password.NoOpPasswordEncoder' factory-method='getInstance' />");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
assertThat(auth).isNotNull();
@@ -121,58 +111,52 @@ public class LdapProviderBeanDefinitionParserTests {
// SEC-2472
@Test
public void supportsCryptoPasswordEncoder() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare>"
+ " <password-encoder ref='pe' />"
+ " </password-compare>"
+ " </ldap-authentication-provider>"
+ "</authentication-manager>"
+ "<b:bean id='pe' class='org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder' />"
);
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>" + " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare>" + " <password-encoder ref='pe' />" + " </password-compare>"
+ " </ldap-authentication-provider>" + "</authentication-manager>"
+ "<b:bean id='pe' class='org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder' />");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", "password"));
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", "password"));
assertThat(auth).isNotNull();
}
@Test
public void inetOrgContextMapperIsSupported() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-details-class='inetOrgPerson' />"
+ "</authentication-manager>"
);
this.appCtx = new InMemoryXmlApplicationContext(
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-details-class='inetOrgPerson' />"
+ "</authentication-manager>");
ProviderManager providerManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
ProviderManager providerManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
assertThat(providerManager.getProviders()).hasSize(1);
assertThat(providerManager.getProviders())
.extracting("userDetailsContextMapper")
.allSatisfy(contextMapper -> assertThat(contextMapper).isInstanceOf(InetOrgPersonContextMapper.class));
assertThat(providerManager.getProviders()).extracting("userDetailsContextMapper").allSatisfy(
(contextMapper) -> assertThat(contextMapper).isInstanceOf(InetOrgPersonContextMapper.class));
}
@Test
public void ldapAuthenticationProviderWorksWithPlaceholders() {
System.setProperty("udp", "people");
System.setProperty("gsf", "member");
appCtx = new InMemoryXmlApplicationContext("<ldap-server />"
+ "<authentication-manager>"
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server />" + "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=${udp}' group-search-filter='${gsf}={0}' />"
+ "</authentication-manager>"
+ "<b:bean id='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' />"
);
+ "<b:bean id='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' />");
ProviderManager providerManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
ProviderManager providerManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
assertThat(providerManager.getProviders()).hasSize(1);
AuthenticationProvider authenticationProvider = providerManager.getProviders().get(0);
assertThat(authenticationProvider)
.extracting("authenticator.userDnFormat")
.satisfies(messageFormats -> assertThat(messageFormats).isEqualTo(new MessageFormat[]{new MessageFormat("uid={0},ou=people")}));
assertThat(authenticationProvider)
.extracting("authoritiesPopulator.groupSearchFilter")
.satisfies(searchFilter -> assertThat(searchFilter).isEqualTo("member={0}"));
assertThat(authenticationProvider).extracting("authenticator.userDnFormat")
.satisfies((messageFormats) -> assertThat(messageFormats)
.isEqualTo(new MessageFormat[] { new MessageFormat("uid={0},ou=people") }));
assertThat(authenticationProvider).extracting("authoritiesPopulator.groupSearchFilter")
.satisfies((searchFilter) -> assertThat(searchFilter).isEqualTo("member={0}"));
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.ldap;
import java.io.IOException;
@@ -35,22 +36,22 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Rob Winch
*/
public class LdapServerBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
if (this.appCtx != null) {
this.appCtx.close();
this.appCtx = null;
}
}
@Test
public void embeddedServerCreationContainsExpectedContextSourceAndData() {
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server ldif='classpath:test-server.ldif' port='0'/>");
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) this.appCtx
.getBean(BeanIds.CONTEXT_SOURCE);
// Check data is loaded
@@ -62,17 +63,14 @@ public class LdapServerBeanDefinitionParserTests {
public void useOfUrlAttributeCreatesCorrectContextSource() throws Exception {
int port = getDefaultPort();
// Create second "server" with a url pointing at embedded one
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server ldif='classpath:test-server.ldif' port='"
+ port
+ "'/>"
+ "<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:"
+ port + "/dc=springframework,dc=org' />");
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='" + port
+ "'/>" + "<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:" + port
+ "/dc=springframework,dc=org' />");
// Check the default context source is still there.
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
this.appCtx.getBean(BeanIds.CONTEXT_SOURCE);
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) this.appCtx
.getBean("blah");
// Check data is loaded as before
@@ -82,9 +80,9 @@ public class LdapServerBeanDefinitionParserTests {
@Test
public void loadingSpecificLdifFileIsSuccessful() {
appCtx = new InMemoryXmlApplicationContext(
this.appCtx = new InMemoryXmlApplicationContext(
"<ldap-server ldif='classpath*:test-server2.xldif' root='dc=monkeymachine,dc=co,dc=uk' port='0'/>");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) this.appCtx
.getBean(BeanIds.CONTEXT_SOURCE);
LdapTemplate template = new LdapTemplate(contextSource);
@@ -93,8 +91,8 @@ public class LdapServerBeanDefinitionParserTests {
@Test
public void defaultLdifFileIsSuccessful() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server/>");
ApacheDSContainer dsContainer = appCtx.getBean(ApacheDSContainer.class);
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server/>");
ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class);
assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif");
}
@@ -104,4 +102,5 @@ public class LdapServerBeanDefinitionParserTests {
return server.getLocalPort();
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.ldap;
import java.util.Set;
@@ -36,11 +37,6 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser.INET_ORG_PERSON_MAPPER_CLASS;
import static org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser.LDAP_AUTHORITIES_POPULATOR_CLASS;
import static org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser.LDAP_SEARCH_CLASS;
import static org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser.LDAP_USER_MAPPER_CLASS;
import static org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser.PERSON_MAPPER_CLASS;
/**
* @author Luke Taylor
@@ -48,36 +44,45 @@ import static org.springframework.security.config.ldap.LdapUserServiceBeanDefini
* @author Eddú Meléndez
*/
public class LdapUserServiceBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
if (this.appCtx != null) {
this.appCtx.close();
this.appCtx = null;
}
}
@Test
public void beanClassNamesAreCorrect() {
assertThat(FilterBasedLdapUserSearch.class.getName()).isEqualTo(LDAP_SEARCH_CLASS);
assertThat(PersonContextMapper.class.getName()).isEqualTo(PERSON_MAPPER_CLASS);
assertThat(InetOrgPersonContextMapper.class.getName()).isEqualTo(INET_ORG_PERSON_MAPPER_CLASS);
assertThat(LdapUserDetailsMapper.class.getName()).isEqualTo(LDAP_USER_MAPPER_CLASS);
assertThat(DefaultLdapAuthoritiesPopulator.class.getName()).isEqualTo(LDAP_AUTHORITIES_POPULATOR_CLASS);
assertThat(new LdapUserServiceBeanDefinitionParser().getBeanClassName(mock(Element.class))).isEqualTo(LdapUserDetailsService.class.getName());
assertThat(FilterBasedLdapUserSearch.class.getName())
.isEqualTo(LdapUserServiceBeanDefinitionParser.LDAP_SEARCH_CLASS);
assertThat(PersonContextMapper.class.getName())
.isEqualTo(LdapUserServiceBeanDefinitionParser.PERSON_MAPPER_CLASS);
assertThat(InetOrgPersonContextMapper.class.getName())
.isEqualTo(LdapUserServiceBeanDefinitionParser.INET_ORG_PERSON_MAPPER_CLASS);
assertThat(LdapUserDetailsMapper.class.getName())
.isEqualTo(LdapUserServiceBeanDefinitionParser.LDAP_USER_MAPPER_CLASS);
assertThat(DefaultLdapAuthoritiesPopulator.class.getName())
.isEqualTo(LdapUserServiceBeanDefinitionParser.LDAP_AUTHORITIES_POPULATOR_CLASS);
assertThat(new LdapUserServiceBeanDefinitionParser().getBeanClassName(mock(Element.class)))
.isEqualTo(LdapUserDetailsService.class.getName());
}
@Test
public void minimalConfigurationIsParsedOk() {
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server ldif='classpath:test-server.ldif' url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
setContext(
"<ldap-user-service user-search-filter='(uid={0})' /><ldap-server ldif='classpath:test-server.ldif' url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
}
@Test
public void userServiceReturnsExpectedData() {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
setContext(
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
@@ -87,12 +92,11 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void differentUserSearchBaseWorksAsExpected() {
setContext("<ldap-user-service id='ldapUDS' "
+ " user-search-base='ou=otherpeople' "
setContext("<ldap-user-service id='ldapUDS' " + " user-search-base='ou=otherpeople' "
+ " user-search-filter='(cn={0})' "
+ " group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails joe = uds.loadUserByUsername("Joe Smeth");
assertThat(joe.getUsername()).isEqualTo("Joe Smeth");
@@ -100,27 +104,26 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void rolePrefixIsSupported() {
setContext("<ldap-user-service id='ldapUDS' "
+ " user-search-filter='(uid={0})' "
setContext("<ldap-user-service id='ldapUDS' " + " user-search-filter='(uid={0})' "
+ " group-search-filter='member={0}' role-prefix='PREFIX_'/>"
+ "<ldap-user-service id='ldapUDSNoPrefix' "
+ " user-search-filter='(uid={0})' "
+ "<ldap-user-service id='ldapUDSNoPrefix' " + " user-search-filter='(uid={0})' "
+ " group-search-filter='member={0}' role-prefix='none'/><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertThat(AuthorityUtils.authorityListToSet(ben.getAuthorities())).contains("PREFIX_DEVELOPERS");
uds = (UserDetailsService) appCtx.getBean("ldapUDSNoPrefix");
uds = (UserDetailsService) this.appCtx.getBean("ldapUDSNoPrefix");
ben = uds.loadUserByUsername("ben");
assertThat(AuthorityUtils.authorityListToSet(ben.getAuthorities())).contains("DEVELOPERS");
}
@Test
public void differentGroupRoleAttributeWorksAsExpected() {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
setContext(
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
@@ -131,18 +134,18 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void isSupportedByAuthenticationProviderElement() {
setContext("<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' ldif='classpath:test-server.ldif'/>"
+ "<authentication-manager>"
+ " <authentication-provider>"
+ " <ldap-user-service user-search-filter='(uid={0})' />"
+ " </authentication-provider>" + "</authentication-manager>");
setContext(
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' ldif='classpath:test-server.ldif'/>"
+ "<authentication-manager>" + " <authentication-provider>"
+ " <ldap-user-service user-search-filter='(uid={0})' />" + " </authentication-provider>"
+ "</authentication-manager>");
}
@Test
public void personContextMapperIsSupported() {
setContext("<ldap-server ldif='classpath:test-server.ldif'/>"
+ "<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='person'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertThat(ben instanceof Person).isTrue();
}
@@ -151,7 +154,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
public void inetOrgContextMapperIsSupported() {
setContext("<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>"
+ "<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='inetOrgPerson'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertThat(ben instanceof InetOrgPerson).isTrue();
}
@@ -160,15 +163,15 @@ public class LdapUserServiceBeanDefinitionParserTests {
public void externalContextMapperIsSupported() {
setContext("<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>"
+ "<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-context-mapper-ref='mapper'/>"
+ "<b:bean id='mapper' class='"
+ InetOrgPersonContextMapper.class.getName() + "'/>");
+ "<b:bean id='mapper' class='" + InetOrgPersonContextMapper.class.getName() + "'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetailsService uds = (UserDetailsService) this.appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertThat(ben instanceof InetOrgPerson).isTrue();
}
private void setContext(String context) {
appCtx = new InMemoryXmlApplicationContext(context);
this.appCtx = new InMemoryXmlApplicationContext(context);
}
}