All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.shredzone.acme4j.OrderBuilder Maven / Gradle / Ivy

/*
 * acme4j - Java ACME client
 *
 * Copyright (C) 2017 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 java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

import java.net.URL;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import edu.umd.cs.findbugs.annotations.Nullable;
import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.toolbox.JSONBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A builder for a new {@link Order} object.
 */
public class OrderBuilder {
    private static final Logger LOG = LoggerFactory.getLogger(OrderBuilder.class);

    private final Login login;

    private final Set identifierSet = new LinkedHashSet<>();
    private @Nullable Instant notBefore;
    private @Nullable Instant notAfter;
    private boolean autoRenewal;
    private @Nullable Instant autoRenewalStart;
    private @Nullable Instant autoRenewalEnd;
    private @Nullable Duration autoRenewalLifetime;
    private @Nullable Duration autoRenewalLifetimeAdjust;
    private boolean autoRenewalGet;

    /**
     * Create a new {@link OrderBuilder}.
     *
     * @param login
     *            {@link Login} to bind with
     */
    protected OrderBuilder(Login login) {
        this.login = login;
    }

    /**
     * Adds a domain name to the order.
     *
     * @param domain
     *            Name of a domain to be ordered. May be a wildcard domain if supported by
     *            the CA. IDN names are accepted and will be ACE encoded automatically.
     * @return itself
     */
    public OrderBuilder domain(String domain) {
        return identifier(Identifier.dns(domain));
    }

    /**
     * Adds domain names to the order.
     *
     * @param domains
     *            Collection of domain names to be ordered. May be wildcard domains if
     *            supported by the CA. IDN names are accepted and will be ACE encoded
     *            automatically.
     * @return itself
     */
    public OrderBuilder domains(String... domains) {
        for (String domain : requireNonNull(domains, "domains")) {
            domain(domain);
        }
        return this;
    }

    /**
     * Adds a collection of domain names to the order.
     *
     * @param domains
     *            Collection of domain names to be ordered. May be wildcard domains if
     *            supported by the CA. IDN names are accepted and will be ACE encoded
     *            automatically.
     * @return itself
     */
    public OrderBuilder domains(Collection domains) {
        requireNonNull(domains, "domains").forEach(this::domain);
        return this;
    }

    /**
     * Adds an {@link Identifier} to the order.
     *
     * @param identifier
     *            {@link Identifier} to be added to the order.
     * @return itself
     * @since 2.3
     */
    public OrderBuilder identifier(Identifier identifier) {
        identifierSet.add(requireNonNull(identifier, "identifier"));
        return this;
    }

    /**
     * Adds a collection of {@link Identifier} to the order.
     *
     * @param identifiers
     *            Collection of {@link Identifier} to be added to the order.
     * @return itself
     * @since 2.3
     */
    public OrderBuilder identifiers(Collection identifiers) {
        requireNonNull(identifiers, "identifiers").forEach(this::identifier);
        return this;
    }

    /**
     * Sets a "not before" date in the certificate. May be ignored by the CA.
     *
     * @param notBefore "not before" date
     * @return itself
     */
    public OrderBuilder notBefore(Instant notBefore) {
        if (autoRenewal) {
            throw new IllegalArgumentException("cannot combine notBefore with autoRenew");
        }
        this.notBefore = requireNonNull(notBefore, "notBefore");
        return this;
    }

    /**
     * Sets a "not after" date in the certificate. May be ignored by the CA.
     *
     * @param notAfter "not after" date
     * @return itself
     */
    public OrderBuilder notAfter(Instant notAfter) {
        if (autoRenewal) {
            throw new IllegalArgumentException("cannot combine notAfter with autoRenew");
        }
        this.notAfter = requireNonNull(notAfter, "notAfter");
        return this;
    }

