add: ensure that for support actions certificate login is used
authorINOPIAE <m.maengel@inopiae.de>
Mon, 8 Jul 2019 12:53:28 +0000 (14:53 +0200)
committerINOPIAE <m.maengel@inopiae.de>
Sun, 8 Sep 2019 19:12:31 +0000 (21:12 +0200)
related to issue #150

Change-Id: I2bc368a8b93d1ccbb3522e74213d2057bd9b2d67

14 files changed:
src/club/wpia/gigi/pages/MainPage.java
src/club/wpia/gigi/pages/MainPage.templ
src/club/wpia/gigi/pages/admin/support/SupportEnterTicketPage.java
src/club/wpia/gigi/util/AuthorizationContext.java
tests/club/wpia/gigi/pages/TestMain.java [new file with mode: 0644]
tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java
tests/club/wpia/gigi/pages/admin/TestSEAdminPageCertSearch.java
tests/club/wpia/gigi/pages/admin/TestSEAdminPageDetails.java
tests/club/wpia/gigi/pages/admin/TestSEAdminPageUserDomainSearch.java
tests/club/wpia/gigi/pages/admin/TestSEAdminPageUserMailSearch.java
tests/club/wpia/gigi/pages/admin/TestSEAdminTicketSetting.java
tests/club/wpia/gigi/testUtils/ClientTest.java
tests/club/wpia/gigi/testUtils/ManagedTest.java
tests/club/wpia/gigi/testUtils/SEClientTest.java

