mirror of https://github.com/shred/acme4j
				
				
				
			Merge Account and Registration, simplify API
							parent
							
								
									d48f7ee0f8
								
							
						
					
					
						commit
						1b83115892
					
				|  | @ -1,52 +0,0 @@ | |||
| /* | ||||
|  * acme4j - Java ACME client | ||||
|  * | ||||
|  * Copyright (C) 2015 Richard "Shred" Körber | ||||
|  *   http://acme4j.shredzone.org
 | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
|  */ | ||||
| package org.shredzone.acme4j; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.security.KeyPair; | ||||
| 
 | ||||
| /** | ||||
|  * Represents an account at the ACME server. | ||||
|  * <p> | ||||
|  * An account is identified by its {@link KeyPair}. | ||||
|  * | ||||
|  * @author Richard "Shred" Körber | ||||
|  */ | ||||
| public class Account implements Serializable { | ||||
|     private static final long serialVersionUID = 1064105289226118702L; | ||||
| 
 | ||||
|     private final KeyPair keyPair; | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a new {@link Account} instance. | ||||
|      * | ||||
|      * @param keyPair | ||||
|      *            {@link KeyPair} that identifies the account. | ||||
|      */ | ||||
|     public Account(KeyPair keyPair) { | ||||
|         if (keyPair == null) { | ||||
|             throw new NullPointerException("keypair must not be null"); | ||||
|         } | ||||
| 
 | ||||
|         this.keyPair = keyPair; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The {@link KeyPair} that belongs to this account. | ||||
|      */ | ||||
|     public KeyPair getKeyPair() { | ||||
|         return keyPair; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -32,62 +32,55 @@ public interface AcmeClient { | |||
|     /** | ||||
|      * Registers a new account. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to register | ||||
|      * @param registration | ||||
|      *            {@link Registration} containing registration data | ||||
|      */ | ||||
|     void newRegistration(Account account, Registration registration) throws AcmeException; | ||||
|     void newRegistration(Registration registration) throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Modifies an existing account. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} that is registered | ||||
|      * @param registration | ||||
|      *            {@link Registration} containing updated registration data and the | ||||
|      *            account location URI | ||||
|      */ | ||||
|     void modifyRegistration(Account account, Registration registration) throws AcmeException; | ||||
|     void modifyRegistration(Registration registration) throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Modifies the account so it is identified with the new {@link KeyPair}. | ||||
|      * <p> | ||||
|      * Starting from the next call, {@link Account} must use the new {@link KeyPair} for | ||||
|      * identification. | ||||
|      * Starting from the next call, {@link Registration} must use the new {@link KeyPair} | ||||
|      * for identification. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to change the identification key pair of | ||||
|      * @param registration | ||||
|      *            {@link Registration} containing the account location URI. Other | ||||
|      *            properties are ignored. | ||||
|      * @param newKeyPair | ||||
|      *            new {@link KeyPair} to be used for identifying this account | ||||
|      */ | ||||
|     void changeRegistrationKey(Account account, Registration registration, KeyPair newKeyPair) | ||||
|     void changeRegistrationKey(Registration registration, KeyPair newKeyPair) | ||||
|                 throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Recovers an account by contact-based recovery. The server starts an out-of-band | ||||
|      * recovery process by using one of the contact addresses given at account creation. | ||||
|      * | ||||
|      * @param account | ||||
|      *            <em>New</em> {@link Account} to associate the recovered account with | ||||
|      * @param registration | ||||
|      *            {@link Registration}, with the account location URI set | ||||
|      *            {@link Registration}, with the new key pair and the account location URI | ||||
|      *            set | ||||
|      * @throws AcmeException | ||||
|      */ | ||||
|     void recoverRegistration(Account account, Registration registration) throws AcmeException; | ||||
|     void recoverRegistration(Registration registration) throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a new {@link Authorization} for a domain. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} the authorization is related to | ||||
|      * @param registration | ||||
|      *            {@link Registration} the authorization is related to | ||||
|      * @param auth | ||||
|      *            {@link Authorization} containing the domain name | ||||
|      */ | ||||
|     void newAuthorization(Account account, Authorization auth) throws AcmeException; | ||||
|     void newAuthorization(Registration registration, Authorization auth) throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Updates an {@link Authorization} to the current server state. | ||||
|  | @ -101,12 +94,12 @@ public interface AcmeClient { | |||
|      * Triggers a {@link Challenge}. The ACME server is requested to validate the | ||||
|      * response. Note that the validation is performed asynchronously. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to be used for conversation | ||||
|      * @param registration | ||||
|      *            {@link Registration} to be used for conversation | ||||
|      * @param challenge | ||||
|      *            {@link Challenge} to trigger | ||||
|      */ | ||||
|     void triggerChallenge(Account account, Challenge challenge) throws AcmeException; | ||||
|     void triggerChallenge(Registration registration, Challenge challenge) throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Updates the {@link Challenge} instance. It contains the current state. | ||||
|  | @ -130,13 +123,13 @@ public interface AcmeClient { | |||
|     /** | ||||
|      * Requests a certificate. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to be used for conversation | ||||
|      * @param registration | ||||
|      *            {@link Registration} to be used for conversation | ||||
|      * @param csr | ||||
|      *            PKCS#10 Certificate Signing Request to be sent to the server | ||||
|      * @return {@link URI} the certificate can be downloaded from | ||||
|      */ | ||||
|     URI requestCertificate(Account account, byte[] csr) throws AcmeException; | ||||
|     URI requestCertificate(Registration registration, byte[] csr) throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Downloads a certificate. | ||||
|  | @ -150,11 +143,12 @@ public interface AcmeClient { | |||
|     /** | ||||
|      * Revokes a certificate. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to be used for conversation | ||||
|      * @param registration | ||||
|      *            {@link Registration} to be used for conversation | ||||
|      * @param certificate | ||||
|      *            Certificate to revoke | ||||
|      */ | ||||
|     void revokeCertificate(Account account, X509Certificate certificate) throws AcmeException; | ||||
|     void revokeCertificate(Registration registration, X509Certificate certificate) | ||||
|                 throws AcmeException; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ package org.shredzone.acme4j; | |||
| import java.io.Serializable; | ||||
| import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| import java.security.KeyPair; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
|  | @ -27,24 +28,47 @@ import java.util.List; | |||
| public class Registration implements Serializable { | ||||
|     private static final long serialVersionUID = -8177333806740391140L; | ||||
| 
 | ||||
|     private final KeyPair keyPair; | ||||
|     private List<URI> contacts = new ArrayList<>(); | ||||
|     private URI agreement; | ||||
|     private URI location; | ||||
| 
 | ||||
|     /** | ||||
|      * Create an empty {@link Registration}. | ||||
|      * Creates a {@link Registration} with no location URI set. This is only useful for | ||||
|      * new registrations. | ||||
|      * | ||||
|      * @param keyPair | ||||
|      *            Account key pair | ||||
|      */ | ||||
|     public Registration() { | ||||
|         // default constructor
 | ||||
|     public Registration(KeyPair keyPair) { | ||||
|         if (keyPair == null) { | ||||
|             throw new NullPointerException("keypair must not be null"); | ||||
|         } | ||||
| 
 | ||||
|         this.keyPair = keyPair; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create a {@link Registration} for the given location URI. | ||||
|      * Creates a {@link Registration} with a location URI set. This is useful for | ||||
|      * modifications to the registration. | ||||
|      * | ||||
|      * @param keyPair | ||||
|      *            Account key pair | ||||
|      * @param location | ||||
|      *            Registration location URI | ||||
|      */ | ||||
|     public Registration(URI location) { | ||||
|     public Registration(KeyPair keyPair, URI location) { | ||||
|         this(keyPair); | ||||
|         this.location = location; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The {@link KeyPair} that belongs to this account. | ||||
|      */ | ||||
|     public KeyPair getKeyPair() { | ||||
|         return keyPair; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the URI of the agreement document the user is required to accept. | ||||
|      */ | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
| package org.shredzone.acme4j.challenge; | ||||
| 
 | ||||
| import org.jose4j.base64url.Base64Url; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
| 
 | ||||
| /** | ||||
|  | @ -32,17 +32,17 @@ public class GenericTokenChallenge extends GenericChallenge { | |||
|     private String authorization; | ||||
| 
 | ||||
|     /** | ||||
|      * Authorizes the {@link Challenge} by signing it with an {@link Account}. | ||||
|      * Authorizes the {@link Challenge} by signing it with a {@link Registration}. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to sign the challenge with | ||||
|      * @param registration | ||||
|      *            {@link Registration} to sign the challenge with | ||||
|      */ | ||||
|     public void authorize(Account account) { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|     public void authorize(Registration registration) { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
| 
 | ||||
|         authorization = computeAuthorization(account); | ||||
|         authorization = computeAuthorization(registration); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -58,7 +58,7 @@ public class GenericTokenChallenge extends GenericChallenge { | |||
|      * Asserts that the challenge was authorized. | ||||
|      * | ||||
|      * @throws IllegalStateException | ||||
|      *             if {@link #authorize(Account)} was not invoked. | ||||
|      *             if {@link #authorize(Registration)} was not invoked. | ||||
|      */ | ||||
|     protected void assertIsAuthorized() { | ||||
|         if (authorization == null) { | ||||
|  | @ -74,7 +74,7 @@ public class GenericTokenChallenge extends GenericChallenge { | |||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Gets the authorization after {@link #authorize(Account)} was invoked. | ||||
|      * Gets the authorization after {@link #authorize(Registration)} was invoked. | ||||
|      */ | ||||
|     protected String getAuthorization() { | ||||
|         assertIsAuthorized(); | ||||
|  | @ -87,14 +87,14 @@ public class GenericTokenChallenge extends GenericChallenge { | |||
|      * The default is {@code token + '.' + base64url(jwkThumbprint)}. Subclasses may | ||||
|      * override this method if a different algorithm is used. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} to authorize with | ||||
|      * @param registration | ||||
|      *            {@link Registration} to authorize with | ||||
|      * @return Authorization string | ||||
|      */ | ||||
|     protected String computeAuthorization(Account account) { | ||||
|     protected String computeAuthorization(Registration registration) { | ||||
|         return getToken() | ||||
|             + '.' | ||||
|             + Base64Url.encode(jwkThumbprint(account.getKeyPair().getPublic())); | ||||
|             + Base64Url.encode(jwkThumbprint(registration.getKeyPair().getPublic())); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ import java.util.Map; | |||
| import org.jose4j.base64url.Base64Url; | ||||
| import org.jose4j.json.JsonUtil; | ||||
| import org.jose4j.lang.JoseException; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
| import org.shredzone.acme4j.util.ValidationBuilder; | ||||
| 
 | ||||
|  | @ -59,20 +59,20 @@ public class ProofOfPossessionChallenge extends GenericChallenge { | |||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Authorizes the challenge by signing it with the {@link Account} of the current | ||||
|      * Authorizes the challenge by signing it with the {@link Registration} of the current | ||||
|      * domain owner. | ||||
|      * | ||||
|      * @param ownerAccount | ||||
|      *            {@link Account} of the certificate holder | ||||
|      * @param ownerRegistration | ||||
|      *            {@link Registration} of the certificate holder | ||||
|      * @param domainKeypair | ||||
|      *            {@link KeyPair} matching one of the requested certificates | ||||
|      * @param domains | ||||
|      *            Domains to validate | ||||
|      */ | ||||
|     public void authorize(Account ownerAccount, KeyPair domainKeypair, String... domains) { | ||||
|     public void authorize(Registration ownerRegistration, KeyPair domainKeypair, String... domains) { | ||||
|         importValidation(new ValidationBuilder() | ||||
|                 .domains(domains) | ||||
|                 .sign(ownerAccount, domainKeypair)); | ||||
|                 .sign(ownerRegistration, domainKeypair)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ import java.io.UnsupportedEncodingException; | |||
| import java.security.MessageDigest; | ||||
| import java.security.NoSuchAlgorithmException; | ||||
| 
 | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| 
 | ||||
| /** | ||||
|  * Implements the {@code tls-sni-01} challenge. | ||||
|  | @ -44,8 +44,8 @@ public class TlsSniChallenge extends GenericTokenChallenge { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void authorize(Account account) { | ||||
|         super.authorize(account); | ||||
|     public void authorize(Registration registration) { | ||||
|         super.authorize(registration); | ||||
|         String hash = computeHash(getAuthorization()); | ||||
|         subject = hash.substring(0, 32) + '.' + hash.substring(32) + ".acme.invalid"; | ||||
|     } | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ import java.net.URI; | |||
| import java.security.cert.X509Certificate; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.exception.AcmeException; | ||||
| import org.shredzone.acme4j.exception.AcmeServerException; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
|  | @ -47,11 +47,12 @@ public interface Connection extends AutoCloseable { | |||
|      *            {@link ClaimBuilder} containing claims. Must not be {@code null}. | ||||
|      * @param session | ||||
|      *            {@link Session} instance to be used for tracking | ||||
|      * @param account | ||||
|      *            {@link Account} to be used for signing the request | ||||
|      * @param registration | ||||
|      *            {@link Registration} to be used for signing the request | ||||
|      * @return HTTP response code | ||||
|      */ | ||||
|     int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException; | ||||
|     int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) | ||||
|                 throws AcmeException; | ||||
| 
 | ||||
|     /** | ||||
|      * Reads a server response as JSON data. | ||||
|  |  | |||
|  | @ -15,13 +15,12 @@ package org.shredzone.acme4j.exception; | |||
| 
 | ||||
| import java.net.URI; | ||||
| 
 | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.AcmeClient; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| 
 | ||||
| /** | ||||
|  * An exception that is thrown when there is a conflict with the request. For example, | ||||
|  * this exception is thrown when {@link AcmeClient#newRegistration(Account, Registration)} | ||||
|  * this exception is thrown when {@link AcmeClient#newRegistration(Registration)} | ||||
|  * is invoked, but the registration already exists. | ||||
|  * | ||||
|  * @author Richard "Shred" Körber | ||||
|  |  | |||
|  | @ -27,7 +27,6 @@ import java.util.Map; | |||
| import org.jose4j.jws.AlgorithmIdentifiers; | ||||
| import org.jose4j.jws.JsonWebSignature; | ||||
| import org.jose4j.lang.JoseException; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.AcmeClient; | ||||
| import org.shredzone.acme4j.Authorization; | ||||
| import org.shredzone.acme4j.Registration; | ||||
|  | @ -88,10 +87,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void newRegistration(Account account, Registration registration) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|         } | ||||
|     public void newRegistration(Registration registration) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|  | @ -110,7 +106,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|                 claims.put("contact", registration.getContacts()); | ||||
|             } | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.NEW_REG), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.NEW_REG), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_CREATED && rc != HttpURLConnection.HTTP_CONFLICT) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -132,10 +128,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void modifyRegistration(Account account, Registration registration) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|         } | ||||
|     public void modifyRegistration(Registration registration) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|  | @ -154,7 +147,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|                 claims.put("agreement", registration.getAgreement()); | ||||
|             } | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(registration.getLocation(), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(registration.getLocation(), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_ACCEPTED) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -172,11 +165,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void changeRegistrationKey(Account account, Registration registration, KeyPair newKeyPair) | ||||
|                 throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|         } | ||||
|     public void changeRegistrationKey(Registration registration, KeyPair newKeyPair) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|  | @ -186,7 +175,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|         if (newKeyPair == null) { | ||||
|             throw new NullPointerException("newKeyPair must not be null"); | ||||
|         } | ||||
|         if (Arrays.equals(account.getKeyPair().getPrivate().getEncoded(), | ||||
|         if (Arrays.equals(registration.getKeyPair().getPrivate().getEncoded(), | ||||
|                         newKeyPair.getPrivate().getEncoded())) { | ||||
|             throw new IllegalArgumentException("newKeyPair must actually be a new key pair"); | ||||
|         } | ||||
|  | @ -195,7 +184,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|         try { | ||||
|             ClaimBuilder oldKeyClaim = new ClaimBuilder(); | ||||
|             oldKeyClaim.putResource("reg"); | ||||
|             oldKeyClaim.putKey("oldKey", account.getKeyPair().getPublic()); | ||||
|             oldKeyClaim.putKey("oldKey", registration.getKeyPair().getPublic()); | ||||
| 
 | ||||
|             JsonWebSignature jws = new JsonWebSignature(); | ||||
|             jws.setPayload(oldKeyClaim.toString()); | ||||
|  | @ -214,7 +203,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|             claims.putResource("reg"); | ||||
|             claims.put("newKey", newKey); | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(registration.getLocation(), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(registration.getLocation(), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_ACCEPTED) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -222,10 +211,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void recoverRegistration(Account account, Registration registration) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|         } | ||||
|     public void recoverRegistration(Registration registration) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|  | @ -243,7 +229,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|                 claims.put("contact", registration.getContacts()); | ||||
|             } | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.RECOVER_REG), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.RECOVER_REG), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_CREATED) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -258,9 +244,9 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void newAuthorization(Account account, Authorization auth) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|     public void newAuthorization(Registration registration, Authorization auth) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|         if (auth == null) { | ||||
|             throw new NullPointerException("auth must not be null"); | ||||
|  | @ -277,7 +263,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|                     .put("type", "dns") | ||||
|                     .put("value", auth.getDomain()); | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.NEW_AUTHZ), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.NEW_AUTHZ), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_CREATED) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -313,9 +299,9 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void triggerChallenge(Account account, Challenge challenge) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|     public void triggerChallenge(Registration registration, Challenge challenge) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|         if (challenge == null) { | ||||
|             throw new NullPointerException("challenge must not be null"); | ||||
|  | @ -330,7 +316,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|             claims.putResource("challenge"); | ||||
|             challenge.respond(claims); | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(challenge.getLocation(), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(challenge.getLocation(), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_OK && rc != HttpURLConnection.HTTP_ACCEPTED) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -383,9 +369,9 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public URI requestCertificate(Account account, byte[] csr) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|     public URI requestCertificate(Registration registration, byte[] csr) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|         if (csr == null) { | ||||
|             throw new NullPointerException("csr must not be null"); | ||||
|  | @ -397,7 +383,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|             claims.putResource(Resource.NEW_CERT); | ||||
|             claims.putBase64("csr", csr); | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.NEW_CERT), claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(resourceUri(Resource.NEW_CERT), claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_CREATED && rc != HttpURLConnection.HTTP_ACCEPTED) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  | @ -429,9 +415,9 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void revokeCertificate(Account account, X509Certificate certificate) throws AcmeException { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|     public void revokeCertificate(Registration registration, X509Certificate certificate) throws AcmeException { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|         if (certificate == null) { | ||||
|             throw new NullPointerException("certificate must not be null"); | ||||
|  | @ -448,7 +434,7 @@ public abstract class AbstractAcmeClient implements AcmeClient { | |||
|             claims.putResource(Resource.REVOKE_CERT); | ||||
|             claims.putBase64("certificate", certificate.getEncoded()); | ||||
| 
 | ||||
|             int rc = conn.sendSignedRequest(resUri, claims, session, account); | ||||
|             int rc = conn.sendSignedRequest(resUri, claims, session, registration); | ||||
|             if (rc != HttpURLConnection.HTTP_OK) { | ||||
|                 conn.throwAcmeException(); | ||||
|             } | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ import org.jose4j.jwk.PublicJsonWebKey; | |||
| import org.jose4j.jws.AlgorithmIdentifiers; | ||||
| import org.jose4j.jws.JsonWebSignature; | ||||
| import org.jose4j.lang.JoseException; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.connector.Connection; | ||||
| import org.shredzone.acme4j.connector.HttpConnector; | ||||
| import org.shredzone.acme4j.connector.Resource; | ||||
|  | @ -99,7 +99,8 @@ public class DefaultConnection implements Connection { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|     public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) | ||||
|                 throws AcmeException { | ||||
|         if (uri == null) { | ||||
|             throw new NullPointerException("uri must not be null"); | ||||
|         } | ||||
|  | @ -109,15 +110,15 @@ public class DefaultConnection implements Connection { | |||
|         if (session == null) { | ||||
|             throw new NullPointerException("session must not be null"); | ||||
|         } | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|         if (conn != null) { | ||||
|             throw new IllegalStateException("Connection was not closed. Race condition?"); | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             KeyPair keypair = account.getKeyPair(); | ||||
|             KeyPair keypair = registration.getKeyPair(); | ||||
| 
 | ||||
|             if (session.getNonce() == null) { | ||||
|                 LOG.debug("Getting initial nonce, HEAD {}", uri); | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ import org.jose4j.jwk.PublicJsonWebKey; | |||
| import org.jose4j.jws.AlgorithmIdentifiers; | ||||
| import org.jose4j.jws.JsonWebSignature; | ||||
| import org.jose4j.lang.JoseException; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.challenge.ProofOfPossessionChallenge; | ||||
| 
 | ||||
| /** | ||||
|  | @ -87,15 +87,15 @@ public class ValidationBuilder { | |||
|      * Signs with the given {@link KeyPair} and returns a signed JSON Web Signature | ||||
|      * structure that can be used for validation. | ||||
|      * | ||||
|      * @param account | ||||
|      *            {@link Account} of the current domain owner | ||||
|      * @param registration | ||||
|      *            {@link Registration} of the current domain owner | ||||
|      * @param keypair | ||||
|      *            One of the {@link KeyPair} requested by the challenge | ||||
|      * @return JWS validation object | ||||
|      */ | ||||
|     public String sign(Account account, KeyPair keypair) { | ||||
|         if (account == null) { | ||||
|             throw new NullPointerException("account must not be null"); | ||||
|     public String sign(Registration registration, KeyPair keypair) { | ||||
|         if (registration == null) { | ||||
|             throw new NullPointerException("registration must not be null"); | ||||
|         } | ||||
|         if (keypair == null) { | ||||
|             throw new NullPointerException("keypair must not be null"); | ||||
|  | @ -105,7 +105,7 @@ public class ValidationBuilder { | |||
|             ClaimBuilder claims = new ClaimBuilder(); | ||||
|             claims.put("type", ProofOfPossessionChallenge.TYPE); | ||||
|             claims.array("identifiers", identifiers.toArray()); | ||||
|             claims.putKey("accountKey", account.getKeyPair().getPublic()); | ||||
|             claims.putKey("accountKey", registration.getKeyPair().getPublic()); | ||||
| 
 | ||||
|             final PublicJsonWebKey jwk = PublicJsonWebKey.Factory.newPublicJwk(keypair.getPublic()); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,52 +0,0 @@ | |||
| /* | ||||
|  * acme4j - Java ACME client | ||||
|  * | ||||
|  * Copyright (C) 2015 Richard "Shred" Körber | ||||
|  *   http://acme4j.shredzone.org
 | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
|  */ | ||||
| package org.shredzone.acme4j; | ||||
| 
 | ||||
| import static org.hamcrest.Matchers.*; | ||||
| import static org.junit.Assert.assertThat; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.security.KeyPair; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.util.TestUtils; | ||||
| 
 | ||||
| /** | ||||
|  * Unit tests for {@link Account}. | ||||
|  * | ||||
|  * @author Richard "Shred" Körber | ||||
|  */ | ||||
| public class AccountTest { | ||||
| 
 | ||||
|     /** | ||||
|      * Test getters and setters. | ||||
|      */ | ||||
|     @Test | ||||
|     public void testGetterAndSetter() throws IOException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
| 
 | ||||
|         Account account = new Account(keypair); | ||||
| 
 | ||||
|         assertThat(account.getKeyPair(), is(sameInstance(keypair))); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Test null values. | ||||
|      */ | ||||
|     @Test(expected = NullPointerException.class) | ||||
|     public void testNull() { | ||||
|         new Account(null); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -16,10 +16,13 @@ package org.shredzone.acme4j; | |||
| import static org.hamcrest.Matchers.*; | ||||
| import static org.junit.Assert.assertThat; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| import java.security.KeyPair; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.util.TestUtils; | ||||
| 
 | ||||
| /** | ||||
|  * Unit tests for {@link Registration}. | ||||
|  | @ -32,12 +35,14 @@ public class RegistrationTest { | |||
|      * Test getters and setters. | ||||
|      */ | ||||
|     @Test | ||||
|     public void testGetterAndSetter() throws URISyntaxException { | ||||
|         Registration registration = new Registration(); | ||||
|     public void testGetterAndSetter() throws IOException, URISyntaxException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
|         Registration registration = new Registration(keypair); | ||||
| 
 | ||||
|         assertThat(registration.getAgreement(), is(nullValue())); | ||||
|         assertThat(registration.getLocation(), is(nullValue())); | ||||
|         assertThat(registration.getContacts(), is(empty())); | ||||
|         assertThat(registration.getKeyPair(), is(sameInstance(keypair))); | ||||
| 
 | ||||
|         registration.setAgreement(new URI("http://example.com/agreement.pdf")); | ||||
|         registration.setLocation(new URI("http://example.com/acme/12345")); | ||||
|  | @ -56,12 +61,16 @@ public class RegistrationTest { | |||
|      * Test constructors. | ||||
|      */ | ||||
|     @Test | ||||
|     public void testConstructor() throws URISyntaxException { | ||||
|         Registration registration1 = new Registration(); | ||||
|         assertThat(registration1.getLocation(), is(nullValue())); | ||||
|     public void testConstructor() throws IOException, URISyntaxException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
| 
 | ||||
|         Registration registration2 = new Registration(new URI("http://example.com/acme/12345")); | ||||
|         Registration registration1 = new Registration(keypair); | ||||
|         assertThat(registration1.getLocation(), is(nullValue())); | ||||
|         assertThat(registration1.getKeyPair(), is(sameInstance(keypair))); | ||||
| 
 | ||||
|         Registration registration2 = new Registration(keypair, new URI("http://example.com/acme/12345")); | ||||
|         assertThat(registration2.getLocation(), is(new URI("http://example.com/acme/12345"))); | ||||
|         assertThat(registration2.getKeyPair(), is(sameInstance(keypair))); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ import java.io.IOException; | |||
| import java.security.KeyPair; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.Status; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
| import org.shredzone.acme4j.util.TestUtils; | ||||
|  | @ -42,7 +42,7 @@ public class DnsChallengeTest { | |||
|     @Test | ||||
|     public void testDnsChallenge() throws IOException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
|         Account account = new Account(keypair); | ||||
|         Registration reg = new Registration(keypair); | ||||
| 
 | ||||
|         DnsChallenge challenge = new DnsChallenge(); | ||||
|         challenge.unmarshall(TestUtils.getJsonAsMap("dnsChallenge")); | ||||
|  | @ -57,7 +57,7 @@ public class DnsChallengeTest { | |||
|             // expected
 | ||||
|         } | ||||
| 
 | ||||
|         challenge.authorize(account); | ||||
|         challenge.authorize(reg); | ||||
| 
 | ||||
|         assertThat(challenge.getDigest(), is("rzMmotrIgsithyBYc0vgiLUEEKYx0WetQRgEF2JIozA")); | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ import java.io.IOException; | |||
| import java.security.KeyPair; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.Status; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
| import org.shredzone.acme4j.util.TestUtils; | ||||
|  | @ -44,7 +44,7 @@ public class HttpChallengeTest { | |||
|     @Test | ||||
|     public void testHttpChallenge() throws IOException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
|         Account account = new Account(keypair); | ||||
|         Registration reg = new Registration(keypair); | ||||
| 
 | ||||
|         HttpChallenge challenge = new HttpChallenge(); | ||||
|         challenge.unmarshall(TestUtils.getJsonAsMap("httpChallenge")); | ||||
|  | @ -59,7 +59,7 @@ public class HttpChallengeTest { | |||
|             // expected
 | ||||
|         } | ||||
| 
 | ||||
|         challenge.authorize(account); | ||||
|         challenge.authorize(reg); | ||||
| 
 | ||||
|         assertThat(challenge.getToken(), is(TOKEN)); | ||||
|         assertThat(challenge.getAuthorization(), is(KEY_AUTHORIZATION)); | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ import java.security.KeyPair; | |||
| import java.security.cert.X509Certificate; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.Status; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
| import org.shredzone.acme4j.util.TestUtils; | ||||
|  | @ -42,7 +42,7 @@ public class ProofOfPossessionChallengeTest { | |||
|     public void testProofOfPossessionChallenge() throws IOException { | ||||
|         X509Certificate cert = TestUtils.createCertificate(); | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
|         Account account = new Account(keypair); | ||||
|         Registration reg = new Registration(keypair); | ||||
|         KeyPair domainKeyPair = TestUtils.createDomainKeyPair(); | ||||
| 
 | ||||
|         ProofOfPossessionChallenge challenge = new ProofOfPossessionChallenge(); | ||||
|  | @ -60,14 +60,14 @@ public class ProofOfPossessionChallengeTest { | |||
|             // expected
 | ||||
|         } | ||||
| 
 | ||||
|         challenge.authorize(account, domainKeyPair, "example.org"); | ||||
|         challenge.authorize(reg, domainKeyPair, "example.org"); | ||||
| 
 | ||||
|         ClaimBuilder cb = new ClaimBuilder(); | ||||
|         challenge.respond(cb); | ||||
| 
 | ||||
|         assertThat(cb.toString(), sameJSONAs("{\"type\"=\"" | ||||
|             + ProofOfPossessionChallenge.TYPE + "\",\"authorization\"=" | ||||
|             + new ValidationBuilder().domain("example.org").sign(account, domainKeyPair) | ||||
|             + new ValidationBuilder().domain("example.org").sign(reg, domainKeyPair) | ||||
|             + "}")); | ||||
|     } | ||||
| 
 | ||||
|  | @ -78,12 +78,12 @@ public class ProofOfPossessionChallengeTest { | |||
|     @Test | ||||
|     public void testImportValidation() throws IOException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
|         Account account = new Account(keypair); | ||||
|         Registration reg = new Registration(keypair); | ||||
|         KeyPair domainKeyPair = TestUtils.createDomainKeyPair(); | ||||
| 
 | ||||
|         String validation = new ValidationBuilder() | ||||
|                 .domain("example.org") | ||||
|                 .sign(account, domainKeyPair); | ||||
|                 .sign(reg, domainKeyPair); | ||||
| 
 | ||||
|         ProofOfPossessionChallenge challenge = new ProofOfPossessionChallenge(); | ||||
|         challenge.unmarshall(TestUtils.getJsonAsMap("proofOfPossessionChallenge")); | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ import java.io.IOException; | |||
| import java.security.KeyPair; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.Status; | ||||
| import org.shredzone.acme4j.util.ClaimBuilder; | ||||
| import org.shredzone.acme4j.util.TestUtils; | ||||
|  | @ -42,7 +42,7 @@ public class TlsSniChallengeTest { | |||
|     @Test | ||||
|     public void testTlsSniChallenge() throws IOException { | ||||
|         KeyPair keypair = TestUtils.createKeyPair(); | ||||
|         Account account = new Account(keypair); | ||||
|         Registration reg = new Registration(keypair); | ||||
| 
 | ||||
|         TlsSniChallenge challenge = new TlsSniChallenge(); | ||||
|         challenge.unmarshall(TestUtils.getJsonAsMap("tlsSniChallenge")); | ||||
|  | @ -57,7 +57,7 @@ public class TlsSniChallengeTest { | |||
|             // expected
 | ||||
|         } | ||||
| 
 | ||||
|         challenge.authorize(account); | ||||
|         challenge.authorize(reg); | ||||
| 
 | ||||
|         assertThat(challenge.getSubject(), is("14e2350a04434f93c2e0b6012968d99d.ed459b6a7a019d9695609b8514f9d63d.acme.invalid")); | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,7 +31,6 @@ import org.jose4j.jws.JsonWebSignature; | |||
| import org.jose4j.lang.JoseException; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Authorization; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.Status; | ||||
|  | @ -54,11 +53,12 @@ import org.shredzone.acme4j.util.TimestampParser; | |||
|  */ | ||||
| public class AbstractAcmeClientTest { | ||||
| 
 | ||||
|     private Account testAccount; | ||||
|     private URI resourceUri; | ||||
|     private URI locationUri; | ||||
|     private URI anotherLocationUri; | ||||
|     private URI agreementUri; | ||||
|     private KeyPair accountKeyPair; | ||||
|     private Registration testRegistration; | ||||
| 
 | ||||
|     @Before | ||||
|     public void setup() throws IOException, URISyntaxException { | ||||
|  | @ -66,7 +66,8 @@ public class AbstractAcmeClientTest { | |||
|         locationUri = new URI("https://example.com/acme/some-location"); | ||||
|         anotherLocationUri = new URI("https://example.com/acme/another-location"); | ||||
|         agreementUri = new URI("http://example.com/agreement.pdf"); | ||||
|         testAccount = new Account(TestUtils.createKeyPair()); | ||||
|         accountKeyPair = TestUtils.createKeyPair(); | ||||
|         testRegistration = new Registration(accountKeyPair); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -74,16 +75,16 @@ public class AbstractAcmeClientTest { | |||
|      */ | ||||
|     @Test | ||||
|     public void testNewRegistration() throws AcmeException { | ||||
|         Registration registration = new Registration(); | ||||
|         Registration registration = new Registration(accountKeyPair); | ||||
|         registration.addContact("mailto:foo@example.com"); | ||||
| 
 | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(resourceUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("newRegistration"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_CREATED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -104,7 +105,7 @@ public class AbstractAcmeClientTest { | |||
|         TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection); | ||||
|         client.putTestResource(Resource.NEW_REG, resourceUri); | ||||
| 
 | ||||
|         client.newRegistration(testAccount, registration); | ||||
|         client.newRegistration(registration); | ||||
| 
 | ||||
|         assertThat(registration.getLocation(), is(locationUri)); | ||||
|         assertThat(registration.getAgreement(), is(agreementUri)); | ||||
|  | @ -115,18 +116,18 @@ public class AbstractAcmeClientTest { | |||
|      */ | ||||
|     @Test | ||||
|     public void testModifyRegistration() throws AcmeException { | ||||
|         Registration registration = new Registration(); | ||||
|         Registration registration = new Registration(accountKeyPair); | ||||
|         registration.setAgreement(agreementUri); | ||||
|         registration.addContact("mailto:foo2@example.com"); | ||||
|         registration.setLocation(locationUri); | ||||
| 
 | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(locationUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("modifyRegistration"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_ACCEPTED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -146,7 +147,7 @@ public class AbstractAcmeClientTest { | |||
| 
 | ||||
|         TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection); | ||||
| 
 | ||||
|         client.modifyRegistration(testAccount, registration); | ||||
|         client.modifyRegistration(registration); | ||||
| 
 | ||||
|         assertThat(registration.getLocation(), is(locationUri)); | ||||
|         assertThat(registration.getAgreement(), is(agreementUri)); | ||||
|  | @ -157,14 +158,14 @@ public class AbstractAcmeClientTest { | |||
|      */ | ||||
|     @Test | ||||
|     public void testChangeRegistrationKey() throws AcmeException, IOException { | ||||
|         Registration registration = new Registration(); | ||||
|         Registration registration = new Registration(accountKeyPair); | ||||
|         registration.setLocation(locationUri); | ||||
| 
 | ||||
|         final KeyPair newKeyPair = TestUtils.createDomainKeyPair(); | ||||
| 
 | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 Map<String, Object> claimMap = claims.toMap(); | ||||
|                 assertThat(claimMap.get("resource"), is((Object) "reg")); | ||||
|                 assertThat(claimMap.get("newKey"), not(nullValue())); | ||||
|  | @ -189,7 +190,7 @@ public class AbstractAcmeClientTest { | |||
| 
 | ||||
|                 assertThat(uri, is(locationUri)); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_ACCEPTED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -201,7 +202,7 @@ public class AbstractAcmeClientTest { | |||
| 
 | ||||
|         TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection); | ||||
| 
 | ||||
|         client.changeRegistrationKey(testAccount, registration, newKeyPair); | ||||
|         client.changeRegistrationKey(registration, newKeyPair); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -209,13 +210,13 @@ public class AbstractAcmeClientTest { | |||
|      */ | ||||
|     @Test(expected = IllegalArgumentException.class) | ||||
|     public void testChangeRegistrationSameKey() throws AcmeException, IOException { | ||||
|         Registration registration = new Registration(); | ||||
|         Registration registration = new Registration(accountKeyPair); | ||||
|         registration.setLocation(locationUri); | ||||
| 
 | ||||
|         Connection connection = new DummyConnection(); | ||||
|         TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection); | ||||
| 
 | ||||
|         client.changeRegistrationKey(testAccount, registration, testAccount.getKeyPair()); | ||||
|         client.changeRegistrationKey(registration, registration.getKeyPair()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -223,17 +224,17 @@ public class AbstractAcmeClientTest { | |||
|      */ | ||||
|     @Test | ||||
|     public void testRecoverRegistration() throws AcmeException { | ||||
|         Registration registration = new Registration(); | ||||
|         Registration registration = new Registration(accountKeyPair); | ||||
|         registration.addContact("mailto:foo@example.com"); | ||||
|         registration.setLocation(locationUri); | ||||
| 
 | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(resourceUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("recoverRegistration"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_CREATED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -254,7 +255,7 @@ public class AbstractAcmeClientTest { | |||
|         TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection); | ||||
|         client.putTestResource(Resource.RECOVER_REG, resourceUri); | ||||
| 
 | ||||
|         client.recoverRegistration(testAccount, registration); | ||||
|         client.recoverRegistration(registration); | ||||
| 
 | ||||
|         assertThat(registration.getLocation(), is(anotherLocationUri)); | ||||
|         assertThat(registration.getAgreement(), is(agreementUri)); | ||||
|  | @ -270,11 +271,11 @@ public class AbstractAcmeClientTest { | |||
| 
 | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(resourceUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("newAuthorizationRequest"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_CREATED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -297,7 +298,7 @@ public class AbstractAcmeClientTest { | |||
|         client.putTestChallenge("http-01", httpChallenge); | ||||
|         client.putTestChallenge("dns-01", dnsChallenge); | ||||
| 
 | ||||
|         client.newAuthorization(testAccount, auth); | ||||
|         client.newAuthorization(testRegistration, auth); | ||||
| 
 | ||||
|         assertThat(auth.getDomain(), is("example.org")); | ||||
|         assertThat(auth.getStatus(), is(Status.PENDING)); | ||||
|  | @ -365,11 +366,11 @@ public class AbstractAcmeClientTest { | |||
|     public void testTriggerChallenge() throws AcmeException { | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(resourceUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("triggerHttpChallengeRequest"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_ACCEPTED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -383,9 +384,9 @@ public class AbstractAcmeClientTest { | |||
| 
 | ||||
|         HttpChallenge challenge = new HttpChallenge(); | ||||
|         challenge.unmarshall(getJsonAsMap("triggerHttpChallenge")); | ||||
|         challenge.authorize(testAccount); | ||||
|         challenge.authorize(testRegistration); | ||||
| 
 | ||||
|         client.triggerChallenge(testAccount, challenge); | ||||
|         client.triggerChallenge(testRegistration, challenge); | ||||
| 
 | ||||
|         assertThat(challenge.getStatus(), is(Status.PENDING)); | ||||
|         assertThat(challenge.getLocation(), is(locationUri)); | ||||
|  | @ -451,11 +452,11 @@ public class AbstractAcmeClientTest { | |||
|     public void testRequestCertificate() throws AcmeException, IOException { | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(resourceUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("requestCertificateRequest"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration.getKeyPair(), is(sameInstance(accountKeyPair))); | ||||
|                 return HttpURLConnection.HTTP_CREATED; | ||||
|             } | ||||
| 
 | ||||
|  | @ -469,7 +470,7 @@ public class AbstractAcmeClientTest { | |||
|         client.putTestResource(Resource.NEW_CERT, resourceUri); | ||||
| 
 | ||||
|         byte[] csr = TestUtils.getResourceAsByteArray("/csr.der"); | ||||
|         URI certUri = client.requestCertificate(testAccount, csr); | ||||
|         URI certUri = client.requestCertificate(testRegistration, csr); | ||||
| 
 | ||||
|         assertThat(certUri, is(locationUri)); | ||||
|     } | ||||
|  | @ -509,11 +510,11 @@ public class AbstractAcmeClientTest { | |||
| 
 | ||||
|         Connection connection = new DummyConnection() { | ||||
|             @Override | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|             public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|                 assertThat(uri, is(resourceUri)); | ||||
|                 assertThat(claims.toString(), sameJSONAs(getJson("revokeCertificateRequest"))); | ||||
|                 assertThat(session, is(notNullValue())); | ||||
|                 assertThat(account, is(sameInstance(testAccount))); | ||||
|                 assertThat(registration, is(sameInstance(testRegistration))); | ||||
|                 return HttpURLConnection.HTTP_OK; | ||||
|             } | ||||
|         }; | ||||
|  | @ -521,7 +522,7 @@ public class AbstractAcmeClientTest { | |||
|         TestableAbstractAcmeClient client = new TestableAbstractAcmeClient(connection); | ||||
|         client.putTestResource(Resource.REVOKE_CERT, resourceUri); | ||||
| 
 | ||||
|         client.revokeCertificate(testAccount, cert); | ||||
|         client.revokeCertificate(testRegistration, cert); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ import org.jose4j.base64url.Base64Url; | |||
| import org.jose4j.jwx.CompactSerializer; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.connector.Connection; | ||||
| import org.shredzone.acme4j.connector.HttpConnector; | ||||
| import org.shredzone.acme4j.connector.Resource; | ||||
|  | @ -295,9 +295,9 @@ public class DefaultConnectionTest { | |||
|             cb.put("foo", 123).put("bar", "a-string"); | ||||
| 
 | ||||
|             KeyPair keypair = TestUtils.createKeyPair(); | ||||
|             Account account = new Account(keypair); | ||||
|             Registration reg = new Registration(keypair); | ||||
| 
 | ||||
|             conn.sendSignedRequest(requestUri, cb, testSession, account); | ||||
|             conn.sendSignedRequest(requestUri, cb, testSession, reg); | ||||
|         } | ||||
| 
 | ||||
|         verify(mockUrlConnection).setRequestMethod("HEAD"); | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ import java.net.URI; | |||
| import java.security.cert.X509Certificate; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| import org.shredzone.acme4j.connector.Connection; | ||||
| import org.shredzone.acme4j.connector.Resource; | ||||
| import org.shredzone.acme4j.connector.Session; | ||||
|  | @ -38,7 +38,7 @@ public class DummyConnection implements Connection { | |||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Account account) throws AcmeException { | ||||
|     public int sendSignedRequest(URI uri, ClaimBuilder claims, Session session, Registration registration) throws AcmeException { | ||||
|         throw new UnsupportedOperationException(); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ import org.jose4j.base64url.Base64Url; | |||
| import org.jose4j.json.JsonUtil; | ||||
| import org.jose4j.lang.JoseException; | ||||
| import org.junit.Test; | ||||
| import org.shredzone.acme4j.Account; | ||||
| import org.shredzone.acme4j.Registration; | ||||
| 
 | ||||
| /** | ||||
|  * Unit test for {@link ValidationBuilder}. | ||||
|  | @ -40,16 +40,16 @@ public class ValidationBuilderTest { | |||
|      */ | ||||
|     @Test | ||||
|     public void testValidationBuilder() throws IOException, JoseException { | ||||
|         Account account = new Account(TestUtils.createKeyPair()); | ||||
|         Registration reg = new Registration(TestUtils.createKeyPair()); | ||||
|         KeyPair domainKeyPair = TestUtils.createDomainKeyPair(); | ||||
| 
 | ||||
|         assertThat(account.getKeyPair(), not(domainKeyPair)); | ||||
|         assertThat(reg.getKeyPair(), not(domainKeyPair)); | ||||
| 
 | ||||
|         ValidationBuilder vb = new ValidationBuilder(); | ||||
|         vb.domain("abc.de").domain("ef.gh"); | ||||
|         vb.domains("ijk.lm", "no.pq", "rst.uv"); | ||||
|         vb.domains(Arrays.asList("w.x", "y.z")); | ||||
|         String json = vb.sign(account, domainKeyPair); | ||||
|         String json = vb.sign(reg, domainKeyPair); | ||||
| 
 | ||||
|         Map<String, Object> data = JsonUtil.parseJson(json); | ||||
| 
 | ||||
|  |  | |||
|  | @ -80,17 +80,14 @@ public class ClientTest { | |||
|             createdNewKeyPair = true; | ||||
|         } | ||||
| 
 | ||||
|         // Create an Account instance for the user
 | ||||
|         Account account = new Account(userKeyPair); | ||||
| 
 | ||||
|         // Create an AcmeClient for Let's Encrypt
 | ||||
|         // Use "acme://letsencrypt.org" for production server
 | ||||
|         AcmeClient client = AcmeClientFactory.connect("acme://letsencrypt.org/staging"); | ||||
| 
 | ||||
|         // Register a new user
 | ||||
|         Registration reg = new Registration(); | ||||
|         Registration reg = new Registration(userKeyPair); | ||||
|         try { | ||||
|             client.newRegistration(account, reg); | ||||
|             client.newRegistration(reg); | ||||
|             LOG.info("Registered a new user, URI: " + reg.getLocation()); | ||||
|         } catch (AcmeConflictException ex) { | ||||
|             LOG.info("Account does already exist, URI: " + reg.getLocation()); | ||||
|  | @ -99,40 +96,41 @@ public class ClientTest { | |||
|         LOG.info("Terms of Service: " + reg.getAgreement()); | ||||
| 
 | ||||
|         if (createdNewKeyPair) { | ||||
|             boolean accepted = acceptAgreement(client, account, reg); | ||||
|             boolean accepted = acceptAgreement(client, reg); | ||||
|             if (!accepted) { | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         for (String domain : domains) { | ||||
|             // Create a new authorization
 | ||||
|             Authorization auth = new Authorization(); | ||||
|             auth.setDomain(domain); | ||||
|             try { | ||||
|                 client.newAuthorization(account, auth); | ||||
|                 client.newAuthorization(reg, auth); | ||||
|             } catch (AcmeUnauthorizedException ex) { | ||||
|                 // Maybe there are new T&C to accept?
 | ||||
|                 boolean accepted = acceptAgreement(client, account, reg); | ||||
|                 boolean accepted = acceptAgreement(client, reg); | ||||
|                 if (!accepted) { | ||||
|                     return; | ||||
|                 } | ||||
|                 // Then try again...
 | ||||
|                 client.newAuthorization(account, auth); | ||||
|                 client.newAuthorization(reg, auth); | ||||
|             } | ||||
|             LOG.info("New authorization for domain " + domain); | ||||
| 
 | ||||
|             // Uncomment a challenge...
 | ||||
|             Challenge challenge = httpChallenge(auth, account, domain); | ||||
| //            Challenge challenge = dnsChallenge(auth, account, domain);
 | ||||
| //            Challenge challenge = tlsSniChallenge(auth, account, domain);
 | ||||
|             Challenge challenge = httpChallenge(auth, reg, domain); | ||||
| //            Challenge challenge = dnsChallenge(auth, reg, domain);
 | ||||
| //            Challenge challenge = tlsSniChallenge(auth, reg, domain);
 | ||||
| 
 | ||||
|             if (challenge == null) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Trigger the challenge
 | ||||
|             client.triggerChallenge(account, challenge); | ||||
|             client.triggerChallenge(reg, challenge); | ||||
| 
 | ||||
|             // Poll for the challenge to complete
 | ||||
|             int attempts = 10; | ||||
|  | @ -177,7 +175,7 @@ public class ClientTest { | |||
|         } | ||||
| 
 | ||||
|         // Request a signed certificate
 | ||||
|         URI certificateUri = client.requestCertificate(account, csrb.getEncoded()); | ||||
|         URI certificateUri = client.requestCertificate(reg, csrb.getEncoded()); | ||||
|         LOG.info("Success! The certificate for domains " + domains + " has been generated!"); | ||||
|         LOG.info("Certificate URI: " + certificateUri); | ||||
| 
 | ||||
|  | @ -188,13 +186,13 @@ public class ClientTest { | |||
|         } | ||||
| 
 | ||||
|         // Revoke the certificate (uncomment if needed...)
 | ||||
|         // client.revokeCertificate(account, cert);
 | ||||
|         // client.revokeCertificate(reg, cert);
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prepares HTTP challenge. | ||||
|      */ | ||||
|     public Challenge httpChallenge(Authorization auth, Account account, String domain) throws AcmeException { | ||||
|     public Challenge httpChallenge(Authorization auth, Registration reg, String domain) throws AcmeException { | ||||
|         // Find a single http-01 challenge
 | ||||
|         HttpChallenge challenge = auth.findChallenge(HttpChallenge.TYPE); | ||||
|         if (challenge == null) { | ||||
|  | @ -203,7 +201,7 @@ public class ClientTest { | |||
|         } | ||||
| 
 | ||||
|         // Authorize the challenge
 | ||||
|         challenge.authorize(account); | ||||
|         challenge.authorize(reg); | ||||
| 
 | ||||
|         // Output the challenge, wait for acknowledge...
 | ||||
|         LOG.info("Please create a file in your web server's base directory."); | ||||
|  | @ -233,7 +231,7 @@ public class ClientTest { | |||
|     /** | ||||
|      * Prepares DNS challenge. | ||||
|      */ | ||||
|     public Challenge dnsChallenge(Authorization auth, Account account, String domain) throws AcmeException { | ||||
|     public Challenge dnsChallenge(Authorization auth, Registration reg, String domain) throws AcmeException { | ||||
|         // Find a single dns-01 challenge
 | ||||
|         DnsChallenge challenge = auth.findChallenge(DnsChallenge.TYPE); | ||||
|         if (challenge == null) { | ||||
|  | @ -242,7 +240,7 @@ public class ClientTest { | |||
|         } | ||||
| 
 | ||||
|         // Authorize the challenge
 | ||||
|         challenge.authorize(account); | ||||
|         challenge.authorize(reg); | ||||
| 
 | ||||
|         // Output the challenge, wait for acknowledge...
 | ||||
|         LOG.info("Please create a TXT record:"); | ||||
|  | @ -267,7 +265,7 @@ public class ClientTest { | |||
|     /** | ||||
|      * Prepares TLS-SNI challenge. | ||||
|      */ | ||||
|     public Challenge tlsSniChallenge(Authorization auth, Account account, String domain) throws AcmeException { | ||||
|     public Challenge tlsSniChallenge(Authorization auth, Registration reg, String domain) throws AcmeException { | ||||
|         // Find a single tls-sni-01 challenge
 | ||||
|         TlsSniChallenge challenge = auth.findChallenge(TlsSniChallenge.TYPE); | ||||
|         if (challenge == null) { | ||||
|  | @ -276,7 +274,7 @@ public class ClientTest { | |||
|         } | ||||
| 
 | ||||
|         // Authorize the challenge
 | ||||
|         challenge.authorize(account); | ||||
|         challenge.authorize(reg); | ||||
| 
 | ||||
|         // Get the Subject
 | ||||
|         String subject = challenge.getSubject(); | ||||
|  | @ -327,13 +325,11 @@ public class ClientTest { | |||
|      * | ||||
|      * @param client | ||||
|      *            {@link AcmeClient} to send confirmation to | ||||
|      * @param account | ||||
|      *            {@link Account} User's account | ||||
|      * @param reg | ||||
|      *            {@link Registration} User's registration, containing the Agreement URI | ||||
|      * @return {@code true}: User confirmed, {@code false} user rejected | ||||
|      */ | ||||
|     public boolean acceptAgreement(AcmeClient client, Account account, Registration reg) | ||||
|     public boolean acceptAgreement(AcmeClient client, Registration reg) | ||||
|                 throws AcmeException { | ||||
|         int option = JOptionPane.showConfirmDialog(null, | ||||
|                         "Do you accept the Terms of Service?\n\n" + reg.getAgreement(), | ||||
|  | @ -344,7 +340,7 @@ public class ClientTest { | |||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         client.modifyRegistration(account, reg); | ||||
|         client.modifyRegistration(reg); | ||||
|         LOG.info("Updated user's ToS"); | ||||
| 
 | ||||
|         return true; | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ After authorizing the challenge, `DnsChallenge` provides a digest string: | |||
| 
 | ||||
| ```java | ||||
| DnsChallenge challenge = auth.findChallenge(DnsChallenge.TYPE); | ||||
| challenge.authorize(account); | ||||
| challenge.authorize(registration); | ||||
| 
 | ||||
| String digest = challenge.getDigest(); | ||||
| ``` | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ After authorizing the challenge, `HttpChallenge` provides two strings: | |||
| 
 | ||||
| ```java | ||||
| HttpChallenge challenge = auth.findChallenge(HttpChallenge.TYPE); | ||||
| challenge.authorize(account); | ||||
| challenge.authorize(registration); | ||||
| 
 | ||||
| String token = challenge.getToken(); | ||||
| String content = challenge.getAuthorization(); | ||||
|  |  | |||
|  | @ -13,14 +13,14 @@ Collection<X509Certificate> certificates = challenge.getCertificates(); | |||
| In the next step, the _current owner of the domain_ authorizes the challenge, by signing it with a key pair that corresponds to one of the `certificates`: | ||||
| 
 | ||||
| ```java | ||||
| Account ownerAccount = ... // Account of the domain owner | ||||
| Registration ownerRegistration = ... // Registration of the domain owner | ||||
| KeyPair domainKeyPair = ... // Key pair matching a certificate | ||||
| String domain = ... // Domain to authorize | ||||
| 
 | ||||
| challenge.authorize(ownerAccount, domainKeyPair, domain); | ||||
| challenge.authorize(ownerRegistration, domainKeyPair, domain); | ||||
| ``` | ||||
| 
 | ||||
| The challenge is completed when the domain is associated with the account of the `ownerAccount`, and the `domainKeyPair` matches one of the `certificates`. | ||||
| The challenge is completed when the domain is associated with the account of the `ownerRegistration`, and the `domainKeyPair` matches one of the `certificates`. | ||||
| 
 | ||||
| ## Importing a Validation | ||||
| 
 | ||||
|  | @ -31,12 +31,12 @@ There is a way to prepare the validation externally, and import a validation doc | |||
| _acme4j_ offers a `ValidationBuilder` class for generating the validation document: | ||||
| 
 | ||||
| ```java | ||||
| Account ownerAccount = ... // Account of the domain owner | ||||
| Registration ownerRegistration = ... // Registration of the domain owner | ||||
| KeyPair domainKeyPair = ... // Key pair matching a certificates | ||||
| 
 | ||||
| ValidationBuilder vb = new ValidationBuilder(); | ||||
| vb.domain("example.org"); | ||||
| String json = vb.sign(ownerAccount, domainKeyPair); | ||||
| String json = vb.sign(ownerRegistration, domainKeyPair); | ||||
| ``` | ||||
| 
 | ||||
| This `json` string can be transported (e.g. via email) and then imported into the challenge: | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ After authorizing the challenge, `TlsSniChallenge` provides a subject: | |||
| 
 | ||||
| ```java | ||||
| TlsSniChallenge challenge = auth.findChallenge(TlsSniChallenge.TYPE); | ||||
| challenge.authorize(account); | ||||
| challenge.authorize(registration); | ||||
| 
 | ||||
| String subject = challenge.getSubject(); | ||||
| ``` | ||||
|  | @ -17,7 +17,7 @@ The `subject` is basically a domain name formed like in this example: | |||
| 30c452b9bd088cdbc2c4094947025d7c.7364ea602ac325a1b55ceaae024fbe29.acme.invalid | ||||
| ``` | ||||
| 
 | ||||
| You need to create a self-signed certificate with the subject set as _Subject Alternative Name_. After that, configure your web server so it will use this certificate on a SNI request to the  `subject`. | ||||
| You need to create a self-signed certificate with the subject set as _Subject Alternative Name_. After that, configure your web server so it will use this certificate on a SNI request to the `subject`. | ||||
| 
 | ||||
| The `TlsSniChallenge` class does not generate a self-signed certificate, as it would require _Bouncy Castle_. However, there is a utility method in the _acme4j-utils_ module for this use case: | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ Once you have your account set up, you need to associate your domain with it. Th | |||
| Authorization auth = new Authorization(); | ||||
| auth.setDomain("example.org"); | ||||
| 
 | ||||
| client.newAuthorization(account, auth); | ||||
| client.newAuthorization(registration, auth); | ||||
| ``` | ||||
| 
 | ||||
| When `newAuthorization()` returns successfully, the `Authorization` instance contains further details about how you can prove ownership of your domain. An ACME server offers combinations of different authorization methods, called `Challenge`s. | ||||
|  | @ -30,10 +30,10 @@ HttpChallenge challenge = auth.findChallenge(HttpChallenge.TYPE); | |||
| 
 | ||||
| It returns a properly casted `Challenge` object, or `null` if your challenge type was not acceptable. | ||||
| 
 | ||||
| After you have found a challenge, you need to sign it first: | ||||
| After you have found a challenge, you need to sign it with your `Registration` first: | ||||
| 
 | ||||
| ```java | ||||
| challenge.authorize(account); | ||||
| challenge.authorize(registration); | ||||
| ``` | ||||
| 
 | ||||
| After signing the challenge, it provides the necessary data for a successful response to the challenge. The kind of response depends on the challenge type (see the [documentation of challenges](../challenge/index.html)). Some types may also require more data for authorizing the challenge. | ||||
|  | @ -41,7 +41,7 @@ After signing the challenge, it provides the necessary data for a successful res | |||
| After you have performed the necessary steps to set up the response to the challenge, the ACME server is told to test your response: | ||||
| 
 | ||||
| ```java | ||||
| client.triggerChallenge(account, challenge); | ||||
| client.triggerChallenge(registration, challenge); | ||||
| ``` | ||||
| 
 | ||||
| Again, the call completes the `Challenge` transfer object with server side data like the current challenge status and a challenge URI. | ||||
|  | @ -51,7 +51,7 @@ Now you have to wait for the server to test your response and set the challenge | |||
| ```java | ||||
| while (challenge.getStatus() != Challenge.Status.VALID) { | ||||
|     Thread.sleep(3000L); | ||||
|     client.updateChallenge(account, challenge); | ||||
|     client.updateChallenge(registration, challenge); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
|  | @ -61,8 +61,6 @@ As soon as the challenge is `VALID`, you have successfully associated the domain | |||
| 
 | ||||
| If your final certificate contains further domains or subdomains, repeat the authorization run with each of them. | ||||
| 
 | ||||
| Note that wildcard certificates are not currently supported. | ||||
| 
 | ||||
| ## Update an Authorization | ||||
| 
 | ||||
| For each authorization, the server provides an URI where the status of the authorization can be queried. It can be retrieved from `Authorization.getLocation()` after `newAuthorization()` returned. | ||||
|  | @ -88,11 +86,11 @@ Challenge originalChallenge = ... // some Challenge instance | |||
| URI challengeUri = originalChallenge.getLocation(); | ||||
| ``` | ||||
| 
 | ||||
| Later, you pass this `challengeUri` to `recreateChallenge()`: | ||||
| Later, you pass this `challengeUri` to `restoreChallenge()`: | ||||
| 
 | ||||
| ```java | ||||
| URI challengeUri = ... // challenge URI | ||||
| Challenge restoredChallenge = client.restoreChallenge(account, challengeUri); | ||||
| Challenge restoredChallenge = client.restoreChallenge(registration, challengeUri); | ||||
| ``` | ||||
| 
 | ||||
| The `restoredChallenge` already reflects the current state of the challenge. | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ To revoke a certificate, just pass the it to the respective method: | |||
| 
 | ||||
| ```java | ||||
| X509Certificate cert = ... // certificate to be revoked | ||||
| client.revokeCertificate(account, cert); | ||||
| client.revokeCertificate(registration, cert); | ||||
| ``` | ||||
| 
 | ||||
| As an exception, ACME servers also accept the domain's key pair for revoking a certificate. _acme4j_ does not directly support this way of revocation. However, you can do so with this tiny hack: | ||||
|  | @ -53,7 +53,7 @@ As an exception, ACME servers also accept the domain's key pair for revoking a c | |||
| ```java | ||||
| KeyPair domainKeyPair = ... // KeyPair to be used for HTTPS encryption | ||||
| X509Certificate cert = ... // certificate to be revoked | ||||
| client.revokeCertificate(new Account(domainKeyPair), cert); | ||||
| client.revokeCertificate(new Registration(domainKeyPair), cert); | ||||
| ``` | ||||
| 
 | ||||
| If you have the choice, you should always prefer to use your account key. | ||||
|  |  | |||
|  | @ -17,4 +17,4 @@ For this reason, special ACME URIs should be preferred: | |||
| AcmeClient client = AcmeClientFactory.connect("acme://letsencrypt.org/staging"); | ||||
| ``` | ||||
| 
 | ||||
|  Instead of a generic provider, this call uses a special _Let's Encrypt_ provider that also accepts the _Let's Encrypt_ certificate. | ||||
| Instead of a generic provider, this call uses a special _Let's Encrypt_ provider that also accepts the _Let's Encrypt_ certificate. | ||||
|  |  | |||
|  | @ -2,16 +2,28 @@ | |||
| 
 | ||||
| _acme4j_ is a client library that helps connecting to ACME servers without worrying about specification details. | ||||
| 
 | ||||
| Central part of the communication is an [`Account`](../apidocs/org/shredzone/acme4j/Account.html) object, which contains a key pair. The ACME server identifies your account by the public key, and verifies that your requests are signed with your private key. For this reason, you should keep the key pair in a safe place. If you should lose it, you would need to recover access to your account. | ||||
| Central part of the communication is a [`Registration`](../apidocs/org/shredzone/acme4j/Registration.html) object, which contains a key pair. The ACME server identifies your account by the public key, and verifies that your requests are signed with your private key. For this reason, you should keep the key pair in a safe place. If you should lose it, you would need to recover access to your account. | ||||
| 
 | ||||
| The first step is to create a Java `KeyPair`, save it somewhere, and then pass it to the constructor of `Account`: | ||||
| The first step is to create a Java `KeyPair`, save it somewhere, and then pass it to the constructor of `Registration`: | ||||
| 
 | ||||
| ```java | ||||
| KeyPair keypair = ... // your key pair | ||||
| Account account = new Account(keypair); | ||||
| Registration registration = new Registration(keypair); | ||||
| ``` | ||||
| 
 | ||||
| You need this `Account` instance as identifier for almost all API calls. | ||||
| You need this `Registration` instance as identifier for almost all API calls. | ||||
| 
 | ||||
| Some calls additionally need the registration location URI to be set. You can either set it after construction, or use the constructor that also accepts the location URI: | ||||
| 
 | ||||
| ```java | ||||
| KeyPair keypair = ... // your key pair | ||||
| URI accountLocationUri = ... // your account's URI, as returned by newRegistration() | ||||
| 
 | ||||
| Registration registration1 = new Registration(keypair, accountLocationUri); | ||||
| 
 | ||||
| Registration registration2 = new Registration(keypair); | ||||
| registration2.setLocation(accountLocationUri); | ||||
| ``` | ||||
| 
 | ||||
| To get a certificate, these steps need to be performed: | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,16 +12,18 @@ Individual CAs may offer further ways of recovery, which are not part of this do | |||
| 
 | ||||
| On this recovery method, the CA contacts the account owner via one of the contact addresses given on account creation. The owner is asked to take some action (e.g. clicking on a link in an email). If it was successful, the account data is transferred to the new account. | ||||
| 
 | ||||
| To initiate contact-based recovery, you first need to create a new key pair and an `Account` object. Then create a `Registration` object by passing the location URI of your _old_ account to the constructor. Finally, start the recovery process by invoking `recoverRegistration()`: | ||||
| To initiate contact-based recovery, you first need to create a new account key pair. Then create a `Registration` object by passing the _new_ key pair and location URI of your _old_ account to the constructor. Finally, start the recovery process by invoking `recoverRegistration()`: | ||||
| 
 | ||||
| ```java | ||||
| Account account = ... // your new account | ||||
| KeyPair newKeyPair = ... // your new account KeyPair | ||||
| URI oldAccountUri = ... // location of your old account | ||||
| 
 | ||||
| Registration reg = new Registration(oldAccountUri); | ||||
| client.recoverRegistration(account, reg); | ||||
| Registration reg = new Registration(newKeyPair, oldAccountUri); | ||||
| client.recoverRegistration(reg); | ||||
| 
 | ||||
| URI newAccountUri = reg.getLocation(); | ||||
| ``` | ||||
| 
 | ||||
| `newAccountUri` is the location URI of your _new_ account. | ||||
| `newAccountUri` is the location URI of your _new_ account. Store it and use it in connection with your new key pair. | ||||
| 
 | ||||
| The old location URI is now invalid and can be deleted. | ||||
|  |  | |||
|  | @ -1,43 +1,43 @@ | |||
| # Register an Account | ||||
| 
 | ||||
| The first thing to do is to register your `Account` with the CA. | ||||
| The first thing to do is to register your account key with the CA. | ||||
| 
 | ||||
| You need a `Registration` instance that serves as a data transfer object, and fill the object with details of your account. The `AcmeClient.newRegistration()` call then completes the data transfer object with server side account data. | ||||
| 
 | ||||
| This code fragment registers your account with the CA. Optionally you can add contact URIs (like email addresses or phone numbers) to the registration, which will help the CA getting in contact with you. | ||||
| 
 | ||||
| ```java | ||||
| Registration reg = new Registration(); | ||||
| KeyPair keyPair = ... // your account KeyPair | ||||
| Registration reg = new Registration(keypair); | ||||
| reg.addContact("mailto:acme@example.com"); // optional | ||||
| 
 | ||||
| client.newRegistration(account, reg); | ||||
| client.newRegistration(reg); | ||||
| 
 | ||||
| URI accountLocationUri = reg.getLocation(); // your account's server URI | ||||
| ``` | ||||
| 
 | ||||
| After invocating `newRegistration()`, the `location` property contains the URI of your newly created account on server side. | ||||
| After invocating `newRegistration()`, the `location` property contains the URI of your newly created account on server side. You should copy the `location` to a safe place. You will need it again if you need to [update your registration](#Update_your_Registration), or if you need to [recover](./recovery.html) access to your account after you have lost your account key. Unlike your key pair, the `location` is a public information that does not need security precautions. | ||||
| 
 | ||||
| `newRegistration()` may fail and throw an `AcmeException` for various reasons. When your public key was already registered with the CA, an `AcmeConflictException` is thrown, but the `location` property will still hold your account URI after the call. This may be helpful if you forgot your account URI and need to recover it. | ||||
| 
 | ||||
| You should always copy the `location` to a safe place. If you should lose your key pair, you will need it to [recover](./recovery.html) access to your account. Unlike your key pair, the `location` is an information that does not need security precautions. | ||||
| ## Update your Registration | ||||
| 
 | ||||
| ## Update an Account | ||||
| At some point, you may want to update your registration. For example your contact address might have changed, or you were asked by the CA to accept the latest terms of service. | ||||
| 
 | ||||
| At some point, you may want to update your account. For example your contact address might have changed, or you were asked by the CA to accept the current terms of service. | ||||
| 
 | ||||
| To do so, create a `Registration` object again, and set the `location` property to the URI that you previously got via `newRegistration()`. Also set whatever you like to change to your account. | ||||
| To do so, create a `Registration` object again, this time by passing in the account key pair and the `location` property that you previously got via `newRegistration()`. Also set whatever you like to change to your account. | ||||
| 
 | ||||
| The following example accepts the terms of service by explicitly setting the URL to the agreement document. | ||||
| 
 | ||||
| ```java | ||||
| KeyPair keyPair = ... // your account KeyPair | ||||
| URI accountLocationUri = ... // your account's URI | ||||
| 
 | ||||
| URI agreementUri = ... // TAC link provided by the CA | ||||
| 
 | ||||
| Registration reg = new Registration(); | ||||
| reg.setLocation(accountLocationUri); | ||||
| Registration reg = new Registration(keyPair, accountLocationUri); | ||||
| reg.setAgreement(agreementUri); | ||||
| 
 | ||||
| client.modifyRegistration(account, reg); | ||||
| client.modifyRegistration(reg); | ||||
| ``` | ||||
| 
 | ||||
| ## Account Key Roll-Over | ||||
|  | @ -47,12 +47,14 @@ It is also possible to change the key pair that is associated with your account, | |||
| The following example changes the key pair: | ||||
| 
 | ||||
| ```java | ||||
| Registration reg = new Registration(); | ||||
| reg.setLocation(accountLocationUri); | ||||
| KeyPair oldKeyPair = ... // your old KeyPair that is to be replaced | ||||
| URI accountLocationUri = ... // your account's URI | ||||
| 
 | ||||
| Registration reg = new Registration(oldKeyPair, accountLocationUri); | ||||
| 
 | ||||
| KeyPair newKeyPair = ... // new KeyPair to be used | ||||
| 
 | ||||
| client.changeRegistrationKey(account, reg, newKeyPair); | ||||
| client.changeRegistrationKey(reg, newKeyPair); | ||||
| ``` | ||||
| 
 | ||||
| All subsequent calls must now use an `Account` instance with the new key. The old key can be disposed. | ||||
| All subsequent calls must now use the new key pair. The old key pair can be disposed. | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ | |||
|       <item name="Introduction" href="index.html"/> | ||||
|       <item name="How to Use" href="usage/index.html"> | ||||
|         <item name="Connection" href="usage/connect.html"/> | ||||
|         <item name="Account" href="usage/register.html"/> | ||||
|         <item name="Registration" href="usage/register.html"/> | ||||
|         <item name="Authorization" href="usage/authorization.html"/> | ||||
|         <item name="Certificate" href="usage/certificate.html"/> | ||||
|         <item name="Recovery" href="usage/recovery.html"/> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Richard Körber
						Richard Körber