]> WPIA git - gigi.git/blobdiff - tests/club/wpia/gigi/testUtils/ConfiguredTest.java
add: enable Support to see the new RA Agent status
[gigi.git] / tests / club / wpia / gigi / testUtils / ConfiguredTest.java
index ead6ffd2c02a0fa1f563234d1fe42408ccb3842e..322af0bc55e6d15e2b744316b8431b0c2c4d17c4 100644 (file)
@@ -8,11 +8,19 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.math.BigInteger;
 import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
 import java.security.Signature;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
 import java.sql.SQLException;
+import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
@@ -25,22 +33,28 @@ import java.util.regex.Pattern;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
+import club.wpia.gigi.Gigi;
 import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.DatabaseConnection;
 import club.wpia.gigi.database.DatabaseConnection.Link;
 import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.database.SQLFileManager.ImportType;
+import club.wpia.gigi.dbObjects.CATS;
 import club.wpia.gigi.dbObjects.CATS.CATSType;
 import club.wpia.gigi.dbObjects.CertificateProfile;
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.Contract.ContractType;
 import club.wpia.gigi.dbObjects.Domain;
 import club.wpia.gigi.dbObjects.DomainPingType;
 import club.wpia.gigi.dbObjects.User;
+import club.wpia.gigi.passwords.PasswordStrengthChecker;
 import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
 import club.wpia.gigi.util.DatabaseManager;
 import club.wpia.gigi.util.DomainAssessment;
 import club.wpia.gigi.util.Notary;
 import club.wpia.gigi.util.PEM;
 import club.wpia.gigi.util.PasswordHash;
+import club.wpia.gigi.util.RandomToken;
 import club.wpia.gigi.util.ServerConstants;
 import club.wpia.gigi.util.TimeConditions;
 import sun.security.pkcs10.PKCS10;
@@ -98,6 +112,7 @@ public abstract class ConfiguredTest {
         TimeConditions.init(props);
         DomainAssessment.init(props);
         PasswordHash.init(props);
+        Gigi.setPasswordChecker(new PasswordStrengthChecker());
 
         if ( !DatabaseConnection.isInited()) {
             DatabaseConnection.init(testProps);
@@ -177,6 +192,99 @@ public abstract class ConfiguredTest {
         return keyPair;
     }
 
+    public static KeyPair generateBrokenKeypair() throws GeneralSecurityException {
+        KeyPair keyPair = null;
+        File f = new File("testBrokenKeypair");
+        if (f.exists()) {
+            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
+                keyPair = (KeyPair) ois.readObject();
+            } catch (ClassNotFoundException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            // -----BEGIN SHAMELESSLY ADAPTED BLOCK-----
+            /**
+             * Modified original RSA key generator to use three primes with one
+             * prime set to fixed value to allow simple checking for such faulty
+             * keys.
+             *
+             * @link sun.security.rsa.RSAKeyPairGenerator#generateKeyPair
+             */
+
+            KeyFactory factory = KeyFactory.getInstance("RSA");
+            Random random = new SecureRandom();
+            int keySize = 4096;
+            long r_lv = 7331;
+
+            // The generated numbers p q and r fall into the
+            // following ranges:
+            // - p: 2^(lp-1) < p < 2^lp
+            // - q: 2^(lq-1) < q < 2^lq
+            // - r: 2^12 < r < 2^13
+            // Thus the generated number has at least lp+lq+11 bit and
+            // can have at most lp+lq+13 bit.
+            // Thus for random selection of p and q the algorithm will
+            // at some point select a number of length n=n/2+lr+(n-n/2-lr)=>n
+            // bit.
+            int lp = (keySize + 1) >> 1;
+            int lr = BigInteger.valueOf(r_lv).bitLength();
+            int lq = keySize - lp - lr;
+
+            BigInteger e = BigInteger.valueOf(7331);
+
+            keyPair = null;
+            while (keyPair == null) {
+                // generate two random primes of size lp/lq
+                BigInteger p, q, r, n;
+
+                r = BigInteger.valueOf(r_lv);
+                do {
+                    p = BigInteger.probablePrime(lp, random);
+                    q = BigInteger.probablePrime(lq, random);
+
+                    // modulus n = p * q * r
+                    n = p.multiply(q).multiply(r);
+
+                    // even with correctly sized p, q and r, there is a chance
+                    // that n will be one bit short. re-generate the
+                    // primes if so.
+                } while (n.bitLength() < keySize);
+
+                // phi = (p - 1) * (q - 1) * (r - 1) must be relative prime to e
+                // otherwise RSA just won't work ;-)
+                BigInteger p1 = p.subtract(BigInteger.ONE);
+                BigInteger q1 = q.subtract(BigInteger.ONE);
+                BigInteger r1 = r.subtract(BigInteger.ONE);
+                BigInteger phi = p1.multiply(q1).multiply(r1);
+
+                // generate new p and q until they work. typically
+                if (e.gcd(phi).equals(BigInteger.ONE) == false) {
+                    continue;
+                }
+
+                // private exponent d is the inverse of e mod phi
+                BigInteger d = e.modInverse(phi);
+
+                RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(n, e);
+                RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(n, d);
+                PublicKey publicKey = factory.generatePublic(publicSpec);
+                PrivateKey privateKey = factory.generatePrivate(privateSpec);
+                keyPair = new KeyPair(publicKey, privateKey);
+            }
+            // -----END SHAMELESSLY ADAPTED BLOCK-----
+
+            try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f))) {
+                oos.writeObject(keyPair);
+                oos.close();
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            }
+        }
+        return keyPair;
+    }
+
     public static String generatePEMCSR(KeyPair kp, String dn) throws GeneralSecurityException, IOException {
         return generatePEMCSR(kp, dn, new PKCS10Attributes());
     }
