Skip to content
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

Digest auth support #10

Merged
merged 10 commits into from
Mar 10, 2019
Merged

Digest auth support #10

merged 10 commits into from
Mar 10, 2019

Conversation

mssfang
Copy link
Member

@mssfang mssfang commented Feb 25, 2019

Current proxy implementation has a limitation: we donot negotiate the Auth mechanisms with the Proxy and assume that it is going to be No-Auth or Basic-Auth. With java 1.8's recent update - Basic Auth is no longer part of the defualt settings for jre applications.

This PR adds the below 2 functionalities and brings us relevant to the current security standards:

  1. adds proxy authentication negotiation
  2. implements digest auth.

cc: @timtay-microsoft @apraovjr @binzywu @ShubhaVijayasarathy @tameraw @prmathur-microsoft @jasmineymlo @sjkwak @JonathanGiles @mayurid

try {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(System.currentTimeMillis());
byte[] nonceBytes = new byte[16];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot find that nonceBytes is ever used. It looks like these four lines can be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's cnonceBytes, which is a separate array from nonceBytes. There's a similar duplication with random/secureRandom.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, thanks. Just delete these 4 lines with a new commit.

Copy link
Contributor

@SreeramGarlapati SreeramGarlapati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your contribution @mssfang. Adding digest Auth to our library makes us relevant to the current security standards. Truly appreciate your help!
Please make the necessary changes & lets ship it.

public class ProxyImpl implements Proxy, TransportLayer {
private final int proxyHandshakeBufferSize = 4 * 1024; // buffers used only for proxy-handshake
private final int proxyHandshakeBufferSize = 2 * 1024 * 1024; // buffers used only for proxy-handshake
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the buffer size updated to 2MB? This is supposed to be used only for Proxy Handshake. Are the Digest Auth headers large?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Digest Auth header is larger than 4096 bytes, in my case, it is about 4150 bytes. The reason to change to 2 * 1024 * 1024 is that I saw the proton impl class TransportImpl has defined BUFFER_RELEASE_THRESHOLD as 2 * 1024 * 1024.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current implementation holds on to the 4k buffers - as long as the Connection is live. With this change, when customers create large no. of Connections - these 2MB buffers are going to show up in the memory profile - which is essentially unused but allocated memory.

Can you please evaluate these 2 options:

  1. Find the maximum size of the buffer needed for Digest Auth. If this is below say 10K then we are good. Just update that constant.
  2. If we have to go with 2MB buffers - please explore how you can clear the buffers, once the proxy negotiation is done.

In reply to: 261047300 [](ancestors = 261047300)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the explanation. I have tried find a way to flush the input socket buffer but seems it is controlled by proton-j lib. So I change to use the 8 * 1024 in our use case now.

if (responseResult.getIsSuccess()) {
proxyState = ProxyState.PN_PROXY_CONNECTED;
} else if (responseResult.getError() != null &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous implementation assumes that - we dont negotiate the AuthMechanism with the Proxy and always assumes Digest Auth. In your current design, you have a new state where you are reading proxy challenge and responding with the appropriate response. Can you indicate this by adding a new state for this?

In the case of Proxies with No Auth:

PN_PROXY_NOT_STARTED,
PN_PROXY_CONNECTING,
PN_PROXY_CONNECTED

In case of Proxies with Auth:

PN_PROXY_NOT_STARTED,
PN_PROXY_CONNECTING,
PN_PROXY_CHALLENGE,
PN_PROXY_CHALLENGE_RESPONDED,
PN_PROXY_CONNECTED

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new states added

proxyState = ProxyState.PN_PROXY_NOT_STARTED;
final Scanner responseScanner = new Scanner(responseResult.getError());
final Map<String, String> challengeQuestionValues = new HashMap<String, String>();
while (responseScanner.hasNextLine()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think about the scope of this class as -a place holder for the state transistions and buffers. Please refactor processing the challenge headers into a different files.

I would Create an interface something like:

interface ProxyChallengeProcessor {
 string getHeader();
}

implement a basic auth processor and digest auth processor. Select processor based on the Challege response.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added ProxyChallengeProcessor and ProxyChallengeProcessorImpl classes

@@ -31,7 +31,7 @@
public class ProxyImplTest {

private String hostName = "test.host.name";
private int bufferSize = 4 * 1024;
private int bufferSize = 2 * 1024 * 1024;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider adding unit tests for the scenario you added.

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ProxyChallengeProcessorImpl implements ProxyChallengeProcessor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be multiple implementations of the ProxyChallengeProcessor interface, one for each auth scheme we support: DigestProxyChallengeProcessorImpl, BasicProxyChallengeProcessorImpl. process() should look at the challenge, select the preferred scheme, and instantiate the class which supports that scheme. This design allows us to cleanly add new schemes later.

Copy link
Member Author

@mssfang mssfang Mar 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, James. Current PR has updated with the new suggest changes. Please let me know if there is missing.

Copy link
Member Author

@mssfang mssfang Mar 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any updates of reviewing, we are trying to get this PR approved and merged ASAP. Please let me know if there is anything I can do to make it happen. Free feel to ping me. Thank you.
@JamesBirdsall @SreeramGarlapati

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good to me. I'll merge it tomorrow morning unless Sreeram has something more to say. I think we're at the point where all the major pieces are in place and any tweaks can be handled as separate PRs. Thanks Shawn!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, James.

@JamesBirdsall JamesBirdsall merged commit 3c28728 into Azure:master Mar 10, 2019
JamesBirdsall pushed a commit to Azure/azure-event-hubs-java that referenced this pull request Mar 11, 2019
conniey added a commit to Azure/azure-sdk-for-java that referenced this pull request Apr 30, 2019
* Update Apache Proton-J dependency (0.29.0 --> 0.31.0) (#407)

* PartitionReceiver - add a method that provides an EventPosition which corresponds to an EventData returned last by the receiver (#408)

* Support IsPartitionEmpty property for PartitionRuntimeInformation (#399)

* Move setPrefetchCount API to the ReceiverOptions class from the PartitionReceiver and update the settings of Default & Max Prefetch count (#410)

This pull request includes two major changes related to Prefetch API.

1) Move setPrefetchCount API to the ReceiverOptions class so that prefetch value specified by a user can be used instead of using default value when communicating to the service during link open and initializing a receiver. This change also addresses the receiver stuck issue caused by setPrefetchAPI in a race condition.

2) Change the default value and set the upper bound of the prefetch count. Note that prefetch count should be greater than or equal to maxEventCount which can be set when either a) calling receive() API or b) implementing the getMaxEventCount API of the SessionReceiverHandler interface.

* Fixes several issues in the reactor related components (#411)

This pull request contains the following changes.

1) Finish pending tasks when recreating the reactor and make sure pending calls scheduled on the old reactor get complete.
2) Fix the session open timeout issue which can result in NPE in proton-J engine.
3) Make session open timeout configurable and use the value of OperationTimeout.
4) Update the message of exceptions and include an entity name in the exception message.
5) API change - use ScheduledExecutorService.
6) Improve tracing.

