001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2017 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.it.pebble;
015
016import static org.assertj.core.api.Assertions.assertThat;
017import static org.junit.jupiter.api.Assertions.assertThrows;
018
019import java.net.URI;
020import java.security.KeyPair;
021
022import org.junit.jupiter.api.Test;
023import org.shredzone.acme4j.Account;
024import org.shredzone.acme4j.AccountBuilder;
025import org.shredzone.acme4j.Login;
026import org.shredzone.acme4j.Session;
027import org.shredzone.acme4j.Status;
028import org.shredzone.acme4j.exception.AcmeException;
029import org.shredzone.acme4j.exception.AcmeServerException;
030import org.shredzone.acme4j.exception.AcmeUnauthorizedException;
031
032/**
033 * Account related integration tests.
034 */
035public class AccountIT extends PebbleITBase {
036
037    /**
038     * Create a new account, then bind it to a second session.
039     */
040    @Test
041    public void testCreate() throws AcmeException {
042        var keyPair = createKeyPair();
043        var session = new Session(pebbleURI());
044
045        // Register a new user
046        var login = new AccountBuilder()
047                        .addContact("mailto:acme@example.com")
048                        .agreeToTermsOfService()
049                        .useKeyPair(keyPair)
050                        .createLogin(session);
051
052        var location = login.getAccountLocation();
053        assertIsPebbleUrl(location);
054
055        // Check registered data
056        var acct = login.getAccount();
057        assertThat(acct.getLocation()).isEqualTo(location);
058        assertThat(acct.getContacts()).contains(URI.create("mailto:acme@example.com"));
059        assertThat(acct.getStatus()).isEqualTo(Status.VALID);
060
061        // Bind another Account object
062        var session2 = new Session(pebbleURI());
063        var login2 = new Login(location, keyPair, session2);
064        assertThat(login2.getAccountLocation()).isEqualTo(location);
065        var acct2 = login2.getAccount();
066        assertThat(acct2.getLocation()).isEqualTo(location);
067        assertThat(acct2.getContacts()).contains(URI.create("mailto:acme@example.com"));
068        assertThat(acct2.getStatus()).isEqualTo(Status.VALID);
069    }
070
071    /**
072     * Register the same key pair twice.
073     */
074    @Test
075    public void testReCreate() throws AcmeException {
076        var keyPair = createKeyPair();
077
078        // Register a new user
079        var session1 = new Session(pebbleURI());
080        var login1 = new AccountBuilder()
081                        .addContact("mailto:acme@example.com")
082                        .agreeToTermsOfService()
083                        .useKeyPair(keyPair)
084                        .createLogin(session1);
085
086        var location1 = login1.getAccountLocation();
087        assertIsPebbleUrl(location1);
088
089        // Try to register the same account again
090        var session2 = new Session(pebbleURI());
091        var login2 = new AccountBuilder()
092                        .addContact("mailto:acme@example.com")
093                        .agreeToTermsOfService()
094                        .useKeyPair(keyPair)
095                        .createLogin(session2);
096
097        var location2 = login2.getAccountLocation();
098        assertIsPebbleUrl(location2);
099
100        assertThat(location1).isEqualTo(location2);
101    }
102
103    /**
104     * Create a new account. Locate it via onlyExisting.
105     */
106    @Test
107    public void testCreateOnlyExisting() throws AcmeException {
108        var keyPair = createKeyPair();
109
110        var session1 = new Session(pebbleURI());
111        var login1 = new AccountBuilder()
112                        .agreeToTermsOfService()
113                        .useKeyPair(keyPair)
114                        .createLogin(session1);
115
116        var location1 = login1.getAccountLocation();
117        assertIsPebbleUrl(location1);
118
119        var session2 = new Session(pebbleURI());
120        var login2 = new AccountBuilder()
121                        .onlyExisting()
122                        .useKeyPair(keyPair)
123                        .createLogin(session2);
124
125        var location2 = login2.getAccountLocation();
126        assertIsPebbleUrl(location2);
127
128        assertThat(location1).isEqualTo(location2);
129    }
130
131    /**
132     * Locate a non-existing account via onlyExisting. Make sure an accountDoesNotExist
133     * error is returned.
134     */
135    @Test
136    public void testNotExisting() {
137        var ex = assertThrows(AcmeServerException.class, () -> {
138            KeyPair keyPair = createKeyPair();
139            Session session = new Session(pebbleURI());
140            new AccountBuilder().onlyExisting().useKeyPair(keyPair).create(session);
141        });
142        assertThat(ex.getType()).isEqualTo(URI.create("urn:ietf:params:acme:error:accountDoesNotExist"));
143    }
144
145    /**
146     * Modify the contacts of an account.
147     */
148    @Test
149    public void testModify() throws AcmeException {
150        var keyPair = createKeyPair();
151        var session = new Session(pebbleURI());
152
153        var acct = new AccountBuilder()
154                        .addContact("mailto:acme@example.com")
155                        .agreeToTermsOfService()
156                        .useKeyPair(keyPair)
157                        .create(session);
158        var location = acct.getLocation();
159        assertIsPebbleUrl(location);
160
161        acct.modify().addContact("mailto:acme2@example.com").commit();
162
163        assertThat(acct.getContacts()).contains(
164                        URI.create("mailto:acme@example.com"),
165                        URI.create("mailto:acme2@example.com"));
166
167        // Still the same after updating
168        acct.update();
169        assertThat(acct.getContacts()).contains(
170                        URI.create("mailto:acme@example.com"),
171                        URI.create("mailto:acme2@example.com"));
172    }
173
174    /**
175     * Change the account key.
176     */
177    @Test
178    public void testKeyChange() throws AcmeException {
179        var keyPair = createKeyPair();
180        var session = new Session(pebbleURI());
181
182        var acct = new AccountBuilder()
183                        .agreeToTermsOfService()
184                        .useKeyPair(keyPair)
185                        .create(session);
186        var location = acct.getLocation();
187
188        var newKeyPair = createKeyPair();
189        acct.changeKey(newKeyPair);
190
191        assertThrows(AcmeServerException.class, () -> {
192            Session sessionOldKey = new Session(pebbleURI());
193            Account oldAccount = sessionOldKey.login(location, keyPair).getAccount();
194            oldAccount.update();
195        }, "Old account key is still accessible");
196
197        var sessionNewKey = new Session(pebbleURI());
198        var newAccount = sessionNewKey.login(location, newKeyPair).getAccount();
199        assertThat(newAccount.getStatus()).isEqualTo(Status.VALID);
200    }
201
202    /**
203     * Deactivate an account.
204     */
205    @Test
206    public void testDeactivate() throws AcmeException {
207        var keyPair = createKeyPair();
208        var session = new Session(pebbleURI());
209
210        var acct = new AccountBuilder()
211                        .agreeToTermsOfService()
212                        .useKeyPair(keyPair)
213                        .create(session);
214        var location = acct.getLocation();
215
216        acct.deactivate();
217
218        // Make sure it is deactivated now...
219        assertThat(acct.getStatus()).isEqualTo(Status.DEACTIVATED);
220
221        // Make sure account cannot be accessed any more...
222        var ex = assertThrows(AcmeUnauthorizedException.class,
223                () -> {
224            Session session2 = new Session(pebbleURI());
225            Account acct2 = session2.login(location, keyPair).getAccount();
226            acct2.update();
227        }, "Account can still be accessed");
228        assertThat(ex.getMessage()).isEqualTo("Account has been deactivated");
229    }
230
231}