]> WPIA git - gigi.git/commitdiff
Merge "add: implement to define a strong authenticated login"
authorFelix Dörre <felix@dogcraft.de>
Tue, 10 Sep 2019 21:45:40 +0000 (23:45 +0200)
committerGerrit Code Review <gigi-system@dogcraft.de>
Tue, 10 Sep 2019 21:45:40 +0000 (23:45 +0200)
14 files changed:
src/club/wpia/gigi/api/CreateCertificate.java
src/club/wpia/gigi/pages/LoginPage.java
src/club/wpia/gigi/pages/admin/support/SupportEnterTicketForm.java
src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.java
src/club/wpia/gigi/pages/orga/MyOrganisationsForm.java
src/club/wpia/gigi/util/AuthorizationContext.java
tests/club/wpia/gigi/pages/account/TestCertificateRequest.java
tests/club/wpia/gigi/pages/main/CertStatusTest.java
tests/club/wpia/gigi/pages/main/KeyCompromiseTest.java
tests/club/wpia/gigi/pages/main/KeyCompromiseTestMessage.java
tests/club/wpia/gigi/util/TestAuthorizationContext.java [new file with mode: 0644]
tests/club/wpia/gigi/util/TestCAAValidation.java
util-testing/club/wpia/gigi/DevelLauncher.java
util-testing/club/wpia/gigi/pages/Manager.java

index 6af284c032e19aedc93d6097aa8ee00a922f77b2..1890e4a9372d4eeb1e54faaa24f6758acea61d5b 100644 (file)
@@ -9,11 +9,11 @@ import javax.servlet.http.HttpServletResponse;
 
 import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.dbObjects.Certificate;
+import club.wpia.gigi.dbObjects.Certificate.CertificateStatus;
 import club.wpia.gigi.dbObjects.CertificateProfile;
 import club.wpia.gigi.dbObjects.Job;
 import club.wpia.gigi.dbObjects.Organisation;
 import club.wpia.gigi.dbObjects.User;
-import club.wpia.gigi.dbObjects.Certificate.CertificateStatus;
 import club.wpia.gigi.pages.account.certs.CertificateRequest;
 import club.wpia.gigi.util.AuthorizationContext;
 import club.wpia.gigi.util.CertExporter;
@@ -38,7 +38,7 @@ public class CreateCertificate extends APIPoint {
                 return;
             }
         }
-        AuthorizationContext ctx = new AuthorizationContext(u, u);
+        AuthorizationContext ctx = new AuthorizationContext(u, u, true);
         String asOrg = req.getParameter("asOrg");
         if (asOrg != null) {
             try {
@@ -54,7 +54,7 @@ public class CreateCertificate extends APIPoint {
                     resp.sendError(500, "Error, Organisation with id " + i + " not found.");
                     return;
                 } else {
-                    ctx = new AuthorizationContext(o0, u);
+                    ctx = new AuthorizationContext(o0, u, true);
                 }
             } catch (NumberFormatException e) {
                 resp.sendError(500, "Error, as Org is not an integer");
index 66412a9166adee300775efa19f2d60c9901917b4..fccfea1d2e8db8f0d793af85d7ca930dd9618f33 100644 (file)
@@ -6,6 +6,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.math.BigInteger;
 import java.security.cert.X509Certificate;
+import java.util.Date;
 import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
@@ -15,6 +16,7 @@ import javax.servlet.http.HttpSession;
 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.CertificateOwner;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.dbObjects.User;
@@ -140,7 +142,7 @@ public class LoginPage extends Page {
                     }
                 }
 
-                loginSession(req, user);
+                loginSession(req, user, false);
                 req.getSession().setAttribute(LOGIN_METHOD, new TranslateCommand("Password"));
                 return;
             }
