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.pebble; 015 016import static java.util.concurrent.TimeUnit.SECONDS; 017import static java.util.stream.Collectors.toList; 018import static org.assertj.core.api.Assertions.assertThat; 019import static org.awaitility.Awaitility.await; 020 021import java.time.Duration; 022import java.time.Instant; 023import java.time.temporal.ChronoUnit; 024 025import org.bouncycastle.asn1.x509.GeneralName; 026import org.junit.jupiter.api.Test; 027import org.shredzone.acme4j.AccountBuilder; 028import org.shredzone.acme4j.Session; 029import org.shredzone.acme4j.Status; 030import org.shredzone.acme4j.challenge.Dns01Challenge; 031 032/** 033 * Tests a complete wildcard certificate order. Wildcard certificates currently only 034 * support dns-01 challenge. 035 */ 036public class OrderWildcardIT extends PebbleITBase { 037 038 private static final String TEST_DOMAIN = "example.com"; 039 private static final String TEST_WILDCARD_DOMAIN = "*.example.com"; 040 041 /** 042 * Test if a wildcard certificate can be ordered via dns-01 challenge. 043 */ 044 @Test 045 public void testDnsValidation() throws Exception { 046 var client = getBammBammClient(); 047 var keyPair = createKeyPair(); 048 var session = new Session(pebbleURI()); 049 050 var account = new AccountBuilder() 051 .agreeToTermsOfService() 052 .useKeyPair(keyPair) 053 .create(session); 054 055 var domainKeyPair = createKeyPair(); 056 057 var notBefore = Instant.now().truncatedTo(ChronoUnit.MILLIS); 058 var notAfter = notBefore.plus(Duration.ofDays(20L)); 059 060 var order = account.newOrder() 061 .domain(TEST_WILDCARD_DOMAIN) 062 .domain(TEST_DOMAIN) 063 .notBefore(notBefore) 064 .notAfter(notAfter) 065 .create(); 066 assertThat(order.getNotBefore().orElseThrow()).isEqualTo(notBefore); 067 assertThat(order.getNotAfter().orElseThrow()).isEqualTo(notAfter); 068 assertThat(order.getStatus()).isEqualTo(Status.PENDING); 069 070 for (var auth : order.getAuthorizations()) { 071 assertThat(auth.getIdentifier().getDomain()).isEqualTo(TEST_DOMAIN); 072 assertThat(auth.getStatus()).isEqualTo(Status.PENDING); 073 074 if (auth.getStatus() == Status.VALID) { 075 continue; 076 } 077 078 var challenge = auth.findChallenge(Dns01Challenge.class).orElseThrow(); 079 080 var challengeDomainName = Dns01Challenge.toRRName(TEST_DOMAIN); 081 082 client.dnsAddTxtRecord(challengeDomainName, challenge.getDigest()); 083 cleanup(() -> client.dnsRemoveTxtRecord(challengeDomainName)); 084 085 challenge.trigger(); 086 087 await() 088 .pollInterval(1, SECONDS) 089 .timeout(30, SECONDS) 090 .conditionEvaluationListener(cond -> updateAuth(auth)) 091 .untilAsserted(() -> assertThat( 092 auth.getStatus()).isNotIn(Status.PENDING, Status.PROCESSING)); 093 094 assertThat(auth.getStatus()).isEqualTo(Status.VALID); 095 } 096 097 order.execute(domainKeyPair); 098 099 await() 100 .pollInterval(1, SECONDS) 101 .timeout(30, SECONDS) 102 .conditionEvaluationListener(cond -> updateOrder(order)) 103 .untilAsserted(() -> assertThat( 104 order.getStatus()).isNotIn(Status.PENDING, Status.PROCESSING)); 105 106 107 var cert = order.getCertificate().getCertificate(); 108 assertThat(cert).isNotNull(); 109 assertThat(cert.getNotAfter()).isNotEqualTo(notBefore); 110 assertThat(cert.getNotBefore()).isNotEqualTo(notAfter); 111 assertThat(cert.getSubjectX500Principal().getName()).satisfiesAnyOf( 112 name -> assertThat(name).contains("CN=" + TEST_DOMAIN), 113 name -> assertThat(name).contains("CN=" + TEST_WILDCARD_DOMAIN) 114 ); 115 116 var san = cert.getSubjectAlternativeNames().stream() 117 .filter(it -> ((Number) it.get(0)).intValue() == GeneralName.dNSName) 118 .map(it -> (String) it.get(1)) 119 .collect(toList()); 120 assertThat(san).contains(TEST_DOMAIN, TEST_WILDCARD_DOMAIN); 121 } 122 123}