001/* 002 * acme4j - Java ACME client 003 * 004 * Copyright (C) 2018 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; 015 016import static org.assertj.core.api.Assertions.assertThat; 017import static org.junit.jupiter.api.Assertions.assertThrows; 018import static org.mockito.Mockito.*; 019import static org.shredzone.acme4j.toolbox.TestUtils.getJSON; 020import static org.shredzone.acme4j.toolbox.TestUtils.url; 021 022import java.io.IOException; 023import java.net.HttpURLConnection; 024import java.net.URL; 025 026import org.junit.jupiter.api.Test; 027import org.mockito.ArgumentMatchers; 028import org.shredzone.acme4j.challenge.Challenge; 029import org.shredzone.acme4j.challenge.Dns01Challenge; 030import org.shredzone.acme4j.challenge.Http01Challenge; 031import org.shredzone.acme4j.exception.AcmeException; 032import org.shredzone.acme4j.exception.AcmeProtocolException; 033import org.shredzone.acme4j.provider.AcmeProvider; 034import org.shredzone.acme4j.provider.TestableConnectionProvider; 035import org.shredzone.acme4j.toolbox.JSON; 036import org.shredzone.acme4j.toolbox.JSONBuilder; 037import org.shredzone.acme4j.toolbox.TestUtils; 038 039/** 040 * Unit tests for {@link Login}. 041 */ 042public class LoginTest { 043 044 private final URL resourceUrl = url("https://example.com/acme/resource/123"); 045 046 /** 047 * Test the constructor. 048 */ 049 @Test 050 public void testConstructor() throws IOException { 051 var location = url(TestUtils.ACCOUNT_URL); 052 var keypair = TestUtils.createKeyPair(); 053 var session = TestUtils.session(); 054 055 var login = new Login(location, keypair, session); 056 assertThat(login.getAccountLocation()).isEqualTo(location); 057 assertThat(login.getKeyPair()).isEqualTo(keypair); 058 assertThat(login.getSession()).isEqualTo(session); 059 060 assertThat(login.getAccount()).isNotNull(); 061 assertThat(login.getAccount().getLogin()).isEqualTo(login); 062 assertThat(login.getAccount().getLocation()).isEqualTo(location); 063 assertThat(login.getAccount().getSession()).isEqualTo(session); 064 } 065 066 /** 067 * Test the simple binders. 068 */ 069 @Test 070 public void testBinder() throws IOException { 071 var location = url(TestUtils.ACCOUNT_URL); 072 var keypair = TestUtils.createKeyPair(); 073 var session = TestUtils.session(); 074 075 var login = new Login(location, keypair, session); 076 077 var auth = login.bindAuthorization(resourceUrl); 078 assertThat(auth).isNotNull(); 079 assertThat(auth.getLogin()).isEqualTo(login); 080 assertThat(auth.getLocation()).isEqualTo(resourceUrl); 081 082 var cert = login.bindCertificate(resourceUrl); 083 assertThat(cert).isNotNull(); 084 assertThat(cert.getLogin()).isEqualTo(login); 085 assertThat(cert.getLocation()).isEqualTo(resourceUrl); 086 087 var order = login.bindOrder(resourceUrl); 088 assertThat(order).isNotNull(); 089 assertThat(order.getLogin()).isEqualTo(login); 090 assertThat(order.getLocation()).isEqualTo(resourceUrl); 091 } 092 093 /** 094 * Test that the account's keypair can be changed. 095 */ 096 @Test 097 public void testKeyChange() throws IOException { 098 var location = url(TestUtils.ACCOUNT_URL); 099 var keypair = TestUtils.createKeyPair(); 100 var session = TestUtils.session(); 101 102 var login = new Login(location, keypair, session); 103 assertThat(login.getKeyPair()).isEqualTo(keypair); 104 105 var keypair2 = TestUtils.createKeyPair(); 106 login.setKeyPair(keypair2); 107 assertThat(login.getKeyPair()).isEqualTo(keypair2); 108 } 109 110 /** 111 * Test that challenges are correctly created via provider. 112 */ 113 @Test 114 public void testCreateChallenge() throws Exception { 115 var challengeType = Http01Challenge.TYPE; 116 var challengeUrl = url("https://example.com/acme/authz/0"); 117 118 var data = new JSONBuilder() 119 .put("type", challengeType) 120 .put("url", challengeUrl) 121 .toJSON(); 122 123 var mockChallenge = mock(Http01Challenge.class); 124 var mockProvider = mock(AcmeProvider.class); 125 126 when(mockProvider.createChallenge( 127 ArgumentMatchers.any(Login.class), 128 ArgumentMatchers.eq(data))) 129 .thenReturn(mockChallenge); 130 131 var location = url(TestUtils.ACCOUNT_URL); 132 var keypair = TestUtils.createKeyPair(); 133 var session = TestUtils.session(mockProvider); 134 135 var login = new Login(location, keypair, session); 136 var challenge = login.createChallenge(data); 137 assertThat(challenge).isInstanceOf(Http01Challenge.class); 138 assertThat(challenge).isSameAs(mockChallenge); 139 140 verify(mockProvider).createChallenge(login, data); 141 } 142 143 /** 144 * Test that binding to a challenge invokes createChallenge 145 */ 146 @Test 147 public void testBindChallenge() throws Exception { 148 var locationUrl = new URL("https://example.com/acme/challenge/1"); 149 150 var mockChallenge = mock(Http01Challenge.class); 151 when(mockChallenge.getType()).thenReturn(Http01Challenge.TYPE); 152 var httpChallenge = getJSON("httpChallenge"); 153 var provider = new TestableConnectionProvider() { 154 @Override 155 public int sendSignedPostAsGetRequest(URL url, Login login) { 156 assertThat(url).isEqualTo(locationUrl); 157 return HttpURLConnection.HTTP_OK; 158 } 159 160 @Override 161 public JSON readJsonResponse() { 162 return httpChallenge; 163 } 164 165 @Override 166 public Challenge createChallenge(Login login, JSON json) { 167 assertThat(json).isEqualTo(httpChallenge); 168 return mockChallenge; 169 } 170 }; 171 172 var login = provider.createLogin(); 173 var challenge = login.bindChallenge(locationUrl); 174 assertThat(challenge).isInstanceOf(Http01Challenge.class); 175 assertThat(challenge).isSameAs(mockChallenge); 176 177 var challenge2 = login.bindChallenge(locationUrl, Http01Challenge.class); 178 assertThat(challenge2).isSameAs(mockChallenge); 179 180 var ex = assertThrows(AcmeProtocolException.class, 181 () -> login.bindChallenge(locationUrl, Dns01Challenge.class)); 182 assertThat(ex.getMessage()).isEqualTo("Challenge type http-01 does not match" + 183 " requested class class org.shredzone.acme4j.challenge.Dns01Challenge"); 184 } 185 186 /** 187 * Test that a new order can be created. 188 */ 189 @Test 190 public void testNewOrder() throws AcmeException, IOException { 191 var provider = new TestableConnectionProvider(); 192 var login = provider.createLogin(); 193 194 assertThat(login.newOrder()).isNotNull(); 195 196 provider.close(); 197 } 198 199}