@@ -161,11 +163,15 @@ public class LoginPage extends Page {
 
     private void tryAuthWithCertificate(HttpServletRequest req, X509Certificate x509Certificate) {
         BigInteger serial = extractSerialFormCert(x509Certificate);
+        Certificate c = Certificate.getBySerial(serial);
         User user = fetchUserBySerial(serial);
         if (user == null) {
             return;
         }
-        loginSession(req, user);
+        if (c.getExpiryDate().before(new Date()) || c.getRevocationDate() != null || c.isLoginEnabled() == false) {
+            return;
+        }
+        loginSession(req, user, true);
         req.getSession().setAttribute(CERT_SERIAL, serial);
         req.getSession().setAttribute(CERT_ISSUER, x509Certificate.getIssuerDN());
         req.getSession().setAttribute(LOGIN_METHOD, new TranslateCommand("Certificate"));
@@ -194,7 +200,7 @@ public class LoginPage extends Page {
 
     private static final Group LOGIN_BLOCKED = Group.BLOCKED_LOGIN;
 
-    private void loginSession(HttpServletRequest req, User user) {
+    private void loginSession(HttpServletRequest req, User user, boolean isStronglyAuthenticated) {
         if (user.isInGroup(LOGIN_BLOCKED)) {
             return;
         }
@@ -203,7 +209,7 @@ public class LoginPage extends Page {
         HttpSession hs = req.getSession();
         hs.setAttribute(LOGGEDIN, true);
         hs.setAttribute(Language.SESSION_ATTRIB_NAME, user.getPreferredLocale());
-        hs.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user));
+        hs.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user, isStronglyAuthenticated));
     }
 
     @Override
index 58b2997e11ae9b84174d3bf9a5b8886a797db6bd..918df15d156806e17cfc3f8c6916a0f551da1ebd 100644 (file)
@@ -37,7 +37,7 @@ public class SupportEnterTicketForm extends Form {
             throw new GigiApiException("Ticket format malformed");
         } else if (req.getParameter("deleteTicket") != null) {
             AuthorizationContext ac = LoginPage.getAuthorizationContext(req);
-            req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(ac.getActor(), ac.getActor()));
+            req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(ac.getActor(), ac.getActor(), ac.isStronglyAuthenticated()));
             return new RedirectResult(SupportEnterTicketPage.PATH);
         }
         throw new GigiApiException("No valid action given.");
index 7445c52c54946cc87c00c02780aebdefeef88f20..71909cf24b48d0793262125897a96dc038c45db1 100644 (file)
@@ -63,7 +63,7 @@ public class SupportUserDetailsForm extends Form {
                 if (toMod == Group.SUPPORTER) {
                     user.revoke(toMod);
                     AuthorizationContext ac = LoginPage.getAuthorizationContext(req);
-                    req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(ac.getActor(), ac.getActor()));
+                    req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(ac.getActor(), ac.getActor(), ac.isStronglyAuthenticated()));
                     return new RedirectResult(MyDetails.PATH);
                 }
             }
index 8858c5c0af631946f59850aabd348a8ed2e7be3d..c4120fc7e6108c8c1875bca7d0013c7d8e13f0d5 100644 (file)
@@ -31,8 +31,9 @@ public class MyOrganisationsForm extends Form {
 
     @Override
     public SubmissionResult submit(HttpServletRequest req) throws GigiApiException {
+        AuthorizationContext sessionAc = (AuthorizationContext) req.getSession().getAttribute(Gigi.AUTH_CONTEXT);
         if (req.getParameter("org-leave") != null) {
-            req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(target.getActor(), target.getActor()));
+            req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(target.getActor(), target.getActor(), sessionAc.isStronglyAuthenticated()));
             return new RedirectResult(SwitchOrganisation.PATH);
         }
         Enumeration<String> i = req.getParameterNames();
@@ -51,7 +52,7 @@ public class MyOrganisationsForm extends Form {
         for (Organisation org : target.getActor().getOrganisations()) {
             if (org.getId() == orgId) {
 
-                req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(org, target.getActor()));
+                req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(org, target.getActor(), sessionAc.isStronglyAuthenticated()));
                 return new RedirectResult(SwitchOrganisation.PATH);
             }
         }
