diff --git a/commafeed-server/src/test/java/com/commafeed/integration/BaseIT.java b/commafeed-server/src/test/java/com/commafeed/integration/BaseIT.java index 1f6f09d9..f6676bf3 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/BaseIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/BaseIT.java @@ -38,12 +38,7 @@ import lombok.Getter; @ExtendWith(MockServerExtension.class) public abstract class BaseIT { - private static final CommaFeedDropwizardAppExtension EXT = new CommaFeedDropwizardAppExtension() { - @Override - protected JerseyClientBuilder clientBuilder() { - return super.clientBuilder().register(HttpAuthenticationFeature.basic("admin", "admin")).register(MultiPartFeature.class); - } - }; + private final CommaFeedDropwizardAppExtension extension = buildExtension(); private Client client; @@ -55,17 +50,26 @@ public abstract class BaseIT { private String webSocketUrl; + protected CommaFeedDropwizardAppExtension buildExtension() { + return new CommaFeedDropwizardAppExtension() { + @Override + protected JerseyClientBuilder clientBuilder() { + return super.clientBuilder().register(HttpAuthenticationFeature.basic("admin", "admin")).register(MultiPartFeature.class); + } + }; + } + @BeforeEach void init(MockServerClient mockServerClient) throws IOException { URL resource = Objects.requireNonNull(getClass().getResource("/feed/rss.xml")); mockServerClient.when(HttpRequest.request().withMethod("GET").withPath("/")) .respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8))); - this.client = EXT.client(); + this.client = extension.client(); this.feedUrl = "http://localhost:" + mockServerClient.getPort() + "/"; - this.baseUrl = "http://localhost:" + EXT.getLocalPort() + "/"; + this.baseUrl = "http://localhost:" + extension.getLocalPort() + "/"; this.apiBaseUrl = this.baseUrl + "rest/"; - this.webSocketUrl = "ws://localhost:" + EXT.getLocalPort() + "/ws"; + this.webSocketUrl = "ws://localhost:" + extension.getLocalPort() + "/ws"; } protected String login() { @@ -82,10 +86,7 @@ public abstract class BaseIT { SubscribeRequest subscribeRequest = new SubscribeRequest(); subscribeRequest.setUrl(feedUrl); subscribeRequest.setTitle("my title for this feed"); - try (Response response = client.target(apiBaseUrl + "feed/subscribe").request().post(Entity.json(subscribeRequest))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - return response.readEntity(Long.class); - } + return client.target(apiBaseUrl + "feed/subscribe").request().post(Entity.json(subscribeRequest), Long.class); } protected Long subscribeAndWaitForEntries(String feedUrl) { @@ -95,10 +96,7 @@ public abstract class BaseIT { } protected Subscription getSubscription(Long subscriptionId) { - try (Response response = client.target(apiBaseUrl + "feed/get/{id}").resolveTemplate("id", subscriptionId).request().get()) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - return response.readEntity(Subscription.class); - } + return client.target(apiBaseUrl + "feed/get/{id}").resolveTemplate("id", subscriptionId).request().get(Subscription.class); } protected Entries getFeedEntries(long subscriptionId) { diff --git a/commafeed-server/src/test/java/com/commafeed/integration/SecurityIT.java b/commafeed-server/src/test/java/com/commafeed/integration/SecurityIT.java new file mode 100644 index 00000000..70bd4232 --- /dev/null +++ b/commafeed-server/src/test/java/com/commafeed/integration/SecurityIT.java @@ -0,0 +1,95 @@ +package com.commafeed.integration; + +import java.util.Base64; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; + +import org.eclipse.jetty.http.HttpStatus; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.commafeed.CommaFeedDropwizardAppExtension; +import com.commafeed.frontend.model.Entries; +import com.commafeed.frontend.model.UserModel; +import com.commafeed.frontend.model.request.ProfileModificationRequest; +import com.commafeed.frontend.model.request.SubscribeRequest; + +class SecurityIT extends BaseIT { + + @Override + protected CommaFeedDropwizardAppExtension buildExtension() { + // override so we don't add http basic auth + return new CommaFeedDropwizardAppExtension(); + } + + @Test + void notLoggedIn() { + try (Response response = getClient().target(getApiBaseUrl() + "user/profile").request().get()) { + Assertions.assertEquals(HttpStatus.UNAUTHORIZED_401, response.getStatus()); + } + } + + @Test + void wrongPassword() { + String auth = "Basic " + Base64.getEncoder().encodeToString("admin:wrong-password".getBytes()); + try (Response response = getClient().target(getApiBaseUrl() + "user/profile") + .request() + .header(HttpHeaders.AUTHORIZATION, auth) + .get()) { + Assertions.assertEquals(HttpStatus.UNAUTHORIZED_401, response.getStatus()); + } + } + + @Test + void missingRole() { + String auth = "Basic " + Base64.getEncoder().encodeToString("demo:demo".getBytes()); + try (Response response = getClient().target(getApiBaseUrl() + "admin/settings") + .request() + .header(HttpHeaders.AUTHORIZATION, auth) + .get()) { + Assertions.assertEquals(HttpStatus.FORBIDDEN_403, response.getStatus()); + } + } + + @Test + void apiKey() { + String auth = "Basic " + Base64.getEncoder().encodeToString("admin:admin".getBytes()); + + // create api key + ProfileModificationRequest req = new ProfileModificationRequest(); + req.setCurrentPassword("admin"); + req.setNewApiKey(true); + getClient().target(getApiBaseUrl() + "user/profile") + .request() + .header(HttpHeaders.AUTHORIZATION, auth) + .post(Entity.json(req)) + .close(); + + // fetch api key + String apiKey = getClient().target(getApiBaseUrl() + "user/profile") + .request() + .header(HttpHeaders.AUTHORIZATION, auth) + .get(UserModel.class) + .getApiKey(); + + // subscribe to a feed + SubscribeRequest subscribeRequest = new SubscribeRequest(); + subscribeRequest.setUrl(getFeedUrl()); + subscribeRequest.setTitle("my title for this feed"); + long subscriptionId = getClient().target(getApiBaseUrl() + "feed/subscribe") + .request() + .header(HttpHeaders.AUTHORIZATION, auth) + .post(Entity.json(subscribeRequest), Long.class); + + // get entries with api key + Entries entries = getClient().target(getApiBaseUrl() + "feed/entries") + .queryParam("id", subscriptionId) + .queryParam("readType", "unread") + .queryParam("apiKey", apiKey) + .request() + .get(Entries.class); + Assertions.assertEquals("my title for this feed", entries.getName()); + } +} diff --git a/commafeed-server/src/test/java/com/commafeed/integration/rest/AdminIT.java b/commafeed-server/src/test/java/com/commafeed/integration/rest/AdminIT.java index 5bd4658d..c3904e82 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/rest/AdminIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/rest/AdminIT.java @@ -4,9 +4,7 @@ import java.util.Arrays; import java.util.List; import javax.ws.rs.client.Entity; -import javax.ws.rs.core.Response; -import org.eclipse.jetty.http.HttpStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -21,10 +19,8 @@ class AdminIT extends BaseIT { @Test void getApplicationSettings() { - try (Response response = getClient().target(getApiBaseUrl() + "admin/settings").request().get()) { - ApplicationSettings settings = response.readEntity(ApplicationSettings.class); - Assertions.assertTrue(settings.getAllowRegistrations()); - } + ApplicationSettings settings = getClient().target(getApiBaseUrl() + "admin/settings").request().get(ApplicationSettings.class); + Assertions.assertTrue(settings.getAllowRegistrations()); } @Nested @@ -37,45 +33,38 @@ class AdminIT extends BaseIT { user.setName("test"); user.setPassword("test".getBytes()); user.setEmail("test@test.com"); + getClient().target(getApiBaseUrl() + "admin/user/save").request().post(Entity.json(user), Void.TYPE); - try (Response response = getClient().target(getApiBaseUrl() + "admin/user/save").request().post(Entity.json(user))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); + List newUsers = getAllUsers(); + Assertions.assertEquals(existingUsers.size() + 1, newUsers.size()); - List newUsers = getAllUsers(); - Assertions.assertEquals(existingUsers.size() + 1, newUsers.size()); - - UserModel newUser = newUsers.stream().filter(u -> u.getName().equals("test")).findFirst().get(); - user.setId(newUser.getId()); - } + UserModel newUser = newUsers.stream() + .filter(u -> u.getName().equals("test")) + .findFirst() + .orElseThrow(() -> new NullPointerException("User not found")); + user.setId(newUser.getId()); IDRequest req = new IDRequest(); req.setId(user.getId()); - try (Response response = getClient().target(getApiBaseUrl() + "admin/user/delete").request().post(Entity.json(req))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - - List newUsers = getAllUsers(); - Assertions.assertEquals(existingUsers.size(), newUsers.size()); - } + getClient().target(getApiBaseUrl() + "admin/user/delete").request().post(Entity.json(req), Void.TYPE); + Assertions.assertEquals(existingUsers.size(), getAllUsers().size()); } @Test void editExistingUser() { List existingUsers = getAllUsers(); - UserModel user = existingUsers.stream().filter(u -> u.getName().equals("admin")).findFirst().get(); + UserModel user = existingUsers.stream() + .filter(u -> u.getName().equals("admin")) + .findFirst() + .orElseThrow(() -> new NullPointerException("User not found")); user.setEmail("new-email@provider.com"); - try (Response response = getClient().target(getApiBaseUrl() + "admin/user/save").request().post(Entity.json(user))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - - List newUsers = getAllUsers(); - Assertions.assertEquals(existingUsers.size(), newUsers.size()); - } + getClient().target(getApiBaseUrl() + "admin/user/save").request().post(Entity.json(user), Void.TYPE); + Assertions.assertEquals(existingUsers.size(), getAllUsers().size()); } private List getAllUsers() { - try (Response response = getClient().target(getApiBaseUrl() + "admin/user/getAll").request().get()) { - return Arrays.asList(response.readEntity(UserModel[].class)); - } + return Arrays.asList(getClient().target(getApiBaseUrl() + "admin/user/getAll").request().get(UserModel[].class)); } } diff --git a/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java b/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java index 277aefaf..ca74a180 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java @@ -40,14 +40,9 @@ class FeedIT extends BaseIT { FeedInfoRequest req = new FeedInfoRequest(); req.setUrl(getFeedUrl()); - try (Response response = getClient().target(getApiBaseUrl() + "feed/fetch").request().post(Entity.json(req))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - - FeedInfo feedInfo = response.readEntity(FeedInfo.class); - Assertions.assertEquals("CommaFeed test feed", feedInfo.getTitle()); - Assertions.assertEquals(getFeedUrl(), feedInfo.getUrl()); - } - + FeedInfo feedInfo = getClient().target(getApiBaseUrl() + "feed/fetch").request().post(Entity.json(req), FeedInfo.class); + Assertions.assertEquals("CommaFeed test feed", feedInfo.getTitle()); + Assertions.assertEquals(getFeedUrl(), feedInfo.getUrl()); } } @@ -110,10 +105,7 @@ class FeedIT extends BaseIT { private void markFeedEntries(long subscriptionId) { MarkRequest request = new MarkRequest(); request.setId(String.valueOf(subscriptionId)); - - try (Response response = getClient().target(getApiBaseUrl() + "feed/mark").request().post(Entity.json(request))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } + getClient().target(getApiBaseUrl() + "feed/mark").request().post(Entity.json(request), Void.TYPE); } } @@ -124,7 +116,9 @@ class FeedIT extends BaseIT { Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); Date now = new Date(); - refreshFeed(subscriptionId); + IDRequest request = new IDRequest(); + request.setId(subscriptionId); + getClient().target(getApiBaseUrl() + "feed/refresh").request().post(Entity.json(request), Void.TYPE); Awaitility.await() .atMost(Duration.ofSeconds(15)) @@ -136,28 +130,12 @@ class FeedIT extends BaseIT { Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); Date now = new Date(); - refreshAllFeeds(); + getClient().target(getApiBaseUrl() + "feed/refreshAll").request().get(Void.TYPE); Awaitility.await() .atMost(Duration.ofSeconds(15)) .until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().after(now)); } - - private void refreshFeed(Long subscriptionId) { - IDRequest request = new IDRequest(); - request.setId(subscriptionId); - - try (Response response = getClient().target(getApiBaseUrl() + "feed/refresh").request().post(Entity.json(request))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } - } - - private void refreshAllFeeds() { - try (Response response = getClient().target(getApiBaseUrl() + "feed/refreshAll").request().get()) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } - } - } @Nested @@ -172,9 +150,7 @@ class FeedIT extends BaseIT { req.setId(subscriptionId); req.setName("new name"); req.setCategoryId(subscription.getCategoryId()); - try (Response response = getClient().target(getApiBaseUrl() + "feed/modify").request().post(Entity.json(req))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } + getClient().target(getApiBaseUrl() + "feed/modify").request().post(Entity.json(req), Void.TYPE); subscription = getSubscription(subscriptionId); Assertions.assertEquals("new name", subscription.getName()); @@ -187,25 +163,21 @@ class FeedIT extends BaseIT { void favicon() throws IOException { Long subscriptionId = subscribe(getFeedUrl()); - try (Response response = getClient().target(getApiBaseUrl() + "feed/favicon/{id}") + byte[] icon = getClient().target(getApiBaseUrl() + "feed/favicon/{id}") .resolveTemplate("id", subscriptionId) .request() - .get()) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - byte[] icon = response.readEntity(byte[].class); - - byte[] defaultFavicon = IOUtils.toByteArray(Objects.requireNonNull(getClass().getResource("/images/default_favicon.gif"))); - Assertions.assertArrayEquals(defaultFavicon, icon); - } + .get(byte[].class); + byte[] defaultFavicon = IOUtils.toByteArray(Objects.requireNonNull(getClass().getResource("/images/default_favicon.gif"))); + Assertions.assertArrayEquals(defaultFavicon, icon); } } @Nested class Opml { @Test - void importExportOpml() throws IOException { + void importExportOpml() { importOpml(); - String opml = exportOpml(); + String opml = getClient().target(getApiBaseUrl() + "feed/export").request().get(String.class); String expextedOpml = "\n" + "\n" + " \n" + " admin subscriptions in CommaFeed\n" + " \n" + " \n" + " \n" @@ -219,18 +191,9 @@ class FeedIT extends BaseIT { MultiPart multiPart = new MultiPart().bodyPart(new StreamDataBodyPart("file", stream)); multiPart.setMediaType(MediaType.MULTIPART_FORM_DATA_TYPE); - try (Response response = getClient().target(getApiBaseUrl() + "feed/import") + getClient().target(getApiBaseUrl() + "feed/import") .request() - .post(Entity.entity(multiPart, multiPart.getMediaType()))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } - } - - String exportOpml() { - try (Response response = getClient().target(getApiBaseUrl() + "feed/export").request().get()) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - return response.readEntity(String.class); - } + .post(Entity.entity(multiPart, multiPart.getMediaType()), Void.TYPE); } } diff --git a/commafeed-server/src/test/java/com/commafeed/integration/rest/FeverIT.java b/commafeed-server/src/test/java/com/commafeed/integration/rest/FeverIT.java index 5ad0b2a1..ea7189df 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/rest/FeverIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/rest/FeverIT.java @@ -2,10 +2,8 @@ package com.commafeed.integration.rest; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Form; -import javax.ws.rs.core.Response; import org.apache.commons.codec.digest.DigestUtils; -import org.eclipse.jetty.http.HttpStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,9 +24,7 @@ class FeverIT extends BaseIT { ProfileModificationRequest req = new ProfileModificationRequest(); req.setCurrentPassword("admin"); req.setNewApiKey(true); - try (Response response = getClient().target(getApiBaseUrl() + "user/profile").request().post(Entity.json(req))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } + getClient().target(getApiBaseUrl() + "user/profile").request().post(Entity.json(req), Void.TYPE); // retrieve api key UserModel user = getClient().target(getApiBaseUrl() + "user/profile").request().get(UserModel.class); @@ -38,13 +34,11 @@ class FeverIT extends BaseIT { @Test void get() { - try (Response response = getClient().target(getApiBaseUrl() + "fever/user/${userId}") + String message = getClient().target(getApiBaseUrl() + "fever/user/${userId}") .resolveTemplate("userId", 1) .request() - .get()) { - Assertions.assertEquals("Welcome to the CommaFeed Fever API. Add this URL to your Fever-compatible reader.", - response.readEntity(String.class)); - } + .get(String.class); + Assertions.assertEquals("Welcome to the CommaFeed Fever API. Add this URL to your Fever-compatible reader.", message); } @Test @@ -81,12 +75,9 @@ class FeverIT extends BaseIT { Form form = new Form(); form.param("api_key", DigestUtils.md5Hex("admin:" + apiKey)); form.param(what, "1"); - try (Response response = getClient().target(getApiBaseUrl() + "fever/user/{userId}") + return getClient().target(getApiBaseUrl() + "fever/user/{userId}") .resolveTemplate("userId", userId) .request() - .post(Entity.form(form))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - return response.readEntity(FeverResponse.class); - } + .post(Entity.form(form), FeverResponse.class); } } diff --git a/commafeed-server/src/test/java/com/commafeed/integration/servlet/CustomCodeIT.java b/commafeed-server/src/test/java/com/commafeed/integration/servlet/CustomCodeIT.java index 9bfc31ca..e8078a74 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/servlet/CustomCodeIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/servlet/CustomCodeIT.java @@ -4,7 +4,6 @@ import javax.ws.rs.client.Entity; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; -import org.eclipse.jetty.http.HttpStatus; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -16,17 +15,12 @@ class CustomCodeIT extends BaseIT { @Test void test() { // get settings - Settings settings = null; - try (Response response = getClient().target(getApiBaseUrl() + "user/settings").request().get()) { - settings = response.readEntity(Settings.class); - } + Settings settings = getClient().target(getApiBaseUrl() + "user/settings").request().get(Settings.class); // update settings settings.setCustomJs("custom-js"); settings.setCustomCss("custom-css"); - try (Response response = getClient().target(getApiBaseUrl() + "user/settings").request().post(Entity.json(settings))) { - Assertions.assertEquals(HttpStatus.OK_200, response.getStatus()); - } + getClient().target(getApiBaseUrl() + "user/settings").request().post(Entity.json(settings), Void.TYPE); // check custom code servlets String cookie = login(); diff --git a/commafeed-server/src/test/java/com/commafeed/integration/servlet/NextUnreadIT.java b/commafeed-server/src/test/java/com/commafeed/integration/servlet/NextUnreadIT.java index a9d50cf4..da67f8be 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/servlet/NextUnreadIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/servlet/NextUnreadIT.java @@ -14,7 +14,7 @@ class NextUnreadIT extends BaseIT { @Test void test() { - Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); + subscribeAndWaitForEntries(getFeedUrl()); String cookie = login(); Response response = getClient().target(getBaseUrl() + "next") diff --git a/commafeed-server/src/test/resources/config.test.yml b/commafeed-server/src/test/resources/config.test.yml index e5cb3ce6..c6a613d4 100644 --- a/commafeed-server/src/test/resources/config.test.yml +++ b/commafeed-server/src/test/resources/config.test.yml @@ -14,7 +14,7 @@ app: strictPasswordPolicy: true # create a demo account the first time the app starts - createDemoAccount: false + createDemoAccount: true # put your google analytics tracking code here googleAnalyticsTrackingCode: