001/* 002 * acme4j - Java ACME client 003 * 004 * Copyright (C) 2016 Richard "Shred" Körber 005 * http://acme4j.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.acme4j.provider; 015 016import java.io.IOException; 017import java.net.URI; 018import java.net.URL; 019import java.time.Instant; 020import java.util.HashMap; 021import java.util.Map; 022import java.util.Optional; 023import java.util.function.BiFunction; 024 025import org.shredzone.acme4j.Login; 026import org.shredzone.acme4j.Session; 027import org.shredzone.acme4j.challenge.Challenge; 028import org.shredzone.acme4j.connector.Connection; 029import org.shredzone.acme4j.connector.DummyConnection; 030import org.shredzone.acme4j.connector.NetworkSettings; 031import org.shredzone.acme4j.connector.Resource; 032import org.shredzone.acme4j.toolbox.JSON; 033import org.shredzone.acme4j.toolbox.JSONBuilder; 034import org.shredzone.acme4j.toolbox.TestUtils; 035 036/** 037 * Test implementation of {@link AcmeProvider}. It also implements a dummy implementation 038 * of {@link Connection} that is always returned on {@link #connect(URI, NetworkSettings)}. 039 */ 040public class TestableConnectionProvider extends DummyConnection implements AcmeProvider { 041 private final Map<String, BiFunction<Login, JSON, Challenge>> creatorMap = new HashMap<>(); 042 private final Map<String, Challenge> createdMap = new HashMap<>(); 043 private final JSONBuilder directory = new JSONBuilder(); 044 private JSONBuilder metadata = null; 045 046 /** 047 * Register a {@link Resource} mapping. 048 * 049 * @param r 050 * {@link Resource} to be mapped 051 * @param u 052 * {@link URL} to be returned 053 */ 054 public void putTestResource(Resource r, URL u) { 055 directory.put(r.path(), u); 056 } 057 058 /** 059 * Add a property to the metadata registry. 060 * 061 * @param key 062 * Metadata key 063 * @param value 064 * Metadata value 065 */ 066 public void putMetadata(String key, Object value) { 067 if (metadata == null) { 068 metadata = directory.object("meta"); 069 } 070 metadata.put(key, value); 071 } 072 073 /** 074 * Register a {@link Challenge}. 075 * 076 * @param type 077 * Challenge type to register. 078 * @param creator 079 * Creator {@link BiFunction} that creates a matching {@link Challenge} 080 */ 081 public void putTestChallenge(String type, BiFunction<Login, JSON, Challenge> creator) { 082 creatorMap.put(type, creator); 083 } 084 085 /** 086 * Returns the {@link Challenge} instance that has been created. Fails if no such 087 * challenge was created. 088 * 089 * @param type Challenge type 090 * @return Created {@link Challenge} instance 091 */ 092 public Challenge getChallenge(String type) { 093 if (!createdMap.containsKey(type)) { 094 throw new IllegalArgumentException("No challenge of type " + type + " was created"); 095 } 096 return createdMap.get(type); 097 } 098 099 /** 100 * Creates a {@link Session} that uses this {@link AcmeProvider}. 101 */ 102 public Session createSession() { 103 return TestUtils.session(this); 104 } 105 106 /** 107 * Creates a {@link Login} that uses this {@link AcmeProvider}. 108 */ 109 public Login createLogin() throws IOException { 110 var session = createSession(); 111 return session.login(new URL(TestUtils.ACCOUNT_URL), TestUtils.createKeyPair()); 112 } 113 114 @Override 115 public Optional<Instant> getRetryAfter() { 116 return Optional.empty(); 117 } 118 119 @Override 120 public boolean accepts(URI serverUri) { 121 throw new UnsupportedOperationException(); 122 } 123 124 @Override 125 public URL resolve(URI serverUri) { 126 throw new UnsupportedOperationException(); 127 } 128 129 @Override 130 public Connection connect(URI serverUri, NetworkSettings networkSettings) { 131 return this; 132 } 133 134 @Override 135 public JSON directory(Session session, URI serverUri) { 136 if (directory.toMap().isEmpty()) { 137 throw new UnsupportedOperationException(); 138 } 139 return directory.toJSON(); 140 } 141 142 @Override 143 public Challenge createChallenge(Login login, JSON data) { 144 if (creatorMap.isEmpty()) { 145 throw new UnsupportedOperationException(); 146 } 147 148 Challenge created; 149 150 var type = data.get("type").asString(); 151 if (creatorMap.containsKey(type)) { 152 created = creatorMap.get(type).apply(login, data); 153 } else { 154 created = new Challenge(login, data); 155 } 156 157 createdMap.put(type, created); 158 159 return created; 160 } 161 162}