You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/02/22 02:47:55 UTC

[james-project] 01/03: JAMES-3885 Username change should adapt delegation

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

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

commit 548011f49ec81a7df4590729bdae0646d1d27698
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Feb 20 15:57:42 2023 +0700

    JAMES-3885 Username change should adapt delegation
---
 .../data/CassandraUsersRepositoryModule.java       |  5 ++
 .../modules/data/MemoryUsersRepositoryModule.java  |  7 ++
 .../james/rrt/ForwardUsernameChangeTaskStep.java   |  2 +-
 .../user/api/DelegationUsernameChangeTaskStep.java | 66 ++++++++++++++++++
 .../DelegationUsernameChangeTaskStepTest.java      | 81 ++++++++++++++++++++++
 .../MemoryUsernameChangeIntegrationTest.java       | 21 ++++++
 6 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/server/container/guice/data-cassandra/src/main/java/org/apache/james/modules/data/CassandraUsersRepositoryModule.java b/server/container/guice/data-cassandra/src/main/java/org/apache/james/modules/data/CassandraUsersRepositoryModule.java
index 0f4b3f0906..5f4424f652 100644
--- a/server/container/guice/data-cassandra/src/main/java/org/apache/james/modules/data/CassandraUsersRepositoryModule.java
+++ b/server/container/guice/data-cassandra/src/main/java/org/apache/james/modules/data/CassandraUsersRepositoryModule.java
@@ -25,6 +25,8 @@ import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.mailbox.Authorizator;
 import org.apache.james.server.core.configuration.ConfigurationProvider;
 import org.apache.james.user.api.DelegationStore;
+import org.apache.james.user.api.DelegationUsernameChangeTaskStep;
+import org.apache.james.user.api.UsernameChangeTaskStep;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.cassandra.CassandraDelegationStore;
 import org.apache.james.user.cassandra.CassandraRepositoryConfiguration;
@@ -53,6 +55,9 @@ public class CassandraUsersRepositoryModule extends AbstractModule {
         cassandraDataDefinitions.addBinding().toInstance(org.apache.james.user.cassandra.CassandraUsersRepositoryModule.MODULE);
         bind(DelegationStore.class).to(CassandraDelegationStore.class);
         bind(Authorizator.class).to(DelegationStoreAuthorizator.class);
+
+        Multibinder.newSetBinder(binder(), UsernameChangeTaskStep.class)
+            .addBinding().to(DelegationUsernameChangeTaskStep.class);
     }
 
     @Provides
diff --git a/server/container/guice/memory/src/main/java/org/apache/james/modules/data/MemoryUsersRepositoryModule.java b/server/container/guice/memory/src/main/java/org/apache/james/modules/data/MemoryUsersRepositoryModule.java
index d80f1a30ff..9bf747823d 100644
--- a/server/container/guice/memory/src/main/java/org/apache/james/modules/data/MemoryUsersRepositoryModule.java
+++ b/server/container/guice/memory/src/main/java/org/apache/james/modules/data/MemoryUsersRepositoryModule.java
@@ -23,6 +23,8 @@ import org.apache.james.UserEntityValidator;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.server.core.configuration.ConfigurationProvider;
 import org.apache.james.user.api.DelegationStore;
+import org.apache.james.user.api.DelegationUsernameChangeTaskStep;
+import org.apache.james.user.api.UsernameChangeTaskStep;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.memory.MemoryDelegationStore;
 import org.apache.james.user.memory.MemoryUsersRepository;