index 13f70cc7c96c088c301d6a9c618ce152048fc586..719ac923b2936d3c06fb8a9abdaed25d1dc5f4fa 100644 (file)
@@ -24,7 +24,9 @@ public class AuthorizationContext implements Outputable, Serializable {
 
     private final String supporterTicketId;
 
-    public AuthorizationContext(CertificateOwner target, User actor) {
+    private final boolean isStronglyAuthenticated;
+
+    public AuthorizationContext(CertificateOwner target, User actor, boolean isStronglyAuthenticated) {
         if (actor == null) {
             throw new Error("Internal Error: The actor of an AuthorizationContext must not be null!");
         }
@@ -34,6 +36,7 @@ public class AuthorizationContext implements Outputable, Serializable {
         this.target = target;
         this.actor = actor;
         this.supporterTicketId = null;
+        this.isStronglyAuthenticated = isStronglyAuthenticated;
     }
 
     public AuthorizationContext(User actor, String supporterTicket) throws GigiApiException {
@@ -49,6 +52,7 @@ public class AuthorizationContext implements Outputable, Serializable {
             throw new GigiApiException("requires a supporter");
         }
         this.supporterTicketId = supporterTicket;
+        this.isStronglyAuthenticated = true;
     }
 
     public CertificateOwner getTarget() {
@@ -111,4 +115,8 @@ public class AuthorizationContext implements Outputable, Serializable {
     public boolean canVerify() {
         return target instanceof User && ((User) target).canVerify();
     }
+
+    public boolean isStronglyAuthenticated() {
+        return isStronglyAuthenticated;
+    }
 }
index 03c9a8d136c666bf507a98457b67c7ea801bbfd2..023be5ae543f307ba95376b116fd419bc1391f0e 100644 (file)
@@ -16,7 +16,6 @@ import club.wpia.gigi.dbObjects.EmailAddress;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.pages.account.certs.CertificateRequest;
 import club.wpia.gigi.testUtils.ClientTest;
-import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
 import club.wpia.gigi.util.AuthorizationContext;
 import club.wpia.gigi.util.TimeConditions;
 
@@ -27,7 +26,7 @@ public class TestCertificateRequest extends ClientTest {
     AuthorizationContext ac;
 
     public TestCertificateRequest() throws GeneralSecurityException, IOException, GigiApiException {
-        ac = new AuthorizationContext(u, u);
+        ac = new AuthorizationContext(u, u, false);
         makeAgent(u.getId());
     }
 
index f16ebb36af4c62115f0660f385a3448503c6c39d..ef6cf0c789f5fee6208318f201b8ca44c38f17e0 100644 (file)
@@ -46,7 +46,7 @@ public class CertStatusTest extends ClientTest {
 
         KeyPair kp = generateKeypair();
         String csr = generatePEMCSR(kp, "CN=test");
-        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
+        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u, false), csr);
         cr.update(CertificateRequest.DEFAULT_CN, Digest.SHA512.toString(), "client", null, null, "email:" + email + "\n");
         cert = cr.draft();
         Job j = cert.issue(null, "2y", u);
index 406590d2d161ba4c32ac6da90cee0b2f4c449b35..89180e866daaba388ac1967f707c35361d5c5188 100644 (file)
@@ -79,7 +79,7 @@ public class KeyCompromiseTest extends ClientTest {
         KeyPair kp = generateKeypair();
         priv = kp.getPrivate();
         String csr = generatePEMCSR(kp, "CN=test");
-        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
+        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u, false), csr);
         cr.update(CertificateRequest.DEFAULT_CN, Digest.SHA512.toString(), "client", null, null, "email:" + email + "\n");
         cert = cr.draft();
         Job j = cert.issue(null, "2y", u);
index 0cc355d4ae4743367811e1c891f617e119f65efe..f9fb65641602f6412da5bcf4dbf34e2aa26ca398 100644 (file)
@@ -37,7 +37,7 @@ public class KeyCompromiseTestMessage extends ClientTest {
         KeyPair kp = generateKeypair();
         priv = kp.getPrivate();
         String csr = generatePEMCSR(kp, "CN=test");
-        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
+        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u, false), csr);
         cr.update(CertificateRequest.DEFAULT_CN, Digest.SHA512.toString(), "client", null, null, "email:" + email + "\n");
         cert = cr.draft();
         Job j = cert.issue(null, "2y", u);
diff --git a/tests/club/wpia/gigi/util/TestAuthorizationContext.java b/tests/club/wpia/gigi/util/TestAuthorizationContext.java
new file mode 100644 (file)
index 0000000..7f8e4e7
--- /dev/null
@@ -0,0 +1,23 @@
+package club.wpia.gigi.util;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import club.wpia.gigi.testUtils.ClientBusinessTest;
+
+public class TestAuthorizationContext extends ClientBusinessTest {
+
+    @Test
+    public void testStronglyAuthenticated() {
+        AuthorizationContext ac = new AuthorizationContext(u, u, true);
+        assertTrue(ac.isStronglyAuthenticated());
+    }
+
+    @Test
+    public void testNotStronglyAuthenticated() {
+        AuthorizationContext ac = new AuthorizationContext(u, u, false);
+        assertFalse(ac.isStronglyAuthenticated());
+    }
+
+}
index a762570025e470a8a3f7e31a2c2f6293c4ad75a4..f69c3ecbe0e56637751cca2c6c7cbd087ecf13ca 100644 (file)
@@ -63,7 +63,7 @@ public class TestCAAValidation extends ClientTest {
         Domain d = new Domain(u, u, PublicSuffixes.getInstance().getRegistrablePart(domain));
         verify(d);
         String csr = generatePEMCSR(generateKeypair(), "CN=test");
-        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
+        CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u, false), csr);
         try {
             cr.update("", Digest.SHA512.toString(), "server", null, null, "dns:" + domain + "\n");
         } catch (GigiApiException e) {
index 9789637a6b7c3fa8e6548fb119cf3e8c58907c3b..e62ad6814bdd9a1237d390a7af265eb2b312a43f 100644 (file)
@@ -212,7 +212,9 @@ public class DevelLauncher {
                     }
                     sess.setAttribute(LOGGEDIN, true);
                     sess.setAttribute(Language.SESSION_ATTRIB_NAME, user.getPreferredLocale());
-                    sess.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user));
+                    // ac.isStronglyAuthenticated() set to true to bypass
+                    // certificate login for testing
+                    sess.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user, true));
                     req.getSession().setAttribute(LOGIN_METHOD, new TranslateCommand("Ticket"));
                     resp.getWriter().println("ticket consumed");
                     ticketUsed = true;
index f48c5bed3d836c1d2a8542047bdfe9d30007eadc..cdde36f25f2ff82cfbd52d575f06838fd74d5f5a 100644 (file)
@@ -302,6 +302,7 @@ public class Manager extends Page {
 
     @Override
     public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        AuthorizationContext sessionAc = (AuthorizationContext) req.getSession().getAttribute(Gigi.AUTH_CONTEXT);
         if (req.getParameter("create") != null) {
             String prefix = req.getParameter("prefix");
             String domain = req.getParameter("suffix");
@@ -438,7 +439,7 @@ public class Manager extends Page {
 
                 byte[] res = s.getEncoded(sign);
 
-                CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), Base64.getEncoder().encodeToString(res), "challenge");
+                CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u, sessionAc.isStronglyAuthenticated()), Base64.getEncoder().encodeToString(res), "challenge");
                 cr.update(CertificateRequest.DEFAULT_CN, Digest.SHA512.toString(), "client", null, "", "email:" + u.getEmail());
                 Certificate draft = cr.draft();
                 draft.issue(null, "2y", u).waitFor(10000);