@@ -229,12 +337,49 @@ public abstract class ConfiguredTest {
     }
 
     public static void makeAgent(int uid) {
+        addChallenge(uid, CATSType.AGENT_CHALLENGE);
+        add100Points(uid);
+        insertRAContract(uid);
+    }
+
+    public static void addChallenge(int uid, CATSType ct) {
         try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, language='en_EN', version='1'")) {
             ps1.setInt(1, uid);
-            ps1.setInt(2, CATSType.AGENT_CHALLENGE.getId());
+            ps1.setInt(2, ct.getId());
             ps1.execute();
         }
+    }
+
+    public static void addChallengeInPast(int uid, CATSType ct) {
+        try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, pass_date=?, language='en_EN', version='1'")) {
+            ps1.setInt(1, uid);
+            ps1.setInt(2, ct.getId());
+            ps1.setTimestamp(3, new Timestamp(new Date(System.currentTimeMillis() - 24L * 60 * 60 * (CATS.TEST_MONTHS + 1) * 31 * 1000L).getTime()));
+            ps1.execute();
+        }
+    }
+
+    public static void add100Points(int uid) {
+        try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) {
+            ps2.setInt(1, uid);
+            ps2.setInt(2, User.getById(uid).getPreferredName().getId());
+            ps2.execute();
+        }
+    }
 
+    public static void insertRAContract(int uid) {
+        // insert signed RA Contract
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `user_contracts` SET `memid`=?, `token`=?, `document`=?::`contractType`,`agentname`=?")) {
+            ps.setInt(1, uid);
+            ps.setString(2, RandomToken.generateToken(32));
+            ps.setEnum(3, ContractType.RA_AGENT_CONTRACT);
+            ps.setString(4, User.getById(uid).getPreferredName().toString());
+            ps.execute();
+        }
+    }
+
+    public static void insertVerificationPoints(int uid) {
+        // insert Verification Points
         try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) {
             ps2.setInt(1, uid);
             ps2.setInt(2, User.getById(uid).getPreferredName().getId());
@@ -242,6 +387,15 @@ public abstract class ConfiguredTest {
         }
     }
 
+    public static void insertPassedTest(int uid) {
+        // insert passed test
+        try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, language='en_EN', version='1'")) {
+            ps1.setInt(1, uid);
+            ps1.setInt(2, CATSType.AGENT_CHALLENGE.getId());
+            ps1.execute();
+        }
+    }
+
     public MailReceiver getMailReceiver() {
         throw new Error("Feature requires Business or ManagedTest.");
     }
@@ -251,6 +405,12 @@ public abstract class ConfiguredTest {
             d.addPing(DomainPingType.EMAIL, "admin");
             TestMail testMail = getMailReceiver().receive("admin@" + d.getSuffix());
             testMail.verify();
+            // Enforce successful ping :-)
+            d.addPing(DomainPingType.HTTP, "a:b");
+            try (GigiPreparedStatement gps = new GigiPreparedStatement("INSERT INTO `domainPinglog` SET `configId`=(SELECT `id` FROM `pingconfig` WHERE `domainid`=? AND `type`='http'), state='success', needsAction=false")) {
+                gps.setInt(1, d.getId());
+                gps.execute();
+            }
             assertTrue(d.isVerified());
         } catch (GigiApiException e) {
             throw new Error(e);
@@ -279,4 +439,9 @@ public abstract class ConfiguredTest {
         c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION + 1);
         return sdf.format(new Date(c.getTimeInMillis()));
     }
+
+    public void signRAContract(User u) throws GigiApiException {
+        new Contract(u, ContractType.RA_AGENT_CONTRACT);
+        getMailReceiver().receive(u.getEmail());
+    }
 }