private Http01Challenge httpChallenge(Authorization auth) throws AcmeException { // Find a single http-01 challenge Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); if (challenge == null) { throw new AcmeException("Found no " + Http01Challenge.TYPE + " challenge, don't know what to do..."); } // Output the challenge, wait for acknowledge... log.debug("http://{}/.well-known/acme-challenge/{}", auth.getIdentifier().getDomain(), challenge.getToken()); log.debug("Content: {}", challenge.getAuthorization()); return challenge; }
public String getToken() { Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); return challenge.getToken(); }
private CompletableFuture<Void> processChallenge(Authorization auth) { //TODO: We should DUMP EACH Challenge into it's own Runnable so we do challenges in parallel try { Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); log.info("tell remote end to trigger a call now. status="+auth.getStatus()+" domain="+auth.getDomain()+" expires="+auth.getExpires()); challenge.trigger(); log.info("status after="+auth.getStatus()); while (auth.getStatus() != Status.VALID) { //HACK for now....modify to catch RetryAfterException and schedule future Thread.sleep(3000L); log.info("reupdate status"); auth.update(); log.info("updated to status="+auth.getStatus()); } return null; } catch (AcmeException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } }
private void checkAuthStatii(Order order) { for(Authorization auth : order.getAuthorizations()) { Status status = auth.getStatus(); log.info("checking auth="+auth.getDomain()+" status="+status+" location="+auth.getLocation()+" expires="+auth.getExpires()); if(status != Status.PENDING) throw new ChallengeInBadStateException("challenge in bad state="+auth.getJSON()); } }
@Override public Tuple2<Order, Dns01Challenge> challengeInit(String domainName) { AssertTools.assertNotNull(account, "You need to log in first"); Order order; try { order = account.newOrder() // .domains(domainName) // .create(); } catch (AcmeException e) { LOGGER.error("Could not ask for domain {}", domainName, e); throw new LetsencryptException("Could not ask for domain " + domainName, e); } // Get the DNS challenge Dns01Challenge challenge = null; List<String> availableChallenges = new ArrayList<>(); for (Authorization auth : order.getAuthorizations()) { auth.getChallenges().stream().map(it -> it.getType()).forEach(it -> availableChallenges.add(it)); challenge = auth.findChallenge(Dns01Challenge.TYPE); } if (challenge == null) { throw new LetsencryptException("DNS Challenge not found for " + domainName + " ; Available challenges are: [" + Joiner.on(", ").join(availableChallenges) + "]"); } return new Tuple2<>(order, challenge); }
/** * Permanently deactivates the {@link Authorization}. */ public void deactivate() throws AcmeException { LOG.debug("deactivate"); try (Connection conn = getSession().connect()) { JSONBuilder claims = new JSONBuilder(); claims.put("status", "deactivated"); conn.sendSignedRequest(getLocation(), claims, getLogin()); JSON json = conn.readJsonResponse(); if (json != null) { setJSON(json); } } }
/** * Gets the expiry date of the authorization, if set by the server. */ @CheckForNull public Instant getExpires() { return getJSON().get("expires") .map(Value::asString) .map(AcmeUtils::parseTimestamp) .orElse(null); }
/** * Gets a list of all challenges offered by the server, in no specific order. */ public List<Challenge> getChallenges() { Login login = getLogin(); return Collections.unmodifiableList(getJSON().get("challenges") .asArray() .stream() .map(Value::asObject) .map(login::createChallenge) .collect(toList())); }
LOG.info("Authorization for domain {}", auth.getIdentifier().getDomain()); if (auth.getStatus() == Status.VALID) { return; + auth.getIdentifier().getDomain() + ", ... Giving up.");
public String getDomain() { return auth.getDomain(); }
/** * Finds a {@link Challenge} of the given type. Responding to this {@link Challenge} * is sufficient for authorization. * * @param type * Challenge name (e.g. "http-01") * @return {@link Challenge} matching that name, or {@code null} if there is no such * challenge, or if the challenge alone is not sufficient for authorization. * @throws ClassCastException * if the type does not match the expected Challenge class type */ @SuppressWarnings("unchecked") @CheckForNull public <T extends Challenge> T findChallenge(final String type) { return (T) getChallenges().stream() .filter(ch -> type.equals(ch.getType())) .reduce((a, b) -> {throw new AcmeProtocolException("Found more than one challenge of type " + type);}) .orElse(null); }
log.info("Starting authorization for domain {}", auth.getIdentifier().getDomain()); + auth.getIdentifier().getDomain() + ", ... Giving up.");
public Status getStatus() { return auth.getStatus(); }
public URL getLocation() { return auth.getLocation(); }
public String getAuthContent() { Http01Challenge challenge = auth.findChallenge(Http01Challenge.TYPE); return challenge.getAuthorization(); }
/** * Permanently deactivates the {@link Authorization}. */ public void deactivate() throws AcmeException { LOG.debug("deactivate"); try (Connection conn = getSession().connect()) { JSONBuilder claims = new JSONBuilder(); claims.put("status", "deactivated"); conn.sendSignedRequest(getLocation(), claims, getLogin()); JSON json = conn.readJsonResponse(); if (json != null) { setJSON(json); } } }
/** * Gets the expiry date of the authorization, if set by the server. */ @CheckForNull public Instant getExpires() { return getJSON().get("expires") .map(Value::asString) .map(AcmeUtils::parseTimestamp) .orElse(null); }
/** * Gets a list of all challenges offered by the server, in no specific order. */ public List<Challenge> getChallenges() { Login login = getLogin(); return Collections.unmodifiableList(getJSON().get("challenges") .asArray() .stream() .map(Value::asObject) .map(login::createChallenge) .collect(toList())); }
private boolean authorize(final Authorization authorization) throws AcmeException { final Challenge challenge = httpChallenge(authorization); if (challenge == null) { throw new AcmeException("HTTP challenge is null"); } if (challenge.getStatus() == Status.VALID) { return false; } challenge.trigger(); try { int attempts = config.getRetryCount(); while (challenge.getStatus() != Status.VALID && attempts-- > 0) { if (challenge.getStatus() == Status.INVALID) { throw new AcmeException("Invalid challenge status, exiting refresh iteration"); } Thread.sleep(config.getRetryTimeoutMs()); challenge.update(); } } catch (final InterruptedException ex) { Thread.currentThread().interrupt(); } if (challenge.getStatus() != Status.VALID) { throw new AcmeException("Challenge for domain " + authorization.getDomain() + ", is invalid, exiting iteration"); } return true; }
/** * Finds a {@link Challenge} of the given type. Responding to this {@link Challenge} * is sufficient for authorization. * * @param type * Challenge name (e.g. "http-01") * @return {@link Challenge} matching that name, or {@code null} if there is no such * challenge, or if the challenge alone is not sufficient for authorization. * @throws ClassCastException * if the type does not match the expected Challenge class type */ @SuppressWarnings("unchecked") @CheckForNull public <T extends Challenge> T findChallenge(final String type) { return (T) getChallenges().stream() .filter(ch -> type.equals(ch.getType())) .reduce((a, b) -> {throw new AcmeProtocolException("Found more than one challenge of type " + type);}) .orElse(null); }