This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c845dfe8bd2f7e1447386f4f36a8412b2d484a2f
Author: Gautier DI FOLCO <[email protected]>
AuthorDate: Thu Feb 13 12:57:46 2020 +0100

    JAMES-3066 Add allowed From headers list route in WebAdmin
---
 .../apache/james/webadmin/routes/UserRoutes.java   | 62 +++++++++++++-
 .../apache/james/webadmin/service/UserService.java | 13 +++
 .../james/webadmin/routes/UserRoutesTest.java      | 96 +++++++++++++++++++++-
 src/site/markdown/server/manage-webadmin.md        | 19 +++++
 4 files changed, 186 insertions(+), 4 deletions(-)

diff --git 
a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
 
b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
index 6d3b641..d0b78ee 100644
--- 
a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/UserRoutes.java
@@ -22,6 +22,8 @@ package org.apache.james.webadmin.routes;
 import static org.apache.james.webadmin.Constants.SEPARATOR;
 import static spark.Spark.halt;
 
+import java.util.List;
+
 import javax.inject.Inject;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -29,7 +31,11 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 
+import org.apache.james.core.MailAddress;
 import org.apache.james.core.Username;
+import org.apache.james.rrt.api.CanSendFrom;
+import org.apache.james.rrt.api.RecipientRewriteTable;
+import org.apache.james.rrt.api.RecipientRewriteTableException;
 import org.apache.james.user.api.InvalidUsernameException;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.webadmin.Routes;
