-
Notifications
You must be signed in to change notification settings - Fork 9.2k
HDFS-17606. Do not require implementing CustomizedCallbackHandler. #7005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,25 +20,45 @@ | |
| import org.apache.hadoop.conf.Configuration; | ||
| import org.apache.hadoop.hdfs.client.HdfsClientConfigKeys; | ||
| import org.apache.hadoop.hdfs.protocol.datatransfer.sasl.SaslDataTransferServer.SaslServerCallbackHandler; | ||
| import org.apache.hadoop.test.LambdaTestUtils; | ||
| import org.junit.Assert; | ||
| import org.junit.Test; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import javax.security.auth.callback.Callback; | ||
| import javax.security.auth.callback.UnsupportedCallbackException; | ||
| import java.util.Arrays; | ||
| import java.io.IOException; | ||
| import java.util.List; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
|
|
||
| /** For testing {@link CustomizedCallbackHandler}. */ | ||
| public class TestCustomizedCallbackHandler { | ||
| public static final Logger LOG = LoggerFactory.getLogger(TestCustomizedCallbackHandler.class); | ||
| static final Logger LOG = LoggerFactory.getLogger(TestCustomizedCallbackHandler.class); | ||
|
|
||
| static final AtomicReference<List<Callback>> LAST_CALLBACKS = new AtomicReference<>(); | ||
|
|
||
| static void runHandleCallbacks(Object caller, List<Callback> callbacks, String name) { | ||
| LOG.info("{}: handling {} for {}", caller.getClass().getSimpleName(), callbacks, name); | ||
| LAST_CALLBACKS.set(callbacks); | ||
| } | ||
|
|
||
| /** Assert if the callbacks in {@link #LAST_CALLBACKS} are the same as the expected callbacks. */ | ||
| static void assertCallbacks(Callback[] expected) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a javadoc explaining what it does |
||
| final List<Callback> computed = LAST_CALLBACKS.getAndSet(null); | ||
| Assert.assertNotNull(computed); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you could do this in a single AssertJ assertion, especially lines 49-51, provides AssertJ.assertThat(computed)
.describedAs("computed callbacks")
.isNotNull()
.hasSameElementsAs(expected)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried it but |
||
| Assert.assertEquals(expected.length, computed.size()); | ||
| for (int i = 0; i < expected.length; i++) { | ||
| Assert.assertSame(expected[i], computed.get(i)); | ||
| } | ||
| } | ||
|
|
||
| static class MyCallback implements Callback { } | ||
|
|
||
| static class MyCallbackHandler implements CustomizedCallbackHandler { | ||
| @Override | ||
| public void handleCallback(List<Callback> callbacks, String name, char[] password) { | ||
| LOG.info("{}: handling {} for {}", getClass().getSimpleName(), callbacks, name); | ||
| public void handleCallbacks(List<Callback> callbacks, String name, char[] password) { | ||
| runHandleCallbacks(this, callbacks, name); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -48,16 +68,52 @@ public void testCustomizedCallbackHandler() throws Exception { | |
| final Callback[] callbacks = {new MyCallback()}; | ||
|
|
||
| // without setting conf, expect UnsupportedCallbackException | ||
| try { | ||
| new SaslServerCallbackHandler(conf, String::toCharArray).handle(callbacks); | ||
| Assert.fail("Expected UnsupportedCallbackException for " + Arrays.asList(callbacks)); | ||
| } catch (UnsupportedCallbackException e) { | ||
| LOG.info("The failure is expected", e); | ||
| } | ||
| LambdaTestUtils.intercept(UnsupportedCallbackException.class, () -> runTest(conf, callbacks)); | ||
|
|
||
| // set conf and expect success | ||
| conf.setClass(HdfsClientConfigKeys.DFS_DATA_TRANSFER_SASL_CUSTOMIZEDCALLBACKHANDLER_CLASS_KEY, | ||
| MyCallbackHandler.class, CustomizedCallbackHandler.class); | ||
| new SaslServerCallbackHandler(conf, String::toCharArray).handle(callbacks); | ||
| assertCallbacks(callbacks); | ||
| } | ||
|
|
||
| static class MyCallbackMethod { | ||
| public void handleCallbacks(List<Callback> callbacks, String name, char[] password) | ||
| throws UnsupportedCallbackException { | ||
| runHandleCallbacks(this, callbacks, name); | ||
| } | ||
| } | ||
|
|
||
| static class MyExceptionMethod { | ||
| public void handleCallbacks(List<Callback> callbacks, String name, char[] password) | ||
| throws UnsupportedCallbackException { | ||
| runHandleCallbacks(this, callbacks, name); | ||
| throw new UnsupportedCallbackException(callbacks.get(0)); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testCustomizedCallbackMethod() throws Exception { | ||
| final Configuration conf = new Configuration(); | ||
| final Callback[] callbacks = {new MyCallback()}; | ||
|
|
||
| // without setting conf, expect UnsupportedCallbackException | ||
| LambdaTestUtils.intercept(UnsupportedCallbackException.class, () -> runTest(conf, callbacks)); | ||
|
|
||
| // set conf and expect success | ||
| conf.setClass(HdfsClientConfigKeys.DFS_DATA_TRANSFER_SASL_CUSTOMIZEDCALLBACKHANDLER_CLASS_KEY, | ||
| MyCallbackMethod.class, Object.class); | ||
| new SaslServerCallbackHandler(conf, String::toCharArray).handle(callbacks); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a static counter somewhere to verify the callback was actually invoked. add another test to raise an exception in the callback to verify it gets reported.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, will add both. |
||
| assertCallbacks(callbacks); | ||
|
|
||
| // set conf and expect exception | ||
| conf.setClass(HdfsClientConfigKeys.DFS_DATA_TRANSFER_SASL_CUSTOMIZEDCALLBACKHANDLER_CLASS_KEY, | ||
| MyExceptionMethod.class, Object.class); | ||
| LambdaTestUtils.intercept(IOException.class, () -> runTest(conf, callbacks)); | ||
| } | ||
|
|
||
| static void runTest(Configuration conf, Callback... callbacks) | ||
| throws IOException, UnsupportedCallbackException { | ||
| new SaslServerCallbackHandler(conf, String::toCharArray).handle(callbacks); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of last week, DynMethod exists in hadoop common to assist here. Have look to see if it would help or are your needs better. A key aspect is can extract IOEs from the invocation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@steveloughran , thanks for the info! Since we need to back port this to some earlier versions, we won't use
DynMethodat the moment.