index 6d27910..53cad4a 100644 (file)
@@ -40,7 +40,12 @@ public class MainPage extends Page {
             vars.put("ra-agent", u.canVerify());
             vars.put("vp", u.getVerificationPoints());
             vars.put("xp", u.getExperiencePoints());
-
+            if (u.isInGroup(Group.SUPPORTER) || u.isInGroup(Group.ORG_AGENT) || u.isInGroup(Group.TTP_AGENT) || u.canVerify()) {
+                vars.put("certlogin", LoginPage.getAuthorizationContext(req).isStronglyAuthenticated());
+                vars.put("certlogininfo", true);
+            } else {
+                vars.put("certlogininfo", false);
+            }
             Certificate[] c = u.getCertificates(false);
             vars.put("c-no", c.length);
 
index a66ddd4..88506f3 100644 (file)
@@ -1,5 +1,18 @@
 <h3><?=_Welcome back, ${username}!?></h3>
 <h4><?=_Subscriber information?></h4>
+
+<? if($certlogininfo) { ?>
+  <? if($certlogin) { ?>
+    <div class="card card-body bg-light">
+      <p><?=_You are authenticated via certificate, so you will be able to perform all actions.?></p>
+    </div>
+  <? } else { ?>
+    <div class="alert alert-warning" role="alert">
+      <p><?=_For some actions, e.g. add verification, support, you need to be authenticated via certificate.?></p>
+    </div>
+  <? } ?>
+<? } ?>
+
 <div class="card card-body bg-light">
 <? if($ra-agent) { ?><p><?=_You are an RA Agent.?></p><? } ?>
 <p><?=_Assigned support permissions?>: <?=$support-groups?></p>
index 24f093a..14b1faa 100644 (file)
@@ -47,7 +47,7 @@ public class SupportEnterTicketPage extends Page {
 
     @Override
     public boolean isPermitted(AuthorizationContext ac) {
-        return ac != null && ac.isInGroup(Group.SUPPORTER);
+        return ac != null && ac.isInGroup(Group.SUPPORTER) && ac.isStronglyAuthenticated();
     }
 
 }
index 719ac92..9888309 100644 (file)
@@ -79,7 +79,7 @@ public class AuthorizationContext implements Outputable, Serializable {
     }
 
     public boolean canSupport() {
-        return getSupporterTicketId() != null && isInGroup(Group.SUPPORTER);
+        return getSupporterTicketId() != null && isInGroup(Group.SUPPORTER) && isStronglyAuthenticated();
     }
 
     private static final SprintfCommand sp = new SprintfCommand("Logged in as {0} via {1}.", Arrays.asList("${username", "${loginMethod"));
diff --git a/tests/club/wpia/gigi/pages/TestMain.java b/tests/club/wpia/gigi/pages/TestMain.java
new file mode 100644 (file)
index 0000000..682daf8
--- /dev/null
@@ -0,0 +1,68 @@
+package club.wpia.gigi.pages;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import org.junit.Test;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Certificate;
+import club.wpia.gigi.dbObjects.Certificate.CSRType;
+import club.wpia.gigi.dbObjects.Digest;
+import club.wpia.gigi.testUtils.ClientTest;
+import club.wpia.gigi.testUtils.IOUtils;
+
+public class TestMain extends ClientTest {
+
+    @Test
+    public void testPasswordLogin() throws MalformedURLException, IOException {
+        URLConnection uc = new URL("https://" + getServerName()).openConnection();
+        uc.addRequestProperty("Cookie", cookie);
+        String content = IOUtils.readURL(uc);
+
+        assertThat(content, not(containsString("via certificate")));
+
+        makeAgent(u.getId());
+        uc = new URL("https://" + getServerName()).openConnection();
+        uc.addRequestProperty("Cookie", cookie);
+        content = IOUtils.readURL(uc);
+        assertThat(content, containsString("For some actions, e.g. add verification, support, you need to be authenticated via certificate."));
+
+    }
+
+    @Test
+    public void testCertLogin() throws GeneralSecurityException, IOException, GigiApiException, InterruptedException {
+        KeyPair kp = generateKeypair();
+        String csr = generatePEMCSR(kp, "CN=" + u.getPreferredName().toString());
+        Certificate c = new Certificate(u, u, Certificate.buildDN("CN", u.getPreferredName().toString()), Digest.SHA256, csr, CSRType.CSR, getClientProfile());
+        final PrivateKey pk = kp.getPrivate();
+        await(c.issue(null, "2y", u));
+        final X509Certificate ce = c.cert();
+        c.setLoginEnabled(true);
+        cookie = login(pk, ce);
+        loginCertificate = c;
+        loginPrivateKey = pk;
+
+        URLConnection uc = new URL("https://" + getSecureServerName()).openConnection();
+        authenticate((HttpURLConnection) uc);
+        String content = IOUtils.readURL(uc);
+        assertThat(content, not(containsString("via certificate")));
+
+        makeAgent(u.getId());
+        uc = new URL("https://" + getSecureServerName()).openConnection();
+        authenticate((HttpURLConnection) uc);
+        content = IOUtils.readURL(uc);
+        assertThat(content, containsString("You are authenticated via certificate, so you will be able to perform all actions."));
+
+    }
+}
index 97ac6a0..180455c 100644 (file)
@@ -158,7 +158,7 @@ public class TestSEAdminNotificationMail extends SEClientTest {
 
         // supporter removes supporter flag
         URLConnection uc = post(SupportUserDetailsPage.PATH + u.getId() + "/", "removeGroup&groupToModify=" + URLEncoder.encode(Group.SUPPORTER.getDBName(), "UTF-8"));
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + MyDetails.PATH, uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + MyDetails.PATH, uc.getHeaderField("Location"));
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         Group.SUPPORTER.getName().output(pw, Language.getInstance(Locale.ENGLISH), new HashMap<String, Object>());
index 74375f2..cf9b403 100644 (file)
@@ -46,13 +46,13 @@ public class TestSEAdminPageCertSearch extends SEClientTest {
     @Test
     public void testSerialSearch() throws IOException {
         URLConnection uc = post(cookie, FindCertPage.PATH, "certType=serial&process=Next&cert=" + c.getSerial(), 0);
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), uc.getHeaderField("Location"));
     }
 
     @Test
     public void testEmailSearch() throws IOException {
         URLConnection uc = post(cookie, FindCertPage.PATH, "certType=email&process=Next&cert=" + URLEncoder.encode(certMail, "UTF-8"), 0);
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), uc.getHeaderField("Location"));
     }
 
     @Test
