package io.lumify.web.auth;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import io.lumify.core.config.Configuration;
import io.lumify.core.config.HashMapConfigurationLoader;
import io.lumify.core.exception.LumifyException;
import io.lumify.core.model.user.UserRepository;
import io.lumify.core.user.User;
import io.lumify.ldap.LdapSearchConfiguration;
import io.lumify.ldap.LdapSearchService;
import io.lumify.ldap.LdapSearchServiceImpl;
import io.lumify.ldap.LdapSearchServiceTest;
import io.lumify.miniweb.HandlerChain;
import io.lumify.web.AuthenticationHandler;
import io.lumify.web.X509AuthenticationHandler;
import org.apache.commons.lang.StringUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.securegraph.Graph;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.mockito.Matchers.isNull;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class LdapX509AuthenticationHandlerTest {
private static InMemoryDirectoryServer ldapServer;
@Mock
private UserRepository userRepository;
@Mock
private User user;
@Mock
private Graph graph;
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private HttpSession httpSession;
@Mock
private HandlerChain chain;
@BeforeClass
public static void setUp() throws Exception {
ldapServer = LdapSearchServiceTest.configureInMemoryDirectoryServer();
ldapServer.startListening();
}
@AfterClass
public static void tearDown() {
ldapServer.shutDown(true);
}
@Test
public void testUserWithRequiredRole() throws Exception {
LdapSearchService ldapSearchService = new LdapSearchServiceImpl(LdapSearchServiceTest.getServerConfig(ldapServer), getSearchConfigWithExtraUserAttribute("role"));
Configuration configuration = getConfigurationWithRequiredAttribute("role", "lumify_administrator");
AuthenticationHandler authenticationHandler = new LdapX509AuthenticationHandler(userRepository, graph, ldapSearchService, configuration);
X509Certificate cert = LdapSearchServiceTest.getPersonCertificate("alice");
when(request.getAttribute(X509AuthenticationHandler.CERTIFICATE_REQUEST_ATTRIBUTE)).thenReturn(new X509Certificate[]{cert});
when(userRepository.findOrAddUser((String)notNull(), (String)notNull(), (String)isNull(), (String)notNull(), (String[])notNull())).thenReturn(user);
when(user.toString()).thenReturn("alice");
when(user.getUserId()).thenReturn("USER_alice");
when(request.getSession()).thenReturn(httpSession);
authenticationHandler.handle(request, response, chain);
verify(chain).next(request, response);
}
@Test
public void testUserWithoutRequiredRole() throws Exception {
LdapSearchService ldapSearchService = new LdapSearchServiceImpl(LdapSearchServiceTest.getServerConfig(ldapServer), getSearchConfigWithExtraUserAttribute("role"));
Configuration configuration = getConfigurationWithRequiredAttribute("role", "lumify_administrator");
AuthenticationHandler authenticationHandler = new LdapX509AuthenticationHandler(userRepository, graph, ldapSearchService, configuration);
X509Certificate cert = LdapSearchServiceTest.getPersonCertificate("bob");
when(request.getAttribute(X509AuthenticationHandler.CERTIFICATE_REQUEST_ATTRIBUTE)).thenReturn(new X509Certificate[]{cert});
authenticationHandler.handle(request, response, chain);
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
verify(chain, never()).next(request, response);
}
@Test
public void testUserWithoutAnyRoles() throws Exception {
LdapSearchService ldapSearchService = new LdapSearchServiceImpl(LdapSearchServiceTest.getServerConfig(ldapServer), getSearchConfigWithExtraUserAttribute("role"));
Configuration configuration = getConfigurationWithRequiredAttribute("role", "lumify_administrator");
AuthenticationHandler authenticationHandler = new LdapX509AuthenticationHandler(userRepository, graph, ldapSearchService, configuration);
X509Certificate cert = LdapSearchServiceTest.getPersonCertificate("carlos");
when(request.getAttribute(X509AuthenticationHandler.CERTIFICATE_REQUEST_ATTRIBUTE)).thenReturn(new X509Certificate[]{cert});
authenticationHandler.handle(request, response, chain);
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
verify(chain, never()).next(request, response);
}
@Test
public void testUserWithRequiredGroup() throws Exception {
LdapSearchService ldapSearchService = new LdapSearchServiceImpl(LdapSearchServiceTest.getServerConfig(ldapServer), LdapSearchServiceTest.getSearchConfig());
Configuration configuration = getConfigurationWithRequiredGroups("managers");
AuthenticationHandler authenticationHandler = new LdapX509AuthenticationHandler(userRepository, graph, ldapSearchService, configuration);
X509Certificate cert = LdapSearchServiceTest.getPersonCertificate("carlos");
when(request.getAttribute(X509AuthenticationHandler.CERTIFICATE_REQUEST_ATTRIBUTE)).thenReturn(new X509Certificate[]{cert});
when(userRepository.findOrAddUser((String)notNull(), (String)notNull(), (String)isNull(), (String)notNull(), (String[])notNull())).thenReturn(user);
when(user.toString()).thenReturn("carlos");
when(user.getUserId()).thenReturn("USER_carlos");
when(request.getSession()).thenReturn(httpSession);
authenticationHandler.handle(request, response, chain);
verify(chain).next(request, response);
}
@Test
public void testUserWithoutRequiredGroup() throws Exception {
LdapSearchService ldapSearchService = new LdapSearchServiceImpl(LdapSearchServiceTest.getServerConfig(ldapServer), LdapSearchServiceTest.getSearchConfig());
Configuration configuration = getConfigurationWithRequiredGroups("managers");
AuthenticationHandler authenticationHandler = new LdapX509AuthenticationHandler(userRepository, graph, ldapSearchService, configuration);
X509Certificate cert = LdapSearchServiceTest.getPersonCertificate("bob");
when(request.getAttribute(X509AuthenticationHandler.CERTIFICATE_REQUEST_ATTRIBUTE)).thenReturn(new X509Certificate[]{cert});
authenticationHandler.handle(request, response, chain);
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
verify(chain, never()).next(request, response);
}
// TODO: user without any groups?
@Test(expected = LumifyException.class)
public void testUserWithoutLdapEntry() throws Exception {
LdapSearchService ldapSearchService = new LdapSearchServiceImpl(LdapSearchServiceTest.getServerConfig(ldapServer), LdapSearchServiceTest.getSearchConfig());
Map<String,String> map = new HashMap<String, String>();
Configuration configuration = new HashMapConfigurationLoader(map).createConfiguration();
AuthenticationHandler authenticationHandler = new LdapX509AuthenticationHandler(userRepository, graph, ldapSearchService, configuration);
X509Certificate cert = LdapSearchServiceTest.getPersonCertificate("diane");
when(request.getAttribute(X509AuthenticationHandler.CERTIFICATE_REQUEST_ATTRIBUTE)).thenReturn(new X509Certificate[]{cert});
authenticationHandler.handle(request, response, chain);
}
private LdapSearchConfiguration getSearchConfigWithExtraUserAttribute(String extraAttribute) {
LdapSearchConfiguration searchConfiguration = LdapSearchServiceTest.getSearchConfig();
List<String> userAttributes = new ArrayList<String>(searchConfiguration.getUserAttributes());
userAttributes.add(extraAttribute);
searchConfiguration.setUserAttributes(StringUtils.join(userAttributes, ","));
return searchConfiguration;
}
private Configuration getConfigurationWithRequiredAttribute(String attribute, String values) {
Map<String,String> map = new HashMap<String, String>();
map.put("ldap.x509Authentication.requiredAttribute", attribute);
map.put("ldap.x509Authentication.requiredAttributeValues", values);
return new HashMapConfigurationLoader(map).createConfiguration();
}
private Configuration getConfigurationWithRequiredGroups(String groups) {
Map<String,String> map = new HashMap<String, String>();
map.put("ldap.x509Authentication.requiredGroups", groups);
return new HashMapConfigurationLoader(map).createConfiguration();
}
}