Skip to content
Snippets Groups Projects
Commit 79e53b68 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

integration tests of ldap

parent f4ad25ea
No related branches found
No related tags found
1 merge request!836Resolve "Implement Spring Security"
package lcsb.mapviewer.web.config;
import com.unboundid.ldap.sdk.LDAPException;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.services.UserDTO;
import lcsb.mapviewer.services.interfaces.ILdapService;
import lcsb.mapviewer.services.interfaces.IUserService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.unboundid.ldap.sdk.LDAPException;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.services.UserDTO;
import lcsb.mapviewer.services.interfaces.ILdapService;
import lcsb.mapviewer.services.interfaces.IUserService;
@Order(2)
@Service
public class LdapAuthenticationProvider implements AuthenticationProvider {
Logger logger = LogManager.getLogger();
private IUserService userService;
private ILdapService ldapService;
private UserDetailsService userDetailsService;
@Autowired
public LdapAuthenticationProvider(IUserService userService,
ILdapService ldapService,
UserDetailsService userDetailsService) {
ILdapService ldapService,
UserDetailsService userDetailsService) {
this.userService = userService;
this.ldapService = ldapService;
this.userDetailsService = userDetailsService;
......@@ -40,6 +42,13 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
if (username.isEmpty()) {
throw new BadCredentialsException("Invalid username.");
}
User existingUser = userService.getUserByLogin(username);
if (existingUser!=null) {
if (!existingUser.isConnectedToLdap()) {
throw new BadCredentialsException("User cannot authenticate over LDAP");
}
}
boolean ldapLoginSuccess;
try {
......@@ -52,16 +61,15 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
throw new BadCredentialsException("Invalid credentials or username.");
}
boolean userExistsLocally = userService.getUserByLogin(username) != null;
boolean userExistsLocally = existingUser != null;
if (!userExistsLocally) {
createLocalUser(authentication);
}
return new UsernamePasswordAuthenticationToken(
username,
authentication.getCredentials(),
userDetailsService.loadUserByUsername(username).getAuthorities()
);
username,
authentication.getCredentials(),
userDetailsService.loadUserByUsername(username).getAuthorities());
}
@Override
......@@ -82,6 +90,9 @@ public class LdapAuthenticationProvider implements AuthenticationProvider {
newUser.setName(userDTO.getFirstName());
newUser.setSurname(userDTO.getLastName());
newUser.setEmail(userDTO.getEmail());
// spring requires not null password - the password is hashed and the hash would
// never be equal to empty string
newUser.setCryptedPassword("");
userService.addUser(newUser);
userService.grantDefaultPrivileges(newUser);
}
......
......@@ -50,7 +50,7 @@ public class LocalAuthenticationProvider implements AuthenticationProvider {
}
User user = userService.getUserByLogin(username);
if (user == null || user.isConnectedToLdap()) {
throw new InternalAuthenticationServiceException("Provider cannot authenticate user.");
throw new UsernameNotFoundException("Provider cannot authenticate user.");
}
return daoAuthenticationProvider.authenticate(authentication);
}
......
package lcsb.mapviewer.web;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import lcsb.mapviewer.model.user.ConfigurationElementType;
import lcsb.mapviewer.services.impl.LdapService;
import lcsb.mapviewer.services.interfaces.IConfigurationService;
import lcsb.mapviewer.services.interfaces.ILdapService;
@Profile("ldapTest")
@Configuration
public class LdapServiceTestConfiguration {
@Autowired
IConfigurationService configurationService;
Logger logger = LogManager.getLogger();
static String TEST_LOGIN = "john.doe.test";
static String TEST_PASSWD = "test_passwd";
static String LDAP_FILE_CONTENT = "./src/test/resources/ldap/john-doe-test-example.ldif";
static String TEST_INVALID_PASSWD = "incorrect password";
@Bean
@Primary
public ILdapService createMockLdapService() throws LDAPException {
configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "dc=uni,dc=lu");
configurationService.setConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS, "person");
configurationService.setConfigurationValue(ConfigurationElementType.LDAP_FILTER,
"memberof=cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu");
LdapService ldapService = Mockito.spy(new LdapService(null));
ldapService.setConfigurationService(configurationService);
Mockito.doAnswer(new Answer<LDAPConnection>() {
@Override
public LDAPConnection answer(InvocationOnMock invocation) throws Throwable {
// Create the configuration to use for the server.
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=uni,dc=lu");
config.addAdditionalBindCredentials("uid=" + TEST_LOGIN + ",cn=users,cn=accounts,dc=uni,dc=lu", TEST_PASSWD);
config.setSchema(null);
// Create the directory server instance, populate it with data from the
// "test-data.ldif" file, and start listening for client connections.
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
ds.importFromLDIF(true, LDAP_FILE_CONTENT);
ds.startListening();
return ds.getConnection();
}
}).when(ldapService).getConnection();
return ldapService;
}
}
......@@ -8,29 +8,22 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.*;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.transaction.annotation.Transactional;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import lcsb.mapviewer.model.user.ConfigurationElementType;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.services.impl.LdapService;
import lcsb.mapviewer.services.interfaces.*;
import lcsb.mapviewer.services.interfaces.IUserService;
import lcsb.mapviewer.web.config.SpringWebConfig;
@ActiveProfiles("ldapTest")
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@Rollback
......@@ -38,70 +31,31 @@ import lcsb.mapviewer.web.config.SpringWebConfig;
@ContextConfiguration(classes = SpringWebConfig.class)
public class SpringSecurityLdapIntegrationTest extends ControllerIntegrationTest {
private static final String LOCAL_PASSWORD = "xxx";
static Logger logger = LogManager.getLogger(SpringSecurityLdapIntegrationTest.class);
@Autowired
private IUserService userService;
@Autowired
private UserDetailsService customUserDetailsService;
private static String TEST_LOGIN = "john.doe.test";
private static String TEST_PASSWD = "test_passwd";
private static String TEST_INVALID_PASSWD = "incorrect password";
@Autowired
ILdapService originalLdapService;
@Autowired
IConfigurationService configurationService;
@Before
public void setUp() throws LDAPException {
LdapService mockLdapService = createMockLdapService("./src/test/resources/ldap/john-doe-test-example.ldif", TEST_LOGIN,
TEST_PASSWD);
// TODO use this mock for the LDAP connection
}
@After
public void tearDown() {
}
private LdapService createMockLdapService(String filename, String login, String passwd) throws LDAPException {
configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "dc=uni,dc=lu");
configurationService.setConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS, "person");
configurationService.setConfigurationValue(ConfigurationElementType.LDAP_FILTER,
"memberof=cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu");
LdapService ldapService = Mockito.spy(new LdapService(null));
ldapService.setConfigurationService(configurationService);
Mockito.when(ldapService.getConnection()).thenAnswer(new Answer<LDAPConnection>() {
@Override
public LDAPConnection answer(InvocationOnMock invocation) throws Throwable {
// Create the configuration to use for the server.
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=uni,dc=lu");
config.addAdditionalBindCredentials("uid=" + login + ",cn=users,cn=accounts,dc=uni,dc=lu", passwd);
config.setSchema(null);
// Create the directory server instance, populate it with data from the
// "test-data.ldif" file, and start listening for client connections.
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
ds.importFromLDIF(true, filename);
ds.startListening();
return ds.getConnection();
}
});
return ldapService;
}
@Test
public void testInvalidLoginFromLdap() throws Exception {
int count = userService.getUsers().size();
RequestBuilder request = post("/api/doLogin")
.param("login", TEST_LOGIN)
.param("password", TEST_INVALID_PASSWD);
.param("login", LdapServiceTestConfiguration.TEST_LOGIN)
.param("password", LdapServiceTestConfiguration.TEST_INVALID_PASSWD);
mockMvc.perform(request)
.andExpect(status().is4xxClientError());
......@@ -112,12 +66,12 @@ public class SpringSecurityLdapIntegrationTest extends ControllerIntegrationTest
@Test
public void testLoginFromLdap() throws Exception {
RequestBuilder request = post("/api/doLogin")
.param("login", TEST_LOGIN)
.param("password", TEST_PASSWD);
.param("login", LdapServiceTestConfiguration.TEST_LOGIN)
.param("password", LdapServiceTestConfiguration.TEST_PASSWD);
mockMvc.perform(request)
.andExpect(status().is2xxSuccessful());
User user = userService.getUserByLogin(TEST_LOGIN);
User user = userService.getUserByLogin(LdapServiceTestConfiguration.TEST_LOGIN);
assertNotNull("After authentication from LDAP user is not present in the system", user);
assertTrue("LDAP user password should be empty",
user.getCryptedPassword() == null || user.getCryptedPassword().isEmpty());
......@@ -129,25 +83,56 @@ public class SpringSecurityLdapIntegrationTest extends ControllerIntegrationTest
int count = userService.getUsers().size();
RequestBuilder request = post("/api/doLogin")
.param("login", TEST_LOGIN)
.param("password", TEST_PASSWD);
.param("login", LdapServiceTestConfiguration.TEST_LOGIN)
.param("password", LdapServiceTestConfiguration.TEST_PASSWD);
mockMvc.perform(request)
.andExpect(status().is2xxSuccessful());
request = post("/api/doLogin")
.param("login", TEST_LOGIN.toLowerCase())
.param("password", TEST_PASSWD);
.param("login", LdapServiceTestConfiguration.TEST_LOGIN.toLowerCase())
.param("password", LdapServiceTestConfiguration.TEST_PASSWD);
mockMvc.perform(request)
.andExpect(status().is2xxSuccessful());
request = post("/api/doLogin")
.param("login", TEST_LOGIN.toUpperCase())
.param("password", TEST_PASSWD);
.param("login", LdapServiceTestConfiguration.TEST_LOGIN.toUpperCase())
.param("password", LdapServiceTestConfiguration.TEST_PASSWD);
mockMvc.perform(request)
.andExpect(status().is2xxSuccessful());
assertEquals("LDAP login is case insensitive and no new user should be added for different cases",
count + 1, userService.getUsers().size());
}
@Test
public void testLocalAccountShouldntAuthenticateFromLdap() throws Exception {
createUser(LdapServiceTestConfiguration.TEST_LOGIN, LOCAL_PASSWORD);
RequestBuilder request = post("/api/doLogin")
.param("login", LdapServiceTestConfiguration.TEST_LOGIN)
.param("password", LdapServiceTestConfiguration.TEST_PASSWD);
mockMvc.perform(request)
.andExpect(status().is4xxClientError());
}
@Test
public void testLdapAccountShouldntAuthenticateFromLocal() throws Exception {
User user = createUser(LdapServiceTestConfiguration.TEST_LOGIN, LOCAL_PASSWORD);
user.setConnectedToLdap(true);
userService.updateUser(user);
RequestBuilder request = post("/api/doLogin")
.param("login", LdapServiceTestConfiguration.TEST_LOGIN)
.param("password", LdapServiceTestConfiguration.TEST_PASSWD);
mockMvc.perform(request)
.andExpect(status().is2xxSuccessful());
request = post("/api/doLogin")
.param("login", LdapServiceTestConfiguration.TEST_LOGIN)
.param("password", LOCAL_PASSWORD);
mockMvc.perform(request)
.andExpect(status().is4xxClientError());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment