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

zhouky pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new ced6f93bc [CELEBORN-1212] Support for Anonymous SASL Mechanism
ced6f93bc is described below

commit ced6f93bc1174b53ae87827482b1907ae10ee7d5
Author: Chandni Singh <[email protected]>
AuthorDate: Sat Jan 6 20:16:23 2024 +0800

    [CELEBORN-1212] Support for Anonymous SASL Mechanism
    
    ### What changes were proposed in this pull request?
    This adds support for ANONYMOUS Sasl Mechanism.
    
    ### Why are the changes needed?
    The changes are needed for adding authentication to Celeborn. See 
[CELEBORN-1011](https://issues.apache.org/jira/browse/CELEBORN-1011).
    
    ### Does this PR introduce _any_ user-facing change?
    No
    
    ### How was this patch tested?
    Added UT.
    
    Closes #2210 from otterc/CELEBORN-1212.
    
    Lead-authored-by: Chandni Singh <[email protected]>
    Co-authored-by: otterc <[email protected]>
    Signed-off-by: zky.zhoukeyong <[email protected]>
---
 .../common/network/sasl/CelebornSaslClient.java    |   1 +
 .../common/network/sasl/CelebornSaslServer.java    |   1 +
 .../celeborn/common/network/sasl/SaslUtils.java    |   8 ++
 .../sasl/anonymous/AnonymousSaslClientFactory.java | 121 +++++++++++++++++++++
 .../sasl/anonymous/AnonymousSaslProvider.java      |  49 +++++++++
 .../sasl/anonymous/AnonymousSaslServerFactory.java | 115 ++++++++++++++++++++
 .../common/network/sasl/CelebornSaslSuiteJ.java    |  21 ++++
 7 files changed, 316 insertions(+)

diff --git 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslClient.java
 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslClient.java
index 96a3ee39a..c04150e55 100644
--- 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslClient.java
+++ 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslClient.java
@@ -58,6 +58,7 @@ public class CelebornSaslClient {
       @Nullable Map<String, String> saslProps,
       @Nullable CallbackHandler authCallbackHandler) {
     Preconditions.checkNotNull(saslMechanism);
+    initializeSaslProviders();
     try {
       this.saslClient =
           Sasl.createSaslClient(
diff --git 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslServer.java
 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslServer.java
index 7248a3389..bc2354f05 100644
--- 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslServer.java
+++ 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/CelebornSaslServer.java
@@ -52,6 +52,7 @@ public class CelebornSaslServer {
       @Nullable Map<String, String> saslProps,
       @Nullable CallbackHandler callbackHandler) {
     Preconditions.checkNotNull(saslMechanism);
+    initializeSaslProviders();
     try {
       this.saslServer =
           Sasl.createSaslServer(saslMechanism, null, DEFAULT_REALM, saslProps, 
callbackHandler);
diff --git 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/SaslUtils.java 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/SaslUtils.java
index 75a20ee37..374543499 100644
--- 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/SaslUtils.java
+++ 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/SaslUtils.java
@@ -26,12 +26,16 @@ import javax.security.sasl.Sasl;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 
+import org.apache.celeborn.common.network.sasl.anonymous.AnonymousSaslProvider;
+
 public class SaslUtils {
   static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
   /** Sasl Mechanisms */
   static final String DIGEST_MD5 = "DIGEST-MD5";
 
+  public static final String ANONYMOUS = "ANONYMOUS";
+
   /** Quality of protection value that does not include encryption. */
   static final String QOP_AUTH = "auth";
 
@@ -66,4 +70,8 @@ public class SaslUtils {
         .encodeToString(password.getBytes(StandardCharsets.UTF_8))
         .toCharArray();
   }
+
+  static void initializeSaslProviders() {
+    AnonymousSaslProvider.initializeIfNeeded();
+  }
 }
diff --git 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslClientFactory.java
 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslClientFactory.java
new file mode 100644
index 000000000..6deeb52e0
--- /dev/null
+++ 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslClientFactory.java
@@ -0,0 +1,121 @@
+/*
+ * 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.celeborn.common.network.sasl.anonymous;
+
+import static org.apache.celeborn.common.network.sasl.SaslUtils.*;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslClientFactory;
+import javax.security.sasl.SaslException;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * This implements the {@code SaslClientFactory} for the ANONYMOUS SASL 
mechanism. It allows the
+ * creation of SASL clients that can perform ANONYMOUS authentication with a 
remote server.
+ */
+public class AnonymousSaslClientFactory implements SaslClientFactory {
+
+  /**
+   * Creates a SASL client for the ANONYMOUS mechanism.
+   *
+   * @param mechanisms The list of SASL mechanisms.
+   * @param authorizationId The authorization ID, typically null for ANONYMOUS.
+   * @param protocol The name of the protocol being used.
+   * @param serverName The name of the server.
+   * @param props A map of properties to configure the SASL client.
+   * @param cbh A callback handler for handling challenges.
+   * @return A {@code CelebornAnonymousSaslClient} instance if ANONYMOUS is 
requested, or null
+   *     otherwise.
+   * @throws SaslException
+   */
+  @Override
+  public SaslClient createSaslClient(
+      String[] mechanisms,
+      String authorizationId,
+      String protocol,
+      String serverName,
+      Map<String, ?> props,
+      CallbackHandler cbh)
+      throws SaslException {
+    Preconditions.checkNotNull(mechanisms);
+    for (String mech : mechanisms) {
+      if (mech.equals(ANONYMOUS)) {
+        return new CelebornAnonymousSaslClient();
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public String[] getMechanismNames(Map<String, ?> props) {
+    return new String[] {ANONYMOUS};
+  }
+
+  class CelebornAnonymousSaslClient implements SaslClient {
+
+    private boolean isCompleted = false;
+
+    @Override
+    public String getMechanismName() {
+      return ANONYMOUS;
+    }
+
+    @Override
+    public boolean hasInitialResponse() {
+      return false;
+    }
+
+    @Override
+    public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
+      if (isCompleted) {
+        throw new IllegalStateException("Authentication has already 
completed.");
+      }
+      isCompleted = true;
+      return ANONYMOUS.getBytes();
+    }
+
+    @Override
+    public boolean isComplete() {
+      return isCompleted;
+    }
+
+    @Override
+    public byte[] unwrap(byte[] incoming, int offset, int len) throws 
SaslException {
+      throw new IllegalStateException("ANONYMOUS mechanism does not support 
wrap/unwrap");
+    }
+
+    @Override
+    public byte[] wrap(byte[] outgoing, int offset, int len) throws 
SaslException {
+      throw new IllegalStateException("ANONYMOUS mechanism does not support 
wrap/unwrap");
+    }
+
+    @Override
+    public Object getNegotiatedProperty(String propName) {
+      return null;
+    }
+
+    @Override
+    public void dispose() throws SaslException {
+      // No resources to cleanup for ANONYMOUS
+    }
+  }
+}
diff --git 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslProvider.java
 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslProvider.java
new file mode 100644
index 000000000..2fe35a7c7
--- /dev/null
+++ 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslProvider.java
@@ -0,0 +1,49 @@
+/*
+ * 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.celeborn.common.network.sasl.anonymous;
+
+import static org.apache.celeborn.common.network.sasl.SaslUtils.*;
+
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * This is a Java Security Provider that adds support for the ANONYMOUS SASL 
mechanism. It allows
+ * for the registration of SASL client and server factories for ANONYMOUS 
authentication.
+ *
+ * <p>This provider registers the necessary SASL factories to enable ANONYMOUS 
SASL mechanism
+ * authentication.
+ */
+public final class AnonymousSaslProvider extends Provider {
+
+  private static boolean init = false;
+
+  private AnonymousSaslProvider() {
+    super("AnonymousSasl", 1.0, "ANONYMOUS SASL MECHANISM PROVIDER");
+    put("SaslClientFactory." + ANONYMOUS, 
AnonymousSaslClientFactory.class.getName());
+    put("SaslServerFactory." + ANONYMOUS, 
AnonymousSaslServerFactory.class.getName());
+  }
+
+  public static synchronized void initializeIfNeeded() {
+    if (!init) {
+      AnonymousSaslProvider provider = new AnonymousSaslProvider();
+      Security.addProvider(provider);
+      init = true;
+    }
+  }
+}
diff --git 
a/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslServerFactory.java
 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslServerFactory.java
new file mode 100644
index 000000000..9a025f975
--- /dev/null
+++ 
b/common/src/main/java/org/apache/celeborn/common/network/sasl/anonymous/AnonymousSaslServerFactory.java
@@ -0,0 +1,115 @@
+/*
+ * 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.celeborn.common.network.sasl.anonymous;
+
+import static org.apache.celeborn.common.network.sasl.SaslUtils.*;
+
+import java.util.Map;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.security.sasl.SaslServerFactory;
+
+/**
+ * This implements the {@code SaslServerFactory} interface for the ANONYMOUS 
SASL mechanism. It
+ * allows the creation of SASL servers that can handle ANONYMOUS 
authentication requests from
+ * clients.
+ */
+public class AnonymousSaslServerFactory implements SaslServerFactory {
+
+  /**
+   * Creates a SASL server for the ANONYMOUS mechanism.
+   *
+   * @param mechanism The requested SASL mechanism (e.g., ANONYMOUS).
+   * @param protocol The name of the protocol being used.
+   * @param serverName The name of the server.
+   * @param props A map of properties to configure the SASL server.
+   * @param cbh A callback handler for handling authentication callbacks.
+   * @return A {@code CelebornAnonymousSaslServer} instance if ANONYMOUS is 
requested, or null
+   *     otherwise.
+   * @throws SaslException
+   */
+  @Override
+  public SaslServer createSaslServer(
+      String mechanism,
+      String protocol,
+      String serverName,
+      Map<String, ?> props,
+      CallbackHandler cbh)
+      throws SaslException {
+    if (mechanism.equals(ANONYMOUS)) {
+      return new CelebornAnonymousSaslServer();
+    }
+    return null;
+  }
+
+  @Override
+  public String[] getMechanismNames(Map<String, ?> props) {
+    return new String[] {ANONYMOUS};
+  }
+
+  class CelebornAnonymousSaslServer implements SaslServer {
+    private boolean isCompleted = false;
+
+    @Override
+    public String getMechanismName() {
+      return ANONYMOUS;
+    }
+
+    @Override
+    public byte[] evaluateResponse(byte[] response) throws SaslException {
+      if (isCompleted) {
+        throw new IllegalStateException("Authentication has already 
completed.");
+      }
+      // Typically, we would process the response here. For ANONYMOUS, we just 
accept it.
+      isCompleted = true;
+      return new byte[0]; // No challenge is expected for ANONYMOUS.
+    }
+
+    @Override
+    public boolean isComplete() {
+      return isCompleted;
+    }
+
+    @Override
+    public String getAuthorizationID() {
+      return ANONYMOUS;
+    }
+
+    @Override
+    public byte[] unwrap(byte[] incoming, int offset, int len) {
+      throw new IllegalStateException("ANONYMOUS mechanism does not support 
wrap/unwrap");
+    }
+
+    @Override
+    public byte[] wrap(byte[] outgoing, int offset, int len) {
+      throw new IllegalStateException("ANONYMOUS mechanism does not support 
wrap/unwrap");
+    }
+
+    @Override
+    public Object getNegotiatedProperty(String propName) {
+      return null;
+    }
+
+    @Override
+    public void dispose() {
+      // Cleanup resources if any.
+    }
+  }
+}
diff --git 
a/common/src/test/java/org/apache/celeborn/common/network/sasl/CelebornSaslSuiteJ.java
 
b/common/src/test/java/org/apache/celeborn/common/network/sasl/CelebornSaslSuiteJ.java
index 10ed9851e..60ff875ed 100644
--- 
a/common/src/test/java/org/apache/celeborn/common/network/sasl/CelebornSaslSuiteJ.java
+++ 
b/common/src/test/java/org/apache/celeborn/common/network/sasl/CelebornSaslSuiteJ.java
@@ -168,6 +168,27 @@ public class CelebornSaslSuiteJ {
     verify(handler).exceptionCaught(isNull(), isNull());
   }
 
+  @Test
+  public void testAnonymous() {
+    CelebornSaslClient client = new CelebornSaslClient(ANONYMOUS, null, null);
+    CelebornSaslServer server = new CelebornSaslServer(ANONYMOUS, null, null);
+
+    assertFalse(client.isComplete());
+    assertFalse(server.isComplete());
+
+    byte[] clientMessage = client.firstToken();
+    while (!client.isComplete()) {
+      clientMessage = client.response(server.response(clientMessage));
+    }
+    assertTrue(server.isComplete());
+
+    // Disposal should invalidate
+    server.dispose();
+    assertFalse(server.isComplete());
+    client.dispose();
+    assertFalse(client.isComplete());
+  }
+
   private static class SaslTestCtx implements AutoCloseable {
 
     final TransportClient client;

Reply via email to