@@ -33,6 +35,7 @@ import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.Scopes;
 import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
 import com.google.inject.multibindings.ProvidesIntoSet;
 
 public class MemoryUsersRepositoryModule extends AbstractModule {
@@ -41,6 +44,10 @@ public class MemoryUsersRepositoryModule extends AbstractModule {
         bind(MemoryDelegationStore.class).in(Scopes.SINGLETON);
         bind(UsersRepository.class).to(MemoryUsersRepository.class);
         bind(DelegationStore.class).to(MemoryDelegationStore.class);
+
+
+        Multibinder.newSetBinder(binder(), UsernameChangeTaskStep.class)
+            .addBinding().to(DelegationUsernameChangeTaskStep.class);
     }
 
     @Provides
diff --git a/server/data/data-api/src/main/java/org/apache/james/rrt/ForwardUsernameChangeTaskStep.java b/server/data/data-api/src/main/java/org/apache/james/rrt/ForwardUsernameChangeTaskStep.java
index 2319f24d09..86bc80c83b 100644
--- a/server/data/data-api/src/main/java/org/apache/james/rrt/ForwardUsernameChangeTaskStep.java
+++ b/server/data/data-api/src/main/java/org/apache/james/rrt/ForwardUsernameChangeTaskStep.java
@@ -81,6 +81,6 @@ public class ForwardUsernameChangeTaskStep implements UsernameChangeTaskStep {
 
     @Override
     public int priority() {
-        return 10;
+        return 0;
     }
 }
diff --git a/server/data/data-api/src/main/java/org/apache/james/user/api/DelegationUsernameChangeTaskStep.java b/server/data/data-api/src/main/java/org/apache/james/user/api/DelegationUsernameChangeTaskStep.java
new file mode 100644
index 0000000000..5b2e32438a
--- /dev/null
+++ b/server/data/data-api/src/main/java/org/apache/james/user/api/DelegationUsernameChangeTaskStep.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * 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.user.api;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.Username;
+import org.reactivestreams.Publisher;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class DelegationUsernameChangeTaskStep implements UsernameChangeTaskStep {
+    private final DelegationStore delegationStore;
+
+    @Inject
+    public DelegationUsernameChangeTaskStep(DelegationStore delegationStore) {
+        this.delegationStore = delegationStore;
+    }
+
+    @Override
+    public StepName name() {
+        return new StepName("DelegationUsernameChangeTaskStep");
+    }
+
+    @Override
+    public int priority() {
+        return 1;
+    }
+
+    @Override
+    public Publisher<Void> changeUsername(Username oldUsername, Username newUsername) {
+        return migrateDelegatees(oldUsername, newUsername)
+            .then(migrateDelegators(oldUsername, newUsername));
+    }
+
+    private Mono<Void> migrateDelegators(Username oldUsername, Username newUsername) {
+        return Flux.from(delegationStore.delegatedUsers(oldUsername))
+            .concatMap(delegator -> Mono.from(delegationStore.addAuthorizedUser(delegator, newUsername))
+                .then(Mono.from(delegationStore.removeAuthorizedUser(delegator, oldUsername))))
+            .then();
+    }
+
+    private Flux<Void> migrateDelegatees(Username oldUsername, Username newUsername) {
+        return Flux.from(delegationStore.authorizedUsers(oldUsername))
+            .concatMap(delegatee -> Mono.from(delegationStore.addAuthorizedUser(newUsername, delegatee))
+                .then(Mono.from(delegationStore.removeAuthorizedUser(oldUsername, delegatee))));
+    }
+}
diff --git a/server/data/data-memory/src/test/java/org/apache/james/user/memory/DelegationUsernameChangeTaskStepTest.java b/server/data/data-memory/src/test/java/org/apache/james/user/memory/DelegationUsernameChangeTaskStepTest.java
new file mode 100644
index 0000000000..1ba073e6d2
--- /dev/null
+++ b/server/data/data-memory/src/test/java/org/apache/james/user/memory/DelegationUsernameChangeTaskStepTest.java
@@ -0,0 +1,81 @@
+/****************************************************************
+ * 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.user.memory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.james.core.Username;
+import org.apache.james.user.api.DelegationUsernameChangeTaskStep;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+class DelegationUsernameChangeTaskStepTest {
+    private static final Username ALICE_OLD = Username.of("alice-old@domain.tld");
+    private static final Username ALICE_NEW = Username.of("alice-new@domain.tld");
+    private static final Username BOB = Username.of("bob@domain.tld");
+
+    private MemoryDelegationStore delegationStore;
+    private DelegationUsernameChangeTaskStep testee;
+
+    @BeforeEach
+    void setUp() {
+        delegationStore = new MemoryDelegationStore();
+        testee = new DelegationUsernameChangeTaskStep(delegationStore);
+    }
+
+    @Test
+    void shouldMigrateDelegationToNewUser() {
+        Mono.from(delegationStore.addAuthorizedUser(BOB)
+            .forUser(ALICE_OLD))
+            .block();
+
+        Mono.from(testee.changeUsername(ALICE_OLD, ALICE_NEW)).block();
+
+        assertThat(Flux.from(delegationStore.authorizedUsers(ALICE_NEW)).collectList().block())
+            .containsOnly(BOB);
+    }
+
+    @Test
+    void shouldRemoveDelegationForOldUser() {
+        Mono.from(delegationStore.addAuthorizedUser(BOB)
+            .forUser(ALICE_OLD))
+            .block();
+
+        Mono.from(testee.changeUsername(ALICE_OLD, ALICE_NEW)).block();
+
+        assertThat(Flux.from(delegationStore.authorizedUsers(ALICE_OLD)).collectList().block())
+            .isEmpty();
+    }
+
+    @Test
+    void shouldMigrateChangesForDelegators() {
+        Mono.from(delegationStore.addAuthorizedUser(ALICE_OLD)
+            .forUser(BOB))
+            .block();
+
+        Mono.from(testee.changeUsername(ALICE_OLD, ALICE_NEW)).block();
+
+        assertThat(Flux.from(delegationStore.authorizedUsers(BOB)).collectList().block())
+            .containsOnly(ALICE_NEW);
+    }
+}
diff --git a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryUsernameChangeIntegrationTest.java b/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryUsernameChangeIntegrationTest.java
index f4c8a91aef..a16b75b904 100644
--- a/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryUsernameChangeIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/memory-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/memory/MemoryUsernameChangeIntegrationTest.java
@@ -105,4 +105,25 @@ class MemoryUsernameChangeIntegrationTest {
             .body(".", hasSize(1))
             .body("[0].mailAddress", is(BOB.asString()));
     }
+
+    @Test
+    void shouldAdaptDelegation() {
+        webAdminApi.put("/users/" + ALICE.asString() + "/authorizedUsers/" + CEDRIC.asString());
+
+        String taskId = webAdminApi
+            .queryParam("action", "rename")
+            .post("/users/" + ALICE.asString() + "/rename/" + BOB.asString())
+            .jsonPath()
+            .get("taskId");
+
+        webAdminApi.get("/tasks/" + taskId + "/await");
+
+        webAdminApi.get("/users/" + ALICE.asString() + "/authorizedUsers")
+            .then()
+                .body(".", hasSize(0));
+        webAdminApi.get("/users/" + BOB.asString() + "/authorizedUsers")
+            .then()
+                .body(".", hasSize(1))
+                .body("[0]", is(CEDRIC.asString()));
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org