@@ -67,7 +67,7 @@ public class TestSEAdminPageCertSearch extends SEClientTest {
     @Test
     public void testRevoke() throws IOException {
         URLConnection conn = post(Certificates.SUPPORT_PATH + "/" + c.getSerial(), "action=revoke");
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), conn.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + Certificates.SUPPORT_PATH + "/" + c.getSerial(), conn.getHeaderField("Location"));
         for (int i = 0; i < 2; i++) {
             TestMail tm = getMailReceiver().receive(i == 0 ? ServerConstants.getSupportMailAddress() : certMail);
             assertThat(tm.getMessage(), CoreMatchers.containsString(certMail));
index 9b92fcb..9187c4f 100644 (file)
@@ -15,6 +15,7 @@ import org.junit.Test;
 
 import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.GigiPreparedStatement;
+import club.wpia.gigi.dbObjects.Certificate;
 import club.wpia.gigi.dbObjects.EmailAddress;
 import club.wpia.gigi.dbObjects.ObjectCache;
 import club.wpia.gigi.dbObjects.User;
@@ -27,7 +28,11 @@ import club.wpia.gigi.util.DayDate;
 
 public class TestSEAdminPageDetails extends SEClientTest {
 
-    public TestSEAdminPageDetails() throws IOException, GigiApiException {}
+    private Certificate cs;
+
+    public TestSEAdminPageDetails() throws IOException, GigiApiException {
+        cs = loginCertificate;
+    }
 
     @Test
     public void testUserDetailsDisplay() throws MalformedURLException, IOException {
@@ -118,12 +123,13 @@ public class TestSEAdminPageDetails extends SEClientTest {
         String clientCookie = login(email, TEST_PASSWORD);
 
         // try to open mypoints as user
+        loginCertificate = null;
         HttpURLConnection uc = get(clientCookie, SupportUserDetailsPage.PATH + id + "/points");
 
         assertEquals(403, uc.getResponseCode());
 
         // enter verification and open mypoints as supporter
-
+        loginCertificate = cs;
         makeAgent(this.id);
         String location = createUniqueName();
         try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?, `when`=? ")) {
@@ -157,7 +163,10 @@ public class TestSEAdminPageDetails extends SEClientTest {
     }
 
     private int logCountUser(String cookie) throws IOException {
-        return getLogEntryCount(IOUtils.readURL(get(cookie, History.PATH)));
+        loginCertificate = null;
+        int count = getLogEntryCount(IOUtils.readURL(get(cookie, History.PATH)));
+        loginCertificate = cs;
+        return count;
     }
 
     private int getLogEntryCount(String readURL) {
index d820a1d..72bb2a6 100644 (file)
@@ -52,13 +52,13 @@ public class TestSEAdminPageUserDomainSearch extends SEClientTest {
     public void testDomainSearch() throws MalformedURLException, UnsupportedEncodingException, IOException, GigiApiException {
         URLConnection uc = post(FindUserByDomainPage.PATH, "process&domain=" + URLEncoder.encode(domainName, "UTF-8"));
 
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportUserDetailsPage.PATH + tid + "/", uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportUserDetailsPage.PATH + tid + "/", uc.getHeaderField("Location"));
     }
 
     @Test
     public void testDomainSearchById() throws MalformedURLException, UnsupportedEncodingException, IOException, GigiApiException {
         URLConnection uc = post(FindUserByDomainPage.PATH, "process&domain=#" + d.getId());
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportUserDetailsPage.PATH + tid + "/", uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportUserDetailsPage.PATH + tid + "/", uc.getHeaderField("Location"));
     }
 
     @Test
@@ -91,7 +91,7 @@ public class TestSEAdminPageUserDomainSearch extends SEClientTest {
         // test
         URLConnection uc = post(FindUserByDomainPage.PATH, "process&domain=" + URLEncoder.encode(dom, "UTF-8"));
 
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportOrgDomainPage.PATH + d.getId(), uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportOrgDomainPage.PATH + d.getId(), uc.getHeaderField("Location"));
 
         String s = IOUtils.readURL(get(cookie, SupportOrgDomainPage.PATH + d.getId()));
         assertThat(s, containsString(dom));
index a21ca96..50d96dd 100644 (file)
@@ -30,7 +30,7 @@ public class TestSEAdminPageUserMailSearch extends SEClientTest {
         int id = createVerifiedUser("Först", "Secönd", mail, TEST_PASSWORD);
 
         URLConnection uc = post(cookie, FindUserByEmailPage.PATH, "process&email=" + URLEncoder.encode(mail, "UTF-8"), 0);
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
     }
 
     @Test
@@ -39,7 +39,7 @@ public class TestSEAdminPageUserMailSearch extends SEClientTest {
         int id = createVerifiedUser("Först", "Secönd", mail, TEST_PASSWORD);
 
         URLConnection uc = post(cookie, FindUserByEmailPage.PATH, "process&email=" + URLEncoder.encode("%@example.tld", "UTF-8"), 0);
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
     }
 
     @Test
@@ -91,7 +91,7 @@ public class TestSEAdminPageUserMailSearch extends SEClientTest {
         createVerifiedEmail(testuser, mail2);
 
         URLConnection uc = post(cookie, FindUserByEmailPage.PATH, "process&email=" + URLEncoder.encode(mail2, "UTF-8"), 0);
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
     }
 
     @Test
@@ -122,7 +122,7 @@ public class TestSEAdminPageUserMailSearch extends SEClientTest {
         createVerifiedEmail(testuser, mail3);
 
         URLConnection uc = post(cookie, FindUserByEmailPage.PATH, "process&email=" + URLEncoder.encode("%@example3.org", "UTF-8"), 0);
-        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
+        assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.SECURE) + SupportUserDetailsPage.PATH + id + "/", uc.getHeaderField("Location"));
 
         uc = post(cookie, FindUserByEmailPage.PATH, "process&email=" + URLEncoder.encode("%@test3.org", "UTF-8"), 0);
 
index e20b494..e85b03e 100644 (file)
@@ -7,12 +7,20 @@ import static org.junit.Assert.*;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
 import java.util.Random;
 
 import org.junit.Test;
 
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Certificate;
+import club.wpia.gigi.dbObjects.Certificate.CSRType;
+import club.wpia.gigi.dbObjects.Digest;
 import club.wpia.gigi.dbObjects.Group;
+import club.wpia.gigi.pages.admin.support.FindCertPage;
 import club.wpia.gigi.pages.admin.support.FindUserByDomainPage;
 import club.wpia.gigi.pages.admin.support.FindUserByEmailPage;
 import club.wpia.gigi.pages.admin.support.SupportEnterTicketForm;
@@ -24,16 +32,31 @@ public class TestSEAdminTicketSetting extends ClientTest {
 
     public TestSEAdminTicketSetting() throws IOException, GigiApiException {
         grant(u, Group.SUPPORTER);
-        cookie = login(email, TEST_PASSWORD);
+        try {
+            KeyPair kp = generateKeypair();
+            String csr = generatePEMCSR(kp, "CN=" + u.getPreferredName().toString());
+            Certificate c = new Certificate(u, u, Certificate.buildDN("CN", u.getPreferredName().toString()), Digest.SHA256, csr, CSRType.CSR, getClientProfile());
+            final PrivateKey pk = kp.getPrivate();
+            await(c.issue(null, "2y", u));
+            final X509Certificate ce = c.cert();
+            c.setLoginEnabled(true);
+            cookie = login(pk, ce);
+            loginCertificate = c;
+            loginPrivateKey = pk;
+        } catch (InterruptedException e) {
+            throw new GigiApiException(e.toString());
+        } catch (GeneralSecurityException e) {
+            throw new GigiApiException(e.toString());
+        }
     }
 
     @Test
     public void testFulltextMailSearch() throws MalformedURLException, UnsupportedEncodingException, IOException {
         assertEquals(403, get(FindUserByEmailPage.PATH).getResponseCode());
-        assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=a20140808.8&setTicket=action", 0).getResponseCode());
+        assertEquals(302, post(SupportEnterTicketPage.PATH, "ticketno=a20140808.8&setTicket=action", 0).getResponseCode());
         assertEquals(200, get(FindUserByEmailPage.PATH).getResponseCode());
         assertEquals(200, get(FindUserByDomainPage.PATH).getResponseCode());
-        assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=a20140808.8&deleteTicket=action", 0).getResponseCode());
+        assertEquals(302, post(SupportEnterTicketPage.PATH, "ticketno=a20140808.8&deleteTicket=action", 0).getResponseCode());
         assertEquals(403, get(FindUserByEmailPage.PATH).getResponseCode());
     }
 
@@ -45,9 +68,9 @@ public class TestSEAdminTicketSetting extends ClientTest {
         // test allowed character
         for (char ch : SupportEnterTicketForm.TICKET_PREFIX.toCharArray()) {
             ticket = ch + "20171212.1";
-            assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=" + ticket + "&setTicket=action", 0).getResponseCode());
+            assertEquals(302, post(SupportEnterTicketPage.PATH, "ticketno=" + ticket + "&setTicket=action", 0).getResponseCode());
             ticket = Character.toUpperCase(ch) + "20171212.1";
-            assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=" + ticket + "&setTicket=action", 0).getResponseCode());
+            assertEquals(302, post(SupportEnterTicketPage.PATH, "ticketno=" + ticket + "&setTicket=action", 0).getResponseCode());
             alphabet = alphabet.replaceAll(Character.toString(ch), "");
         }
 
@@ -99,4 +122,15 @@ public class TestSEAdminTicketSetting extends ClientTest {
         String res = IOUtils.readURL(post(SupportEnterTicketPage.PATH, "ticketno=" + ticket + "&setTicket=action"));
         assertThat(res, containsString("Ticket format malformed"));
     }
+
+    @Test
+    public void testPWLogin() throws MalformedURLException, UnsupportedEncodingException, IOException {
+        String cookiePW = login(email, TEST_PASSWORD);
+        loginCertificate = null;
+        assertEquals(403, get(cookiePW, SupportEnterTicketPage.PATH).getResponseCode());
+        assertEquals(403, get(cookiePW, FindUserByEmailPage.PATH).getResponseCode());
+        assertEquals(403, get(cookiePW, FindUserByDomainPage.PATH).getResponseCode());
+        assertEquals(403, get(cookiePW, FindCertPage.PATH).getResponseCode());
+    }
+
 }
index 1cd12d2..17103f7 100644 (file)
@@ -1,8 +1,14 @@
 package club.wpia.gigi.testUtils;
 
 import java.io.IOException;
+import java.io.OutputStream;
 import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.security.GeneralSecurityException;
 
+import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.dbObjects.User;
 
 /**
@@ -44,11 +50,44 @@ public abstract class ClientTest extends ManagedTest {
     }
 
     public HttpURLConnection post(String path, String query, int formIndex) throws IOException {
-        return post(cookie, path, query, formIndex);
+        String server = getServerName();
+        if (loginCertificate != null) {
+            server = getSecureServerName();
+        }
+        URLConnection uc = new URL("https://" + server + path).openConnection();
+        authenticate((HttpURLConnection) uc);
+        String csrf = getCSRF(uc, formIndex);
+
+        uc = new URL("https://" + server + path).openConnection();
+        authenticate((HttpURLConnection) uc);
+        uc.setDoOutput(true);
+        OutputStream os = uc.getOutputStream();
+        os.write(("csrf=" + URLEncoder.encode(csrf, "UTF-8") + "&" //
+                + query//
+        ).getBytes("UTF-8"));
+        os.flush();
+        return (HttpURLConnection) uc;
     }
 
     public HttpURLConnection get(String path) throws IOException {
-        return get(cookie, path);
+        String server = getServerName();
+        if (loginCertificate != null) {
+            server = getSecureServerName();
+        }
+        URLConnection uc = new URL("https://" + server + path).openConnection();
+        authenticate((HttpURLConnection) uc);
+        return (HttpURLConnection) uc;
+    }
+
+    protected void authenticate(HttpURLConnection uc) throws IOException {
+        uc.addRequestProperty("Cookie", cookie);
+        if (loginCertificate != null) {
+            try {
+                authenticateClientCert(loginPrivateKey, loginCertificate.cert(), uc);
+            } catch (GeneralSecurityException | GigiApiException e) {
+                throw new IOException(e);
+            }
+        }
     }
 
 }
index aa18a30..25df272 100644 (file)
@@ -17,6 +17,7 @@ import java.net.URLConnection;
 import java.net.URLEncoder;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
@@ -42,6 +43,7 @@ import club.wpia.gigi.DevelLauncher;
 import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.database.GigiResultSet;
+import club.wpia.gigi.dbObjects.Certificate;
 import club.wpia.gigi.dbObjects.EmailAddress;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.dbObjects.Job;
@@ -70,6 +72,10 @@ public class ManagedTest extends ConfiguredTest {
 
     private static String acceptLanguage = null;
 
+    protected static Certificate loginCertificate;
+
+    protected static PrivateKey loginPrivateKey;
+
     public static void setAcceptLanguage(String acceptLanguage) {
         ManagedTest.acceptLanguage = acceptLanguage;
     }
@@ -469,12 +475,16 @@ public class ManagedTest extends ConfiguredTest {
     }
 
     public static HttpURLConnection post(String cookie, String path, String query, int formIndex) throws IOException, MalformedURLException, UnsupportedEncodingException {
-        URLConnection uc = new URL("https://" + getServerName() + path).openConnection();
-        uc.addRequestProperty("Cookie", cookie);
+        String server = getServerName();
+        if (loginCertificate != null) {
+            server = getSecureServerName();
+        }
+        URLConnection uc = new URL("https://" + server + path).openConnection();
+        authenticate((HttpURLConnection) uc, cookie);
         String csrf = getCSRF(uc, formIndex);
 
-        uc = new URL("https://" + getServerName() + path).openConnection();
-        uc.addRequestProperty("Cookie", cookie);
+        uc = new URL("https://" + server + path).openConnection();
+        authenticate((HttpURLConnection) uc, cookie);
         uc.setDoOutput(true);
         OutputStream os = uc.getOutputStream();
         os.write(("csrf=" + URLEncoder.encode(csrf, "UTF-8") + "&" //
@@ -485,8 +495,12 @@ public class ManagedTest extends ConfiguredTest {
     }
 
     public static HttpURLConnection get(String cookie, String path) throws IOException {
-        URLConnection uc = new URL("https://" + getServerName() + path).openConnection();
-        uc.addRequestProperty("Cookie", cookie);
+        String server = getServerName();
+        if (loginCertificate != null) {
+            server = getSecureServerName();
+        }
+        URLConnection uc = new URL("https://" + server + path).openConnection();
+        authenticate((HttpURLConnection) uc, cookie);
         return (HttpURLConnection) uc;
     }
 
@@ -525,4 +539,15 @@ public class ManagedTest extends ConfiguredTest {
         supporter = User.getById(i);
         return supporter;
     }
+
+    protected static void authenticate(HttpURLConnection uc, String cookie) throws IOException {
+        uc.addRequestProperty("Cookie", cookie);
+        if (loginCertificate != null) {
+            try {
+                authenticateClientCert(loginPrivateKey, loginCertificate.cert(), uc);
+            } catch (GeneralSecurityException | GigiApiException e) {
+                throw new IOException(e);
+            }
+        }
+    }
 }
index 004f34f..358a8c1 100644 (file)
@@ -3,8 +3,15 @@ package club.wpia.gigi.testUtils;
 import static org.junit.Assert.*;
 
 import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
 
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Certificate;
+import club.wpia.gigi.dbObjects.Certificate.CSRType;
+import club.wpia.gigi.dbObjects.Digest;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.pages.admin.support.SupportEnterTicketPage;
 
@@ -16,7 +23,22 @@ public abstract class SEClientTest extends ClientTest {
 
     public SEClientTest() throws IOException, GigiApiException {
         grant(u, Group.SUPPORTER);
-        cookie = login(email, TEST_PASSWORD);
+        try {
+            KeyPair kp = generateKeypair();
+            String csr = generatePEMCSR(kp, "CN=" + u.getPreferredName().toString());
+            Certificate c = new Certificate(u, u, Certificate.buildDN("CN", u.getPreferredName().toString()), Digest.SHA256, csr, CSRType.CSR, getClientProfile());
+            final PrivateKey pk = kp.getPrivate();
+            await(c.issue(null, "2y", u));
+            final X509Certificate ce = c.cert();
+            c.setLoginEnabled(true);
+            loginCertificate = c;
+            loginPrivateKey = pk;
+            cookie = login(pk, ce);
+        } catch (InterruptedException e) {
+            throw new GigiApiException(e.toString());
+        } catch (GeneralSecurityException e) {
+            throw new GigiApiException(e.toString());
+        }
         assertEquals(302, post(cookie, SupportEnterTicketPage.PATH, "ticketno=a20140808.8&setTicket=action", 0).getResponseCode());
     }