| /**************************************************************** |
| * Licensed to the Apache Software Foundation (ASF) under one * |
| * or more contributor license agreements. See the NOTICE file * |
| * distributed with this work for additional information * |
| * regarding copyright ownership. The ASF licenses this file * |
| * to you under the Apache License, Version 2.0 (the * |
| * "License"); you may not use this file except in compliance * |
| * with the License. You may obtain a copy of the License at * |
| * * |
| * http://www.apache.org/licenses/LICENSE-2.0 * |
| * * |
| * Unless required by applicable law or agreed to in writing, * |
| * software distributed under the License is distributed on an * |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * |
| * KIND, either express or implied. See the License for the * |
| * specific language governing permissions and limitations * |
| * under the License. * |
| ****************************************************************/ |
| |
| package org.apache.james.jmap.methods.integration.cucumber; |
| |
| import static org.assertj.core.api.Assertions.assertThat; |
| |
| import java.io.IOException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import javax.inject.Inject; |
| import javax.mail.Flags; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.apache.http.Header; |
| import org.apache.http.HttpResponse; |
| import org.apache.http.client.fluent.Request; |
| import org.apache.http.client.fluent.Response; |
| import org.apache.http.client.utils.URIBuilder; |
| import org.apache.james.jmap.api.access.AccessToken; |
| import org.apache.james.jmap.model.AttachmentAccessToken; |
| import org.apache.james.mailbox.model.MailboxConstants; |
| import org.apache.james.mailbox.model.MailboxPath; |
| |
| import com.google.common.base.Charsets; |
| import com.google.common.base.MoreObjects; |
| import com.google.common.base.Objects; |
| import com.google.common.collect.ArrayListMultimap; |
| import com.google.common.collect.Multimap; |
| |
| import cucumber.api.java.en.Given; |
| import cucumber.api.java.en.Then; |
| import cucumber.api.java.en.When; |
| import cucumber.runtime.java.guice.ScenarioScoped; |
| |
| @ScenarioScoped |
| public class DownloadStepdefs { |
| |
| private static final String ONE_ATTACHMENT_EML_ATTACHEMENT_BLOB_ID = "4000c5145f633410b80be368c44e1c394bff9437"; |
| private static final String EXPIRED_ATTACHMENT_TOKEN = "usera@domain.tld_" |
| + "2016-06-29T13:41:22.124Z_" |
| + "DiZa0O14MjLWrAA8P6MG35Gt5CBp7mt5U1EH/M++rIoZK7nlGJ4dPW0dvZD7h4m3o5b/Yd8DXU5x2x4+s0HOOKzD7X0RMlsU7JHJMNLvTvRGWF/C+MUyC8Zce7DtnRVPEQX2uAZhL2PBABV07Vpa8kH+NxoS9CL955Bc1Obr4G+KN2JorADlocFQA6ElXryF5YS/HPZSvq1MTC6aJIP0ku8WRpRnbwgwJnn26YpcHXcJjbkCBtd9/BhlMV6xNd2hTBkfZmYdoNo+UKBaXWzLxAlbLuxjpxwvDNJfOEyWFPgHDoRvzP+G7KzhVWjanHAHrhF0GilEa/MKpOI1qHBSwA=="; |
| private static final String INVALID_ATTACHMENT_TOKEN = "usera@domain.tld_" |
| + "2015-06-29T13:41:22.124Z_" |
| + "DiZa0O14MjLWrAA8P6MG35Gt5CBp7mt5U1EH/M++rIoZK7nlGJ4dPW0dvZD7h4m3o5b/Yd8DXU5x2x4+s0HOOKzD7X0RMlsU7JHJMNLvTvRGWF/C+MUyC8Zce7DtnRVPEQX2uAZhL2PBABV07Vpa8kH+NxoS9CL955Bc1Obr4G+KN2JorADlocFQA6ElXryF5YS/HPZSvq1MTC6aJIP0ku8WRpRnbwgwJnn26YpcHXcJjbkCBtd9/BhlMV6xNd2hTBkfZmYdoNo+UKBaXWzLxAlbLuxjpxwvDNJfOEyWFPgHDoRvzP+G7KzhVWjanHAHrhF0GilEa/MKpOI1qHBSwA=="; |
| |
| private final UserStepdefs userStepdefs; |
| private final MainStepdefs mainStepdefs; |
| private HttpResponse response; |
| private Multimap<String, String> attachmentsByMessageId; |
| private Map<String, String> blobIdByAttachmentId; |
| private Map<AttachmentAccessTokenKey, AttachmentAccessToken> attachmentAccessTokens; |
| |
| @Inject |
| private DownloadStepdefs(MainStepdefs mainStepdefs, UserStepdefs userStepdefs) { |
| this.mainStepdefs = mainStepdefs; |
| this.userStepdefs = userStepdefs; |
| this.attachmentsByMessageId = ArrayListMultimap.create(); |
| this.blobIdByAttachmentId = new HashMap<>(); |
| this.attachmentAccessTokens = new HashMap<>(); |
| } |
| |
| @Given("^\"([^\"]*)\" mailbox \"([^\"]*)\" contains a message \"([^\"]*)\" with an attachment \"([^\"]*)\"$") |
| public void appendMessageWithAttachmentToMailbox(String user, String mailbox, String messageId, String attachmentId) throws Throwable { |
| MailboxPath mailboxPath = new MailboxPath(MailboxConstants.USER_NAMESPACE, user, mailbox); |
| |
| mainStepdefs.jmapServer.serverProbe().appendMessage(user, mailboxPath, |
| ClassLoader.getSystemResourceAsStream("eml/oneAttachment.eml"), new Date(), false, new Flags()); |
| |
| attachmentsByMessageId.put(messageId, attachmentId); |
| blobIdByAttachmentId.put(attachmentId, "4000c5145f633410b80be368c44e1c394bff9437"); |
| } |
| |
| @Given("^\"([^\"]*)\" mailbox \"([^\"]*)\" contains a message \"([^\"]*)\" with an inlined attachment \"([^\"]*)\"$") |
| public void appendMessageWithInlinedAttachmentToMailbox(String user, String mailbox, String messageId, String attachmentId) throws Throwable { |
| MailboxPath mailboxPath = new MailboxPath(MailboxConstants.USER_NAMESPACE, user, mailbox); |
| |
| mainStepdefs.jmapServer.serverProbe().appendMessage(user, mailboxPath, |
| ClassLoader.getSystemResourceAsStream("eml/oneInlinedImage.eml"), new Date(), false, new Flags()); |
| |
| attachmentsByMessageId.put(messageId, attachmentId); |
| // TODO |
| //blobIdByAttachmentId.put(attachmentId, "<correctComputedBlobId>"); |
| } |
| |
| @When("^\"([^\"]*)\" checks for the availability of the attachment endpoint$") |
| public void optionDownload(String username) throws Throwable { |
| AccessToken accessToken = userStepdefs.tokenByUser.get(username); |
| URI target = mainStepdefs.baseUri().setPath("/download/" + ONE_ATTACHMENT_EML_ATTACHEMENT_BLOB_ID).build(); |
| Request request = Request.Options(target); |
| if (accessToken != null) { |
| request.addHeader("Authorization", accessToken.serialize()); |
| } |
| response = request.execute().returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\"$") |
| public void downloads(String username, String attachmentId) throws Throwable { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| URIBuilder uriBuilder = mainStepdefs.baseUri().setPath("/download/" + blobId); |
| response = authenticatedDownloadRequest(uriBuilder, blobId, username).execute().returnResponse(); |
| } |
| |
| private Request authenticatedDownloadRequest(URIBuilder uriBuilder, String blobId, String username) throws URISyntaxException { |
| AccessToken accessToken = userStepdefs.tokenByUser.get(username); |
| AttachmentAccessTokenKey key = new AttachmentAccessTokenKey(username, blobId); |
| if (attachmentAccessTokens.containsKey(key)) { |
| uriBuilder.addParameter("access_token", attachmentAccessTokens.get(key).serialize()); |
| } |
| Request request = Request.Get(uriBuilder.build()); |
| if (accessToken != null) { |
| request.addHeader("Authorization", accessToken.serialize()); |
| } |
| return request; |
| } |
| |
| @When("^\"([^\"]*)\" is trusted for attachment \"([^\"]*)\"$") |
| public void attachmentAccessTokenFor(String username, String attachmentId) throws Throwable { |
| userStepdefs.connectUser(username); |
| trustForBlobId(blobIdByAttachmentId.get(attachmentId), username); |
| } |
| |
| private static class AttachmentAccessTokenKey { |
| |
| private String username; |
| private String blobId; |
| |
| public AttachmentAccessTokenKey(String username, String blobId) { |
| this.username = username; |
| this.blobId = blobId; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof AttachmentAccessTokenKey) { |
| AttachmentAccessTokenKey other = (AttachmentAccessTokenKey) obj; |
| return Objects.equal(username, other.username) |
| && Objects.equal(blobId, other.blobId); |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hashCode(username, blobId); |
| } |
| |
| @Override |
| public String toString() { |
| return MoreObjects |
| .toStringHelper(this) |
| .add("username", username) |
| .add("blobId", blobId) |
| .toString(); |
| } |
| } |
| |
| private void trustForBlobId(String blobId, String username) throws Exception { |
| Response tokenGenerationResponse = Request.Post(mainStepdefs.baseUri().setPath("/download/" + blobId).build()) |
| .addHeader("Authorization", userStepdefs.tokenByUser.get(username).serialize()) |
| .execute(); |
| String serializedAttachmentAccessToken = tokenGenerationResponse.returnContent().asString(); |
| attachmentAccessTokens.put( |
| new AttachmentAccessTokenKey(username, blobId), |
| AttachmentAccessToken.from( |
| serializedAttachmentAccessToken, |
| blobId)); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with a valid authentication token but a bad blobId$") |
| public void downloadsWithValidToken(String username, String attachmentId) throws Throwable { |
| URIBuilder uriBuilder = mainStepdefs.baseUri().setPath("/download/badblobId"); |
| response = Request.Get(uriBuilder.build()) |
| .addHeader("Authorization", userStepdefs.tokenByUser.get(username).serialize()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" without any authentication token$") |
| public void getDownloadWithoutToken(String username, String attachmentId) throws Exception { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| response = Request.Get(mainStepdefs.baseUri().setPath("/download/" + blobId).build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with an empty authentication token$") |
| public void getDownloadWithEmptyToken(String username, String attachmentId) throws Exception { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| response = Request.Get( |
| mainStepdefs.baseUri() |
| .setPath("/download/" + blobId) |
| .addParameter("access_token", "") |
| .build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with a bad authentication token$") |
| public void getDownloadWithBadToken(String username, String attachmentId) throws Exception { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| response = Request.Get( |
| mainStepdefs.baseUri() |
| .setPath("/download/" + blobId) |
| .addParameter("access_token", "bad") |
| .build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with an invalid authentication token$") |
| public void getDownloadWithUnknownToken(String username, String attachmentId) throws Exception { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| response = Request.Get( |
| mainStepdefs.baseUri() |
| .setPath("/download/" + blobId) |
| .addParameter("access_token", INVALID_ATTACHMENT_TOKEN) |
| .build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" without blobId parameter$") |
| public void getDownloadWithoutBlobId(String username, String attachmentId) throws Throwable { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| |
| URIBuilder uriBuilder = mainStepdefs.baseUri().setPath("/download/"); |
| trustForBlobId(blobId, username); |
| AttachmentAccessTokenKey key = new AttachmentAccessTokenKey(username, blobId); |
| uriBuilder.addParameter("access_token", attachmentAccessTokens.get(key).serialize()); |
| response = Request.Get(uriBuilder.build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with wrong blobId$") |
| public void getDownloadWithWrongBlobId(String username, String attachmentId) throws Throwable { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| |
| URIBuilder uriBuilder = mainStepdefs.baseUri().setPath("/download/badbadbadbadbadbadbadbadbadbadbadbadbadb"); |
| trustForBlobId(blobId, username); |
| AttachmentAccessTokenKey key = new AttachmentAccessTokenKey(username, blobId); |
| uriBuilder.addParameter("access_token", attachmentAccessTokens.get(key).serialize()); |
| response = Request.Get(uriBuilder.build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" asks for a token for attachment \"([^\"]*)\"$") |
| public void postDownload(String username, String attachmentId) throws Throwable { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| AccessToken accessToken = userStepdefs.tokenByUser.get(username); |
| response = Request.Post(mainStepdefs.baseUri().setPath("/download/" + blobId).build()) |
| .addHeader("Authorization", accessToken.serialize()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with \"([^\"]*)\" name$") |
| public void downloadsWithName(String username, String attachmentId, String name) throws Exception { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| URIBuilder uriBuilder = mainStepdefs.baseUri().setPath("/download/" + blobId + "/" + name); |
| response = authenticatedDownloadRequest(uriBuilder, blobId, username) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @When("^\"([^\"]*)\" downloads \"([^\"]*)\" with an expired token$") |
| public void getDownloadWithExpiredToken(String username, String attachmentId) throws Exception { |
| String blobId = blobIdByAttachmentId.get(attachmentId); |
| response = Request.Get(mainStepdefs.baseUri().setPath("/download/" + blobId) |
| .addParameter("access_token", EXPIRED_ATTACHMENT_TOKEN) |
| .build()) |
| .execute() |
| .returnResponse(); |
| } |
| |
| @Then("^the user should be authorized$") |
| public void httpStatusDifferentFromUnauthorized() throws IOException { |
| assertThat(response.getStatusLine().getStatusCode()).isIn(200, 404); |
| } |
| |
| @Then("^the user should not be authorized$") |
| public void httpUnauthorizedStatus() throws IOException { |
| assertThat(response.getStatusLine().getStatusCode()).isEqualTo(401); |
| } |
| |
| @Then("^the user should receive a bad request response$") |
| public void httpBadRequestStatus() throws IOException { |
| assertThat(response.getStatusLine().getStatusCode()).isEqualTo(400); |
| } |
| |
| @Then("^the user should receive that attachment$") |
| public void httpOkStatusAndExpectedContent() throws IOException { |
| assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); |
| assertThat(IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8)).isNotEmpty(); |
| } |
| |
| @Then("^the user should receive a not found response$") |
| public void httpNotFoundStatus() throws IOException { |
| assertThat(response.getStatusLine().getStatusCode()).isEqualTo(404); |
| } |
| |
| @Then("^the user should receive an attachment access token$") |
| public void accessTokenResponse() throws Throwable { |
| assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); |
| assertThat(response.getHeaders("Content-Type")).extracting(Header::toString).containsExactly("Content-Type: text/plain"); |
| assertThat(IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8)).isNotEmpty(); |
| } |
| |
| @Then("^the attachment is named \"([^\"]*)\"$") |
| public void assertContentDisposition(String name) throws IOException { |
| assertThat(response.getHeaders("Content-Disposition")).extracting(Header::toString).containsExactly("Content-Disposition: attachment; filename=\"" + name + "\""); |
| } |
| } |