package io.lumify.web;

import io.lumify.core.bootstrap.InjectHelper;
import io.lumify.miniweb.HandlerChain;
import io.lumify.core.model.user.UserRepository;
import io.lumify.core.user.User;
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(httpSession).setAttribute(CurrentUser.STRING_ATTRIBUTE_NAME, user.getUsername());
        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);
        }
    }
}

@@ -43,69 +43,33 @@
 ore.
-bootstrap.InjectHelper;%0Aimport io.lumify.miniweb.HandlerChain
+model.user.UserRepository
 ;%0Aim
@@ -80,38 +80,32 @@
  io.lumify.core.
-model.
 user.UserReposit
@@ -93,34 +93,24 @@
 re.user.User
-Repository
 ;%0Aimport io.
@@ -112,38 +112,44 @@
 t io.lumify.
-core.user.User
+miniweb.HandlerChain
 ;%0Aimport org

optimize imports