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 420665b66aab7da35ed481054ed089d634336e71
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Jan 5 14:58:51 2026 +0100

    JAMES-4158 Allow protocols to add their own delegation logic
    
    Because we want to be able to do admin impersonation only on private 
network.
---
 .../org/apache/james/mailbox/Authorizator.java     | 18 ++++++++-
 .../org/apache/james/mailbox/SessionProvider.java  |  2 +
 .../org/apache/james/mailbox/AuthorizatorTest.java | 45 ++++++++++++++++++++++
 .../james/mailbox/store/SessionProviderImpl.java   |  5 +++
 .../james/mailbox/store/StoreMailboxManager.java   |  6 +++
 5 files changed, 75 insertions(+), 1 deletion(-)

diff --git 
a/mailbox/api/src/main/java/org/apache/james/mailbox/Authorizator.java 
b/mailbox/api/src/main/java/org/apache/james/mailbox/Authorizator.java
index 38cd4c40f5..575162f91d 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/Authorizator.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/Authorizator.java
@@ -38,7 +38,17 @@ public interface Authorizator {
     enum AuthorizationState {
         ALLOWED,
         FORBIDDEN,
-        UNKNOWN_USER
+        UNKNOWN_USER;
+
+        static AuthorizationState combine(AuthorizationState a, 
AuthorizationState b) {
+            if (a == AuthorizationState.FORBIDDEN) {
+                return b;
+            }
+            if (a == UNKNOWN_USER && b == ALLOWED) {
+                return b;
+            }
+            return a;
+        }
     }
 
     AuthorizationState canLoginAsOtherUser(Username userId, Username 
otherUserId) throws MailboxException;
@@ -50,5 +60,11 @@ public interface Authorizator {
     default Collection<Username> delegatedUsers(Username username) {
         return ImmutableList.of();
     }
+
+    static Authorizator combine(Authorizator a, Authorizator b) {
+        return (userA, userB) -> AuthorizationState.combine(
+            a.canLoginAsOtherUser(userA, userB),
+            b.canLoginAsOtherUser(userA, userB));
+    }
 }
 
diff --git 
a/mailbox/api/src/main/java/org/apache/james/mailbox/SessionProvider.java 
b/mailbox/api/src/main/java/org/apache/james/mailbox/SessionProvider.java
index 5c8b9ec1b4..c0833462a6 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/SessionProvider.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/SessionProvider.java
@@ -75,4 +75,6 @@ public interface SessionProvider {
      *             when the creation fails for other reasons
      */
     AuthorizationStep authenticate(Username givenUserid);
+
+    SessionProvider withExtraAuthorizator(Authorizator authorizator);
 }
diff --git 
a/mailbox/api/src/test/java/org/apache/james/mailbox/AuthorizatorTest.java 
b/mailbox/api/src/test/java/org/apache/james/mailbox/AuthorizatorTest.java
new file mode 100644
index 0000000000..ab8bdd8b18
--- /dev/null
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/AuthorizatorTest.java
@@ -0,0 +1,45 @@
+/******************************************************************
+ * 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.mailbox;
+
+import static org.apache.james.mailbox.Authorizator.AuthorizationState.ALLOWED;
+import static 
org.apache.james.mailbox.Authorizator.AuthorizationState.FORBIDDEN;
+import static 
org.apache.james.mailbox.Authorizator.AuthorizationState.UNKNOWN_USER;
+
+import org.apache.james.mailbox.Authorizator.AuthorizationState;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+
+class AuthorizatorTest {
+    @Test
+    void combineShouldAggregateResults() {
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(AuthorizationState.combine(ALLOWED, 
ALLOWED)).isEqualTo(ALLOWED);
+            softly.assertThat(AuthorizationState.combine(ALLOWED, 
FORBIDDEN)).isEqualTo(ALLOWED);
+            softly.assertThat(AuthorizationState.combine(FORBIDDEN, 
ALLOWED)).isEqualTo(ALLOWED);
+            softly.assertThat(AuthorizationState.combine(FORBIDDEN, 
FORBIDDEN)).isEqualTo(FORBIDDEN);
+            softly.assertThat(AuthorizationState.combine(UNKNOWN_USER, 
FORBIDDEN)).isEqualTo(UNKNOWN_USER);
+            softly.assertThat(AuthorizationState.combine(FORBIDDEN, 
UNKNOWN_USER)).isEqualTo(UNKNOWN_USER);
+            softly.assertThat(AuthorizationState.combine(UNKNOWN_USER, 
UNKNOWN_USER)).isEqualTo(UNKNOWN_USER);
+            softly.assertThat(AuthorizationState.combine(UNKNOWN_USER, 
ALLOWED)).isEqualTo(ALLOWED);
+            softly.assertThat(AuthorizationState.combine(ALLOWED, 
UNKNOWN_USER)).isEqualTo(ALLOWED);
+        });
+    }
+}
diff --git 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/SessionProviderImpl.java
 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/SessionProviderImpl.java
index b0eea7c0a3..9a250499eb 100644
--- 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/SessionProviderImpl.java
+++ 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/SessionProviderImpl.java
@@ -148,4 +148,9 @@ public class SessionProviderImpl implements SessionProvider 
{
     private Optional<Username> isValidLogin(Username userid, String passwd) 
throws MailboxException {
         return authenticator.isAuthentic(userid, passwd);
     }
+
+    @Override
+    public SessionProvider withExtraAuthorizator(Authorizator authorizator) {
+        return new SessionProviderImpl(authenticator, 
Authorizator.combine(this.authorizator, authorizator));
+    }
 }
diff --git 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 02daa0eb21..16bf7c12cd 100644
--- 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -37,6 +37,7 @@ import org.apache.james.core.Username;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.events.EventBus;
+import org.apache.james.mailbox.Authorizator;
 import org.apache.james.mailbox.DefaultMailboxes;
 import org.apache.james.mailbox.MailboxAnnotationManager;
 import org.apache.james.mailbox.MailboxManager;
@@ -250,6 +251,11 @@ public class StoreMailboxManager implements MailboxManager 
{
         return sessionProvider.authenticate(givenUserid, passwd);
     }
 
+    @Override
+    public SessionProvider withExtraAuthorizator(Authorizator authorizator) {
+        return sessionProvider.withExtraAuthorizator(authorizator);
+    }
+
     @Override
     public AuthorizationStep authenticate(Username givenUserid) {
         return sessionProvider.authenticate(givenUserid);


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

Reply via email to