@@ -46,6 +52,8 @@ import org.eclipse.jetty.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.steveash.guavate.Guavate;
+
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -69,14 +77,16 @@ public class UserRoutes implements Routes {
 
     private final UserService userService;
     private final JsonTransformer jsonTransformer;
+    private final CanSendFrom canSendFrom;
     private final JsonExtractor<AddUserRequest> jsonExtractor;
 
     private Service service;
 
     @Inject
-    public UserRoutes(UserService userService, JsonTransformer 
jsonTransformer) {
+    public UserRoutes(UserService userService, CanSendFrom canSendFrom, 
JsonTransformer jsonTransformer) {
         this.userService = userService;
         this.jsonTransformer = jsonTransformer;
+        this.canSendFrom = canSendFrom;
         this.jsonExtractor = new JsonExtractor<>(AddUserRequest.class);
     }
 
@@ -94,6 +104,8 @@ public class UserRoutes implements Routes {
         defineCreateUser();
 
         defineDeleteUser();
+
+        defineAllowedFromHeaders();
     }
 
     @DELETE
@@ -142,6 +154,25 @@ public class UserRoutes implements Routes {
             jsonTransformer);
     }
 
+    @GET
+    @Path("/{username}/allowedFromHeaders")
+    @ApiOperation(value = "List all possible From header value for an existing 
user")
+    @ApiImplicitParams({
+        @ApiImplicitParam(required = true, dataType = "string", name = 
"username", paramType = "path")
+    })
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK.", 
response = List.class),
+        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "user is not 
valid."),
+        @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "user does not 
exist."),
+        @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
+            message = "Internal server error - Something went bad on the 
server side.")
+    })
+    public void defineAllowedFromHeaders() {
+        service.get(USERS + SEPARATOR + USER_NAME + SEPARATOR + 
"allowedFromHeaders",
+            this::allowedFromHeaders,
+            jsonTransformer);
+    }
+
     private String removeUser(Request request, Response response) {
         Username username = extractUsername(request);
         try {
@@ -184,6 +215,35 @@ public class UserRoutes implements Routes {
         }
     }
 
+    private List<String> allowedFromHeaders(Request request, Response 
response) {
+        Username username = extractUsername(request);
+
+        try {
+            if (!userService.existUser(username)) {
+                LOGGER.info("allowed From headers on an unknown user: '{}", 
username.asString());
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.NOT_FOUND_404)
+                    .type(ErrorType.INVALID_ARGUMENT)
+                    .message("user '" + username.asString() + "' does not 
exist")
+                    .haltError();
+            }
+
+            return canSendFrom
+                .allValidFromAddressesForUser(username)
+                .map(MailAddress::asString)
+                .collect(Guavate.toImmutableList());
+        } catch (RecipientRewriteTable.ErrorMappingException | 
RecipientRewriteTableException | UsersRepositoryException e) {
+            String errorMessage = String.format("Error while listing allowed 
From headers for user '%s'", username);
+            LOGGER.info(errorMessage, e);
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
+                .type(ErrorType.SERVER_ERROR)
+                .message(errorMessage)
+                .cause(e)
+                .haltError();
+        }
+    }
+
     private Username extractUsername(Request request) {
         return Username.of(request.params(USER_NAME));
     }
diff --git 
a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
 
b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
index 78501da..cd36afb 100644
--- 
a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
+++ 
b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/service/UserService.java
@@ -24,6 +24,7 @@ import java.util.Optional;
 import java.util.stream.Stream;
 
 import javax.inject.Inject;
+import javax.mail.internet.AddressException;
 
 import org.apache.james.core.Username;
 import org.apache.james.user.api.UsersRepository;
@@ -31,11 +32,15 @@ import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
 import org.apache.james.util.streams.Iterators;
 import org.apache.james.webadmin.dto.UserResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.github.steveash.guavate.Guavate;
 
 public class UserService {
 
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(UserService.class);
+
     private final UsersRepository usersRepository;
 
     @Inject
@@ -61,6 +66,14 @@ public class UserService {
         upsert(user, username, password);
     }
 
+    public boolean existUser(Username username) throws 
UsersRepositoryException {
+        try {
+            return 
usersRepository.contains(usersRepository.getUser(username.asMailAddress()));
+        } catch (AddressException e) {
+            LOGGER.info("Unable to parse address '%s'", username.asString(), 
e);
+            return false;
+        }
+    }
 
     private void upsert(User user, Username username, char[] password) throws 
UsersRepositoryException {
         if (user == null) {
diff --git 
a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
 
b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
index 89112c7..db1dba9 100644
--- 
a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/UserRoutesTest.java
@@ -22,6 +22,7 @@ package org.apache.james.webadmin.routes;
 import static io.restassured.RestAssured.given;
 import static io.restassured.RestAssured.when;
 import static io.restassured.RestAssured.with;
+import static org.apache.james.webadmin.Constants.SEPARATOR;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +40,12 @@ import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainListException;
 import org.apache.james.domainlist.api.mock.SimpleDomainList;
+import org.apache.james.rrt.api.CanSendFrom;
+import org.apache.james.rrt.api.RecipientRewriteTable;
+import org.apache.james.rrt.api.RecipientRewriteTableException;
+import org.apache.james.rrt.lib.CanSendFromImpl;
+import org.apache.james.rrt.lib.MappingSource;
+import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
@@ -90,12 +97,17 @@ class UserRoutesTest {
 
         final MemoryUsersRepository usersRepository;
         final SimpleDomainList domainList;
+        final MemoryRecipientRewriteTable recipientRewriteTable;
+        final CanSendFrom canSendFrom;
 
         WebAdminServer webAdminServer;
 
         UserRoutesExtension(MemoryUsersRepository usersRepository, 
SimpleDomainList domainList) {
             this.usersRepository = spy(usersRepository);
             this.domainList = domainList;
+            this.recipientRewriteTable = new MemoryRecipientRewriteTable();
+            this.recipientRewriteTable.setDomainList(domainList);
+            this.canSendFrom = new CanSendFromImpl(recipientRewriteTable);
         }
 
         @Override
@@ -112,16 +124,25 @@ class UserRoutesTest {
         public boolean supportsParameter(ParameterContext parameterContext, 
ExtensionContext extensionContext) throws ParameterResolutionException {
             return parameterContext.getParameter()
                 .getType()
-                .isAssignableFrom(UsersRepository.class);
+                .isAssignableFrom(UsersRepository.class)
+                || parameterContext.getParameter()
+                .getType()
+                .isAssignableFrom(RecipientRewriteTable.class);
         }
 
         @Override
         public Object resolveParameter(ParameterContext parameterContext, 
ExtensionContext extensionContext) throws ParameterResolutionException {
-            return usersRepository;
+            if 
(parameterContext.getParameter().getType().isAssignableFrom(UsersRepository.class))
 {
+                return usersRepository;
+            }
+            if 
(parameterContext.getParameter().getType().isAssignableFrom(RecipientRewriteTable.class))
 {
+                return recipientRewriteTable;
+            }
+            throw new RuntimeException("Unknown parameter type: " + 
parameterContext.getParameter().getType());
         }
 
         private WebAdminServer startServer(UsersRepository usersRepository) {
-            WebAdminServer server = WebAdminUtils.createWebAdminServer(new 
UserRoutes(new UserService(usersRepository), new JsonTransformer()))
+            WebAdminServer server = WebAdminUtils.createWebAdminServer(new 
UserRoutes(new UserService(usersRepository), canSendFrom, new 
JsonTransformer()))
                 .start();
 
             RestAssured.requestSpecification = 
WebAdminUtils.buildRequestSpecification(server)
@@ -573,6 +594,75 @@ class UserRoutesTest {
                 .statusCode(HttpStatus.NO_CONTENT_204);
         }
 
+        @Test
+        void allowedFromHeadersShouldHaveUsersMailAddress() {
+            // Given
+            with()
+                .body("{\"password\":\"password\"}")
+                .put(USERNAME_WITH_DOMAIN.asString());
+
+            // Then
+            List<String> allowedFroms =
+                when()
+                    .get(USERNAME_WITH_DOMAIN.asString() + SEPARATOR + 
"allowedFromHeaders")
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .body()
+                    .jsonPath()
+                    .getList(".");
+
+            
assertThat(allowedFroms).containsExactly(USERNAME_WITH_DOMAIN.asString());
+        }
+
+        @Test
+        void 
allowedFromHeadersShouldHaveAllMailAddressesWhenAliasAdded(RecipientRewriteTable
 recipientRewriteTable) throws RecipientRewriteTableException {
+            // Given
+            with()
+                .body("{\"password\":\"password\"}")
+                .put(USERNAME_WITH_DOMAIN.asString());
+
+            String aliasAddress = "alias@" + DOMAIN.asString();
+            
recipientRewriteTable.addAliasMapping(MappingSource.fromUser(Username.of(aliasAddress)),
 USERNAME_WITH_DOMAIN.asString());
+
+            // Then
+            List<String> allowedFroms =
+                when()
+                    .get(USERNAME_WITH_DOMAIN.asString() + SEPARATOR + 
"allowedFromHeaders")
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .body()
+                    .jsonPath()
+                    .getList(".");
+
+            
assertThat(allowedFroms).containsExactly(USERNAME_WITH_DOMAIN.asString(), 
aliasAddress);
+        }
+
+        @Test
+        void allowedFromHeadersShouldReturn404WhenUserDoesNotExist() {
+            when()
+                .get(USERNAME_WITH_DOMAIN.asString() + SEPARATOR + 
"allowedFromHeaders")
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404)
+                .body("statusCode", is(HttpStatus.NOT_FOUND_404))
+                .body("type", 
is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                .body("message", is("user 'username@domain' does not exist"));
+        }
+
+        @Test
+        void allowedFromHeadersShouldReturn404WhenUserIsInvalid() {
+            when()
+                .get("@@" + SEPARATOR + "allowedFromHeaders")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .body("statusCode", is(HttpStatus.BAD_REQUEST_400))
+                .body("type", 
is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                .body("message", is("Invalid arguments supplied in the user 
request"));
+        }
+
         @Nested
         class IllegalCharacterErrorHandlingTest implements 
UserRoutesContract.IllegalCharactersErrorHandlingContract {
 
diff --git a/src/site/markdown/server/manage-webadmin.md 
b/src/site/markdown/server/manage-webadmin.md
index b2e0142..76dccc6 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -292,6 +292,7 @@ Response codes:
    - [Updating a user password](#Updating_a_user_password)
    - [Deleting a domain](#Deleting_a_user)
    - [Retrieving the user list](#Retrieving_the_user_list)
+   - [Retrieving the list of allowed `From` headers for a given 
user](Retrieving_the_list_of_allowed_From_headers_for_a_given_user)
 
 ### Create a user
 
@@ -343,6 +344,24 @@ Response codes:
 
  - 200: The user name list was successfully retrieved
 
+### Retrieving the list of allowed `From` headers for a given user
+
+```
+curl -XGET http://ip:port/users/givenUser/allowedFromHeaders
+```
+
+The answer looks like:
+
+```
+["[email protected]","[email protected]"]
+```
+
+Response codes:
+
+ - 200: The list was successfully retrieved
+ - 400: The user is invalid
+ - 404: The user is unknown
+
 ## Administrating mailboxes
 
 ### All mailboxes


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to