* Implement comparable on EventData (#395)

* Update receive/send link creation logic and improve tracing (#414)

* Prep for releasing client 2.0.0 and EPH 2.2.0 (#415)

* Ensure that links are closed when transport error occurrs (#417)

* ensure links are recreated on transport/connection failure
* update API document for EventProcessorOptions class
* add traces for link create/close case

* Prep for releasing client 2.1.0 and EPH 2.3.0 (#418)

* Update prefetch sendflow logic and increment version for new release (#420)

* Fix args for proxy auth call to Authenticator (#421)

* Prepare EPH 2.3.4 release (#423)

* Prepare EPH 2.4.0 release (#423) (#424)

* Handle proton:io errors with meaningful error msg (#427)

* Handle proton:io errors with meaningful error msg

* Use Proton-supplied message if present

* Minor changes to lease scanner (#428)

* Add logging if the scanner threw an exception.
* Change logging level to warn when scanner shuts down for any reason.
* Scanner can call EventProcessorOptions.notifyOfException, which calls user code. Change notifyOfException to defensively catch any exceptions coming out of user code.

* Make EventData.SystemProperties completely public (#435)

Porting testability changes from .NET Core to Java: provide full access to EventData's SystemProperties so that a complete EventData can be fabricated in tests.

* Digest Support: init first connection with null headers (#431)

Related to Azure/qpid-proton-j-extensions#10

* Fix lease scanner issues when Storage unreachable (#434)

This fix is for issue #432. There are two parts:

AzureStorageCheckpointLeaseManager performs certain Storage actions within a forEach. If those actions fail, the StorageException gets wrapped in a NoSuchElementException. Catch those and strip off the NoSuchElementException, then handle the StorageException in the existing way.

The unexpected NoSuchElementExceptions were not being caught anywhere and the scanner thread was dying without rescheduling itself. Added code in PartitionMananger.scan to catch any exceptions that leak out of PartitionScanner and reschedule the scanner unless the host instance is shutting down.

* message receiver - fix null pointer error and ensure that receive link is recreated upon a failure (#439)

* message receiver/sender - fix null pointer error and ensure that receive/send link is recreated on a failure.

* Update version numbers for release (#440)

* Update prefetch count for a receiver (#441)

* Fix an issue of creating multiple sessions for $management & $cbs channel for a single connection and improve logging (#443)

* Fix an issue of creating multiple sessions for $management & $cbs for a connection and improve logging

* Running through java files and double checking changes

* Fix casing on test names

* Ignore testcases that hang.

* Fix NullPointerException when there is no inner exception

* Move parent node to the top of the file.

* Update version numbers in spotbugs-reporting

* Increasing wait time until event hub scheduler is completed.
conniey added a commit to Azure/azure-sdk-for-java that referenced this pull request May 3, 2019
* Update Apache Proton-J dependency (0.29.0 --> 0.31.0) (#407)

* PartitionReceiver - add a method that provides an EventPosition which corresponds to an EventData returned last by the receiver (#408)

* Support IsPartitionEmpty property for PartitionRuntimeInformation (#399)

* Move setPrefetchCount API to the ReceiverOptions class from the PartitionReceiver and update the settings of Default & Max Prefetch count (#410)

This pull request includes two major changes related to Prefetch API.

1) Move setPrefetchCount API to the ReceiverOptions class so that prefetch value specified by a user can be used instead of using default value when communicating to the service during link open and initializing a receiver. This change also addresses the receiver stuck issue caused by setPrefetchAPI in a race condition.

2) Change the default value and set the upper bound of the prefetch count. Note that prefetch count should be greater than or equal to maxEventCount which can be set when either a) calling receive() API or b) implementing the getMaxEventCount API of the SessionReceiverHandler interface.

* Fixes several issues in the reactor related components (#411)

This pull request contains the following changes.

1) Finish pending tasks when recreating the reactor and make sure pending calls scheduled on the old reactor get complete.
2) Fix the session open timeout issue which can result in NPE in proton-J engine.
3) Make session open timeout configurable and use the value of OperationTimeout.
4) Update the message of exceptions and include an entity name in the exception message.
5) API change - use ScheduledExecutorService.
6) Improve tracing.

* Implement comparable on EventData (#395)

* Update receive/send link creation logic and improve tracing (#414)

* Prep for releasing client 2.0.0 and EPH 2.2.0 (#415)

* Ensure that links are closed when transport error occurrs (#417)

* ensure links are recreated on transport/connection failure
* update API document for EventProcessorOptions class
* add traces for link create/close case

* Prep for releasing client 2.1.0 and EPH 2.3.0 (#418)

* Update prefetch sendflow logic and increment version for new release (#420)

* Fix args for proxy auth call to Authenticator (#421)

* Prepare EPH 2.3.4 release (#423)

* Prepare EPH 2.4.0 release (#423) (#424)

* Handle proton:io errors with meaningful error msg (#427)

* Handle proton:io errors with meaningful error msg

* Use Proton-supplied message if present

* Minor changes to lease scanner (#428)

* Add logging if the scanner threw an exception.
* Change logging level to warn when scanner shuts down for any reason.
* Scanner can call EventProcessorOptions.notifyOfException, which calls user code. Change notifyOfException to defensively catch any exceptions coming out of user code.

* Make EventData.SystemProperties completely public (#435)

Porting testability changes from .NET Core to Java: provide full access to EventData's SystemProperties so that a complete EventData can be fabricated in tests.

* Digest Support: init first connection with null headers (#431)

Related to Azure/qpid-proton-j-extensions#10

* Fix lease scanner issues when Storage unreachable (#434)

This fix is for issue #432. There are two parts:

AzureStorageCheckpointLeaseManager performs certain Storage actions within a forEach. If those actions fail, the StorageException gets wrapped in a NoSuchElementException. Catch those and strip off the NoSuchElementException, then handle the StorageException in the existing way.

The unexpected NoSuchElementExceptions were not being caught anywhere and the scanner thread was dying without rescheduling itself. Added code in PartitionMananger.scan to catch any exceptions that leak out of PartitionScanner and reschedule the scanner unless the host instance is shutting down.

* message receiver - fix null pointer error and ensure that receive link is recreated upon a failure (#439)

* message receiver/sender - fix null pointer error and ensure that receive/send link is recreated on a failure.

* Update version numbers for release (#440)

* Update prefetch count for a receiver (#441)

* Fix an issue of creating multiple sessions for $management & $cbs channel for a single connection and improve logging (#443)

* Fix an issue of creating multiple sessions for $management & $cbs for a connection and improve logging

* Update version numbers for new release (#444)

* Update spotbugs.xml report versions
Jgomez13 pushed a commit to Azure/azure-event-hubs-java that referenced this pull request May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants