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;