sql.url=jdbc:mysql://localhost:3306/cacert
sql.user=cacert
sql.password=<password>
+
+
+domain.dnsmanage=http://you-installation-of-the/index.php
+domain.dnstest=the.dns.zone
+domain.dnsns=the.authorativ.ns.for.domain.dnstest
--- /dev/null
+-you need 4 domains resolving to the ci server (or localhost)
+preferably
+static.DOMAIN, secure.DOMAIN, www.DOMAIN and api.DOMAIN.
+enter them in the jenkins job to write them to "keys/config" and "config/test.properties"
+
+-you need credentials to an acessabible mysql database.
+make jenkins write them to "config/test.properties"
+
+-you need a dynamically managable dns zone.
+Write the zone name to "domain.dnstest" in "test.properties"
+and a manage script (see dyn-txt.php). Put the url with password in "domain.dnsmanage"
+
+Setup with bind9:
+dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST example.org.
--- /dev/null
+<?php
+header("Content-type: text/plain");
+
+if($_GET['token'] != "<here a secure password>"){
+ die ();
+}
+$t1 = $_GET['t1'];
+$t2 = $_GET['t2'];
+if(!preg_match("/[a-zA-Z0-9]+/", $t1) || !preg_match("/[a-zA-Z0-9]+/", $t2)){
+ die("Error");
+}
+
+$call = <<<EOF
+server localhost
+update delete cacert-{$t1}.<your fakezone here> TXT
+update add cacert-{$t1}.<your fakezone here> 60 TXT {$t2}
+send
+quit
+
+EOF;
+echo $call;
+
+$nsupdate = popen("/usr/bin/nsupdate -k <here your dnssec key>.key", 'w');
+fwrite($nsupdate, $call);
+$retval = pclose($nsupdate); // nsupdate doesn't return anything useful when called this way
+
+?>
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
-
import org.cacert.gigi.database.DatabaseConnection;
public class Domain {
}
return false;
}
+
+ public String[][] getPings() throws GigiApiException {
+ try {
+ PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT state, type, info, result FROM domainPinglog INNER JOIN pingconfig ON pingconfig.id=domainPinglog.configid WHERE pingconfig.domainid=? ORDER BY `when` DESC;");
+ ps.setInt(1, id);
+ ResultSet rs = ps.executeQuery();
+ rs.last();
+ String[][] contents = new String[rs.getRow()][];
+ rs.beforeFirst();
+ for (int i = 0; i < contents.length && rs.next(); i++) {
+ contents[i] = new String[] {
+ rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4)
+ };
+ }
+ return contents;
+ } catch (SQLException e) {
+ throw new GigiApiException(e);
+ }
+
+ }
}
putPage(RegisterPage.PATH, new RegisterPage(), "Join CAcert.org");
putPage(CertificateAdd.PATH, new CertificateAdd(), "Certificates");
putPage(MailOverview.DEFAULT_PATH, new MailOverview("My email addresses"), "Certificates");
- putPage(DomainOverview.PATH, new DomainOverview("Domains"), "Certificates");
+ putPage(DomainOverview.PATH + "*", new DomainOverview("Domains"), "Certificates");
putPage(MyPoints.PATH, new MyPoints("My Points"), "CAcert Web of Trust");
putPage("/wot/rules", new StaticPage("CAcert Web of Trust Rules", AssurePage.class.getResourceAsStream("Rules.templ")), "CAcert Web of Trust");
baseTemplate = new Template(Gigi.class.getResource("Gigi.templ"));
<td>
Please insert the following DNS TXT entry into the SOA-file of your domain:<br/>
<pre>
- cacert-<?=$tokenName?> IN TXT <?=$tokenValue?>
+ cacert-<?=$tokenName?> IN TXT <?=$tokenValue?>
</pre>
</td>
</tr>
--- /dev/null
+<h2><?=_Ping log for?> '<?=$domainname?>'</h2>
+<table class="wrapper dataTable">
+<tr><th><?=_Type?></th>
+<th><?=_State?></th>
+<th><?=_Config?></th>
+<th><?=_Result?></th></tr>
+<? foreach($pings) { ?>
+<tr>
+<td><?=$type?></td>
+<td><?=$state?></td>
+<td><?=$config?></td>
+<td><?=$result?></td>
+</tr>
+<?}?>
+</table>
\ No newline at end of file
import org.cacert.gigi.output.template.IterableDataset;
import org.cacert.gigi.output.template.Template;
import org.cacert.gigi.pages.Page;
+import org.cacert.gigi.util.ServerConstants;
public class DomainManagementForm extends Form {
}
Domain domain = doms[point];
vars.put("id", domain.getId());
+ vars.put("domainhref", "https://" + ServerConstants.getWwwHostNamePort() + DomainOverview.PATH + domain.getId());
vars.put("domain", domain.getSuffix());
vars.put("status", l.getTranslation(domain.isVerified() ? "verified" : "not verified"));
point++;
vars.put("domains", dts);
t.output(out, l, vars);
}
-
}
<tr>
<td><input type="checkbox" name="delid[]" value="<?=$id?>" /></td>
<td><?=$status?></td>
- <td><?=$domain?></td>
+ <td><a href='<?=$domainhref?>'><?=$domain?></a></td>
</tr>
<? } ?>
<tr>
import java.io.IOException;
import java.util.HashMap;
+import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.cacert.gigi.Domain;
+import org.cacert.gigi.GigiApiException;
import org.cacert.gigi.User;
+import org.cacert.gigi.localisation.Language;
import org.cacert.gigi.output.Form;
+import org.cacert.gigi.output.template.IterableDataset;
+import org.cacert.gigi.output.template.Template;
import org.cacert.gigi.pages.Page;
public class DomainOverview extends Page {
- public static final String PATH = "/account/domains";
+ public static final String PATH = "/account/domains/";
+
+ private Template domainDetails = new Template(DomainOverview.class.getResource("DomainDetails.templ"));
public DomainOverview(String title) {
super(title);
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
User u = getUser(req);
+ String pi = req.getPathInfo();
+ if (pi.length() - PATH.length() > 0) {
+ int i = Integer.parseInt(pi.substring(PATH.length()));
+ Domain d = Domain.getById(i);
+ if (u.getId() != d.getOwner().getId()) {
+ System.out.println(u.getId());
+ System.out.println(d.getOwner().getId());
+ return;
+ }
+ try {
+ final String[][] pings = d.getPings();
+ HashMap<String, Object> vars = new HashMap<>();
+ vars.put("domainname", d.getSuffix());
+ vars.put("pings", new IterableDataset() {
+
+ int counter = 0;
+
+ @Override
+ public boolean next(Language l, Map<String, Object> vars) {
+ if (counter >= pings.length) {
+ return false;
+ }
+ vars.put("state", pings[counter][0]);
+ vars.put("type", pings[counter][1]);
+ vars.put("config", pings[counter][2]);
+ String ping3 = pings[counter][3];
+ if (ping3 == null) {
+ vars.put("result", "");
+ } else {
+ vars.put("result", ping3);
+ }
+ counter++;
+ return true;
+ }
+ });
+ domainDetails.output(resp.getWriter(), getLanguage(req), vars);
+ return;
+ } catch (GigiApiException e) {
+ e.format(resp.getWriter(), getLanguage(req));
+ }
+
+ }
DomainManagementForm domMan = new DomainManagementForm(req, u);
DomainAddForm domAdd = new DomainAddForm(req, u);
HashMap<String, Object> vars = new HashMap<>();
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.util.Arrays;
import java.util.LinkedList;
import org.cacert.gigi.Domain;
nameservers:
for (String NS : nameservers) {
String[] call = new String[] {
- "dig", "@" + NS, "+short", "TXT", "cacert-" + tokenParts[0] + "." + domain
+ "dig", "@" + NS, "+short", "TXT", "cacert-" + tokenParts[0] + "." + domain.getSuffix()
};
+ System.out.println(Arrays.toString(call));
p = Runtime.getRuntime().exec(call);
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String token = null;
--- /dev/null
+package org.cacert.gigi.ping;
+
+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.net.URLEncoder;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.cacert.gigi.database.DatabaseConnection;
+import org.cacert.gigi.pages.account.DomainOverview;
+import org.cacert.gigi.testUtils.IOUtils;
+import org.cacert.gigi.testUtils.ManagedTest;
+import org.cacert.gigi.testUtils.TestEmailReciever.TestMail;
+import org.cacert.gigi.util.RandomToken;
+import org.junit.Test;
+
+public class TestDNS extends ManagedTest {
+
+ @Test
+ public void testDNSSanity() throws IOException {
+
+ String token = RandomToken.generateToken(16);
+ String value = RandomToken.generateToken(16);
+
+ Process p = updateDNS(token, value);
+ String reRead = new String(IOUtils.readURL(p.getInputStream()));
+ reRead = reRead.trim();
+ reRead = reRead.substring(1, reRead.length() - 1);
+ assertEquals(value, reRead);
+
+ }
+
+ @Test
+ public void testEmailAndDNS() throws IOException, InterruptedException, SQLException {
+ String email = createUniqueName() + "@example.org";
+ int uid = createVerifiedUser("a", "b", email, TEST_PASSWORD);
+ String cookie = login(email, TEST_PASSWORD);
+
+ String test = getTestProps().getProperty("domain.dnstest");
+ URL u = new URL("https://" + getServerName() + DomainOverview.PATH);
+ URLConnection openConnection = u.openConnection();
+ openConnection.setRequestProperty("Cookie", cookie);
+ String content1 = IOUtils.readURL(openConnection);
+ String csrf = getCSRF(1, content1);
+
+ Pattern p = Pattern.compile("cacert-([A-Za-z0-9]+) IN TXT ([A-Za-z0-9]+)");
+ Matcher m = p.matcher(content1);
+ m.find();
+ updateDNS(m.group(1), m.group(2));
+
+ String content = "newdomain=" + URLEncoder.encode(test, "UTF-8") + //
+ "&emailType=y&email=2&DNSType=y" + //
+ "&ssl-type-0=direct&ssl-port-0=" + //
+ "&ssl-type-1=direct&ssl-port-1=" + //
+ "&ssl-type-2=direct&ssl-port-2=" + //
+ "&ssl-type-3=direct&ssl-port-3=" + //
+ "&adddomain&csrf=" + csrf;
+ openConnection = u.openConnection();
+ openConnection.setRequestProperty("Cookie", cookie);
+ openConnection.setDoOutput(true);
+ openConnection.getOutputStream().write(content.getBytes());
+ openConnection.getHeaderField("Location");
+
+ String newcontent = IOUtils.readURL(cookie(u.openConnection(), cookie));
+ Pattern dlink = Pattern.compile(DomainOverview.PATH + "([0-9]+)'>");
+ Matcher m1 = dlink.matcher(newcontent);
+ m1.find();
+ URL u2 = new URL(u.toString() + m1.group(1));
+
+ TestMail mail = getMailReciever().recieve();
+ String link = mail.extractLink();
+ new URL(link).openConnection().getHeaderField("");
+
+ PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT COUNT(*) FROM domainPinglog");
+ while (true) {
+ ResultSet rs = ps.executeQuery();
+ rs.next();
+ if (rs.getInt(1) >= 2) {
+ break;
+ }
+ Thread.sleep(200);
+ }
+
+ newcontent = IOUtils.readURL(cookie(u2.openConnection(), cookie));
+ Pattern pat = Pattern.compile("<td>dns</td>\\s*<td>success</td>");
+ assertTrue(newcontent, pat.matcher(newcontent).find());
+ pat = Pattern.compile("<td>email</td>\\s*<td>success</td>");
+ assertTrue(newcontent, pat.matcher(newcontent).find());
+ }
+
+ private Process updateDNS(String token, String value) throws IOException, MalformedURLException {
+ String test = getTestProps().getProperty("domain.dnstest");
+ String targetDomain = "cacert-" + token + "." + test;
+ String manage = getTestProps().getProperty("domain.dnsmanage");
+ String url = manage + "t1=" + token + "&t2=" + value;
+ assertEquals(200, ((HttpURLConnection) new URL(url).openConnection()).getResponseCode());
+
+ Process p = Runtime.getRuntime().exec(new String[] {
+ "dig", "@" + getTestProps().getProperty("domain.testns"), "+short", "TXT", targetDomain
+ });
+ return p;
+ }
+
+}
}
static Properties testProps = new Properties();
+
+ public static Properties getTestProps() {
+ return testProps;
+ }
+
static {
InitTruststore.run();
HttpURLConnection.setFollowRedirects(false);
public static String getCSRF(URLConnection u, int formIndex) throws IOException {
String content = IOUtils.readURL(u);
+ return getCSRF(formIndex, content);
+ }
+
+ public static String getCSRF(int formIndex, String content) throws Error {
Pattern p = Pattern.compile("<input type='hidden' name='csrf' value='([^']+)'>");
Matcher m = p.matcher(content);
for (int i = 0; i < formIndex + 1; i++) {
return adrr;
}
+ public static URLConnection cookie(URLConnection openConnection, String cookie) {
+ openConnection.setRequestProperty("Cookie", cookie);
+ return openConnection;
+ }
+
}