001/* 002 * acme4j - Java ACME client 003 * 004 * Copyright (C) 2017 Richard "Shred" Körber 005 * http://acme4j.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.acme4j.it; 015 016import java.io.IOException; 017import java.util.Collections; 018import java.util.Objects; 019 020import org.apache.http.HttpResponse; 021import org.apache.http.HttpStatus; 022import org.apache.http.client.ClientProtocolException; 023import org.apache.http.client.HttpClient; 024import org.apache.http.client.methods.HttpPost; 025import org.apache.http.entity.ContentType; 026import org.apache.http.entity.StringEntity; 027import org.apache.http.impl.client.HttpClients; 028import org.apache.http.util.EntityUtils; 029import org.shredzone.acme4j.toolbox.JSONBuilder; 030 031/** 032 * The BammBamm client connects to the pebble-challtestsrv. 033 */ 034public class BammBammClient { 035 private static final HttpClient CLIENT = HttpClients.createDefault(); 036 037 private final String baseUrl; 038 039 /** 040 * Creates a new BammBamm client. 041 * 042 * @param baseUrl 043 * Base URL of the pebble-challtestsrv server to connect to. 044 */ 045 public BammBammClient(String baseUrl) { 046 this.baseUrl = Objects.requireNonNull(baseUrl) + '/'; 047 } 048 049 /** 050 * Adds a HTTP token. 051 * 052 * @param token 053 * Token to add 054 * @param challenge 055 * Challenge to respond with 056 */ 057 public void httpAddToken(String token, String challenge) throws IOException { 058 JSONBuilder jb = new JSONBuilder(); 059 jb.put("token", token); 060 jb.put("content", challenge); 061 sendRequest("add-http01", jb.toString()); 062 } 063 064 /** 065 * Removes a HTTP token. 066 * 067 * @param token 068 * Token to remove 069 */ 070 public void httpRemoveToken(String token) throws IOException { 071 JSONBuilder jb = new JSONBuilder(); 072 jb.put("token", token); 073 sendRequest("del-http01", jb.toString()); 074 } 075 076 /** 077 * Adds an A Record to the DNS. Only one A Record is supported per domain. If another 078 * A Record is set, it will replace the existing one. 079 * 080 * @param domain 081 * Domain of the A Record 082 * @param ip 083 * IP address or domain name. If a domain name is used, it will be resolved 084 * and the IP will be used. 085 */ 086 public void dnsAddARecord(String domain, String ip) throws IOException { 087 JSONBuilder jb = new JSONBuilder(); 088 jb.put("host", domain); 089 jb.array("addresses", Collections.singletonList(ip)); 090 sendRequest("add-a", jb.toString()); 091 } 092 093 /** 094 * Removes an A Record from the DNS. 095 * 096 * @param domain 097 * Domain to remove the A Record from 098 */ 099 public void dnsRemoveARecord(String domain) throws IOException { 100 JSONBuilder jb = new JSONBuilder(); 101 jb.put("host", domain); 102 sendRequest("clear-a", jb.toString()); 103 } 104 105 /** 106 * Adds a TXT Record to the DNS. Only one TXT Record is supported per domain. If 107 * another TXT Record is set, it will replace the existing one. 108 * 109 * @param domain 110 * Domain name to add the TXT Record to 111 * @param txt 112 * TXT record to add 113 */ 114 public void dnsAddTxtRecord(String domain, String txt) throws IOException { 115 JSONBuilder jb = new JSONBuilder(); 116 jb.put("host", domain); 117 jb.put("value", txt); 118 sendRequest("set-txt", jb.toString()); 119 } 120 121 /** 122 * Removes a TXT Record from the DNS. 123 * 124 * @param domain 125 * Domain to remove the TXT Record from 126 */ 127 public void dnsRemoveTxtRecord(String domain) throws IOException { 128 JSONBuilder jb = new JSONBuilder(); 129 jb.put("host", domain + '.'); 130 sendRequest("clear-txt", jb.toString()); 131 } 132 133 /** 134 * Adds a CNAME Record to the DNS. Only one CNAME Record is supported per domain. If 135 * another CNAME Record is set, it will replace the existing one. 136 * 137 * @param domain 138 * Domain to add the CNAME Record to 139 * @param cname 140 * CNAME Record to add 141 * @since 2.9 142 */ 143 public void dnsAddCnameRecord(String domain, String cname) throws IOException { 144 JSONBuilder jb = new JSONBuilder(); 145 jb.put("host", domain); 146 jb.put("target", cname); 147 sendRequest("set-cname", jb.toString()); 148 } 149 150 /** 151 * Removes a CNAME Record from the DNS. 152 * 153 * @param domain 154 * Domain to remove the CNAME Record from 155 * @since 2.9 156 */ 157 public void dnsRemoveCnameRecord(String domain) throws IOException { 158 JSONBuilder jb = new JSONBuilder(); 159 jb.put("host", domain); 160 sendRequest("clear-cname", jb.toString()); 161 } 162 163 /** 164 * Simulates a SERVFAIL for the given domain. 165 * 166 * @param domain 167 * Domain that will give a SERVFAIL response 168 * @since 2.9 169 */ 170 public void dnsAddServFailRecord(String domain) throws IOException { 171 JSONBuilder jb = new JSONBuilder(); 172 jb.put("host", domain); 173 sendRequest("set-servfail", jb.toString()); 174 } 175 176 /** 177 * Removes a SERVFAIL Record from the DNS. 178 * 179 * @param domain 180 * Domain to remove the SEVFAIL Record from 181 * @since 2.9 182 */ 183 public void dnsRemoveServFailRecord(String domain) throws IOException { 184 JSONBuilder jb = new JSONBuilder(); 185 jb.put("host", domain); 186 sendRequest("clear-servfail", jb.toString()); 187 } 188 189 /** 190 * Adds a certificate for TLS-ALPN tests. 191 * 192 * @param domain 193 * Certificate domain to be added 194 * @param keyauth 195 * Key authorization to be used for validation 196 */ 197 public void tlsAlpnAddCertificate(String domain, String keyauth) throws IOException { 198 JSONBuilder jb = new JSONBuilder(); 199 jb.put("host", domain); 200 jb.put("content", keyauth); 201 sendRequest("add-tlsalpn01", jb.toString()); 202 } 203 204 /** 205 * Removes a certificate. 206 * 207 * @param domain 208 * Certificate domain to be removed 209 */ 210 public void tlsAlpnRemoveCertificate(String domain) throws IOException { 211 JSONBuilder jb = new JSONBuilder(); 212 jb.put("host", domain); 213 sendRequest("del-tlsalpn01", jb.toString()); 214 } 215 216 /** 217 * Sends a request to the pebble-challtestsrv. 218 * 219 * @param call 220 * Endpoint to be called 221 * @param body 222 * JSON body 223 */ 224 private void sendRequest(String call, String body) throws IOException { 225 try { 226 HttpPost httppost = new HttpPost(baseUrl + call); 227 httppost.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON)); 228 229 HttpResponse response = CLIENT.execute(httppost); 230 231 EntityUtils.consume(response.getEntity()); 232 233 if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 234 throw new IOException(response.getStatusLine().getReasonPhrase()); 235 } 236 } catch (ClientProtocolException ex) { 237 throw new IOException(ex); 238 } 239 } 240 241}