package io.lumify.web;
import io.lumify.core.model.user.UserRepository;
import io.lumify.core.user.User;
import io.lumify.miniweb.HandlerChain;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.securegraph.Graph;
import org.securegraph.Vertex;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class X509AuthenticationHandlerTest {
public static final String X509_REQ_ATTR_NAME = "javax.servlet.request.X509Certificate";
public static final String TEST_USERNAME = "testuser";
@Mock
private HttpServletRequest request;
@Mock
private HttpServletResponse response;
@Mock
private HttpSession httpSession;
@Mock
private HandlerChain chain;
@Mock
private WebApp app;
@Mock
private UserRepository userRepository;
@Mock
private Graph graph;
@Mock
private Vertex userVertex;
@Mock
private User user;
@Mock
private Delegate delegate;
private X509AuthenticationHandler instance;
@Before
public void setupTests() {
instance = new TestX509AuthenticationHandler(userRepository, graph);
when(request.getSession()).thenReturn(httpSession);
}
@Test
public void testNoCertificateAvailable() throws Exception {
when(request.getAttribute(X509_REQ_ATTR_NAME)).thenReturn(null);
instance.handle(request, response, chain);
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
}
@Test
public void testEmptyCertificateArrayAvailable() throws Exception {
X509Certificate[] certs = new X509Certificate[0];
when(request.getAttribute(X509_REQ_ATTR_NAME)).thenReturn(certs);
instance.handle(request, response, chain);
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
}
@Test
public void testExpiredCertificate() throws Exception {
X509Certificate cert = getCertificate("expired");
X509Certificate[] certs = new X509Certificate[]{cert};
when(request.getAttribute(X509_REQ_ATTR_NAME)).thenReturn(certs);
instance.handle(request, response, chain);
verify(delegate, never()).getUsername(any(X509Certificate.class));
verify(response).sendError(HttpServletResponse.SC_FORBIDDEN);
}
@Test
public void testValidCertificate() throws Exception {
X509Certificate cert = getCertificate("valid");
X509Certificate[] certs = new X509Certificate[]{cert};
when(request.getAttribute(X509_REQ_ATTR_NAME)).thenReturn(certs);
when(delegate.getUsername(cert)).thenReturn(TEST_USERNAME);
when(userRepository.findOrAddUser(eq(TEST_USERNAME), eq("valid"), isNull(String.class), anyString(), any(String[].class))).thenReturn(user);
instance.handle(request, response, chain);
verify(delegate).getUsername(cert);
verify(chain).next(request, response);
}
private X509Certificate getCertificate(String name) {
try {
KeyStore ks = KeyStore.getInstance("JKS");
InputStream ksis = X509AuthenticationHandlerTest.class.getResourceAsStream("/" + name + ".jks");
ks.load(ksis, "password".toCharArray());
return (X509Certificate) ks.getCertificate(name);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static interface Delegate {
String getUsername(X509Certificate cert);
boolean login(HttpServletRequest request);
}
private class TestX509AuthenticationHandler extends X509AuthenticationHandler {
public TestX509AuthenticationHandler(UserRepository userRepository, Graph graph) {
super(userRepository, graph);
}
@Override
protected String getUsername(X509Certificate cert) {
return delegate.getUsername(cert);
}
}
}