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.boulder; 015 016import static java.util.concurrent.TimeUnit.SECONDS; 017import static org.assertj.core.api.Assertions.assertThat; 018import static org.awaitility.Awaitility.await; 019 020import java.net.URI; 021import java.security.KeyPair; 022 023import org.junit.jupiter.api.Test; 024import org.shredzone.acme4j.AccountBuilder; 025import org.shredzone.acme4j.Authorization; 026import org.shredzone.acme4j.Order; 027import org.shredzone.acme4j.Session; 028import org.shredzone.acme4j.Status; 029import org.shredzone.acme4j.challenge.Http01Challenge; 030import org.shredzone.acme4j.exception.AcmeException; 031import org.shredzone.acme4j.exception.AcmeLazyLoadingException; 032import org.shredzone.acme4j.it.BammBammClient; 033import org.shredzone.acme4j.util.KeyPairUtils; 034 035/** 036 * Tests a complete certificate order with different challenges. 037 */ 038public class OrderHttpIT { 039 040 private static final String TEST_DOMAIN = "example.com"; 041 042 private final String bammbammUrl = System.getProperty("bammbammUrl", "http://localhost:14001"); 043 044 private final BammBammClient client = new BammBammClient(bammbammUrl); 045 046 /** 047 * Test if a certificate can be ordered via http-01 challenge. 048 */ 049 @Test 050 public void testHttpValidation() throws Exception { 051 var session = new Session(boulderURI()); 052 var keyPair = createKeyPair(); 053 054 var account = new AccountBuilder() 055 .agreeToTermsOfService() 056 .useKeyPair(keyPair) 057 .create(session); 058 059 var domainKeyPair = createKeyPair(); 060 061 var order = account.newOrder().domain(TEST_DOMAIN).create(); 062 063 for (var auth : order.getAuthorizations()) { 064 var challenge = auth.findChallenge(Http01Challenge.class).orElseThrow(); 065 066 client.httpAddToken(challenge.getToken(), challenge.getAuthorization()); 067 068 challenge.trigger(); 069 070 await() 071 .pollInterval(1, SECONDS) 072 .timeout(30, SECONDS) 073 .conditionEvaluationListener(cond -> updateAuth(auth)) 074 .untilAsserted(() -> assertThat(auth.getStatus()).isNotIn(Status.PENDING, Status.PROCESSING)); 075 076 assertThat(auth.getStatus()).isEqualTo(Status.VALID); 077 078 client.httpRemoveToken(challenge.getToken()); 079 } 080 081 order.execute(domainKeyPair); 082 083 await() 084 .pollInterval(1, SECONDS) 085 .timeout(30, SECONDS) 086 .conditionEvaluationListener(cond -> updateOrder(order)) 087 .untilAsserted(() -> assertThat(order.getStatus()).isNotIn(Status.PENDING, Status.PROCESSING)); 088 089 var cert = order.getCertificate().getCertificate(); 090 assertThat(cert.getNotAfter()).isNotNull(); 091 assertThat(cert.getNotBefore()).isNotNull(); 092 assertThat(cert.getSubjectX500Principal().getName()).contains("CN=" + TEST_DOMAIN); 093 } 094 095 /** 096 * @return The {@link URI} of the Boulder server to test against. 097 */ 098 protected URI boulderURI() { 099 return URI.create("http://localhost:4001/directory"); 100 } 101 102 /** 103 * Creates a fresh key pair. 104 * 105 * @return Created new {@link KeyPair} 106 */ 107 protected KeyPair createKeyPair() { 108 return KeyPairUtils.createKeyPair(2048); 109 } 110 111 /** 112 * Safely updates the authorization, catching checked exceptions. 113 * 114 * @param auth 115 * {@link Authorization} to update 116 */ 117 private void updateAuth(Authorization auth) { 118 try { 119 auth.update(); 120 } catch (AcmeException ex) { 121 throw new AcmeLazyLoadingException(auth, ex); 122 } 123 } 124 125 /** 126 * Safely updates the order, catching checked exceptions. 127 * 128 * @param order 129 * {@link Order} to update 130 */ 131 private void updateOrder(Order order) { 132 try { 133 order.update(); 134 } catch (AcmeException ex) { 135 throw new AcmeLazyLoadingException(order, ex); 136 } 137 } 138 139}