    /**
     * Enables short-term automatic renewal of the certificate. Must be supported by the
     * CA.
     * 

* Automatic renewals cannot be combined with {@link #notBefore(Instant)} or {@link * #notAfter(Instant)}. * * @return itself * @since 2.3 */ public OrderBuilder autoRenewal() { if (notBefore != null || notAfter != null) { throw new IllegalArgumentException("cannot combine notBefore/notAfter with autoRenewalOr"); } this.autoRenewal = true; return this; } /** * Sets the earliest date of validity of the first issued certificate. If not set, * the start date is the earliest possible date. *

* Implies {@link #autoRenewal()}. * * @param start * Start date of validity * @return itself * @since 2.3 */ public OrderBuilder autoRenewalStart(Instant start) { autoRenewal(); this.autoRenewalStart = requireNonNull(start, "start"); return this; } /** * Sets the latest date of validity of the last issued certificate. If not set, the * CA's default is used. *

* Implies {@link #autoRenewal()}. * * @param end * End date of validity * @return itself * @see Metadata#getAutoRenewalMaxDuration() * @since 2.3 */ public OrderBuilder autoRenewalEnd(Instant end) { autoRenewal(); this.autoRenewalEnd = requireNonNull(end, "end"); return this; } /** * Sets the maximum validity period of each certificate. If not set, the CA's * default is used. *

* Implies {@link #autoRenewal()}. * * @param duration * Duration of validity of each certificate * @return itself * @see Metadata#getAutoRenewalMinLifetime() * @since 2.3 */ public OrderBuilder autoRenewalLifetime(Duration duration) { autoRenewal(); this.autoRenewalLifetime = requireNonNull(duration, "duration"); return this; } /** * Sets the amount of pre-dating each certificate. If not set, the CA's * default (0) is used. *

* Implies {@link #autoRenewal()}. * * @param duration * Duration of certificate pre-dating * @return itself * @since 2.7 */ public OrderBuilder autoRenewalLifetimeAdjust(Duration duration) { autoRenewal(); this.autoRenewalLifetimeAdjust = requireNonNull(duration, "duration"); return this; } /** * Announces that the client wishes to fetch the auto-renewed certificate via GET * request. If not used, the STAR certificate can only be fetched via POST-as-GET * request. {@link Metadata#isAutoRenewalGetAllowed()} must return {@code true} in * order for this option to work. *

* This option is only needed if you plan to fetch the STAR certificate via other * means than by using acme4j. *

* Implies {@link #autoRenewal()}. * * @return itself * @since 2.6 */ public OrderBuilder autoRenewalEnableGet() { autoRenewal(); this.autoRenewalGet = true; return this; } /** * Sends a new order to the server, and returns an {@link Order} object. * * @return {@link Order} that was created */ public Order create() throws AcmeException { if (identifierSet.isEmpty()) { throw new IllegalArgumentException("At least one identifer is required"); } Session session = login.getSession(); if (autoRenewal && !session.getMetadata().isAutoRenewalEnabled()) { throw new AcmeException("CA does not support short-term automatic renewals"); } LOG.debug("create"); try (Connection conn = session.connect()) { JSONBuilder claims = new JSONBuilder(); claims.array("identifiers", identifierSet.stream().map(Identifier::toMap).collect(toList())); if (notBefore != null) { claims.put("notBefore", notBefore); } if (notAfter != null) { claims.put("notAfter", notAfter); } if (autoRenewal) { JSONBuilder arClaims = claims.object("auto-renewal"); if (autoRenewalStart != null) { arClaims.put("start-date", autoRenewalStart); } if (autoRenewalStart != null) { arClaims.put("end-date", autoRenewalEnd); } if (autoRenewalLifetime != null) { arClaims.put("lifetime", autoRenewalLifetime); } if (autoRenewalLifetimeAdjust != null) { arClaims.put("lifetime-adjust", autoRenewalLifetimeAdjust); } if (autoRenewalGet) { arClaims.put("allow-certificate-get", autoRenewalGet); } } conn.sendSignedRequest(session.resourceUrl(Resource.NEW_ORDER), claims, login); URL orderLocation = conn.getLocation(); if (orderLocation == null) { throw new AcmeProtocolException("Server did not provide an order location"); } Order order = new Order(login, orderLocation); order.setJSON(conn.readJsonResponse()); return order; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy