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

[WIP]kerberos authentication between client and broker #3658

Closed
wants to merge 6 commits into from

Conversation

jiazhai
Copy link
Member

@jiazhai jiazhai commented Feb 22, 2019

Fixes #3652

Master Issue: #3491

Motivation

Currently both Zookeeper and BookKeeper could be secured by using Kerberos, It would be good to support Kerberos in Pulsar Broker and Client.
This is the first PR for issue in #3491 to support Kerberos in Pulsar Broker and Client.
Will add proxy and web resource support in following prs.
The Kerberos authentication is similar to that in Zookeeper and BookKeeper, which leverage SASL and GSSAPI, so reused some of the code there.

Changes.

  • changed connect command to support mutual auth between client and server;
  • provide both client and broker side support for authentication api;
  • add unit test.

@jiazhai jiazhai self-assigned this Feb 22, 2019
@sijie sijie added type/feature The PR added a new feature or issue requested a new feature area/security labels Feb 22, 2019
@sijie sijie added this to the 2.4.0 milestone Feb 22, 2019
@jiazhai jiazhai requested review from merlimat and sijie and removed request for merlimat February 22, 2019 05:40
@jiazhai
Copy link
Member Author

jiazhai commented Feb 22, 2019

@eolivelli Since you are familiar with BookKeeper Kerberos auth, Would you please help review this?
Thanks.

### --- SASL Authentication Provider --- ###

# Whether Use SASL Authentication or not.
isSaslAuthentication=
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be enabled through the authentication plugins list instead of an ad hoc flag

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, @merlimat @sijie, right, this is a temp change, and will not be exist after the implementation of supporting for web resource.
As in the current code, this is only used in web resource checking for authentication.
Will add a TODO and link with the issue.


/**
*
* @return authentication data which will be stored in a command
Copy link
Contributor

Choose a reason for hiding this comment

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

This is changing the current authentication framework in non-trivial ways. This of course is needed to support Kerberos but It needs to be done in a separated PR. Also we should have a PIP to outline the design and have more people to get eyes on it.


/**
* set data which will be stored in a command to send to client
* used for sasl.
Copy link
Contributor

Choose a reason for hiding this comment

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

The interface should not be tied to a specific implementation (eg sasl), but rather abstract the generic needs of multi-step authentication.

### --- SASL Authentication Provider --- ###

# Whether Use SASL Authentication or not.
isSaslAuthentication=
Copy link
Member

Choose a reason for hiding this comment

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

do we really need another flag for checking whether it is sasl authentication?

Shall we just check if the authentication provider is an instance of sasl provider?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, @merlimat @sijie, right, this is a temp change, and will not be exist after the implementation of supporting for web resource.
As in the current code, this is only used in web resource checking for authentication.
Will add a TODO and link with the issue.

}
}

// will get authenticated client id like: "client/[email protected]"
Copy link
Member

Choose a reason for hiding this comment

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

is the comment needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

will remove it.

*
* @return authentication data which will be stored in a command
*/
default byte[] getCommandDataBytes() {
Copy link
Member

Choose a reason for hiding this comment

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

shall we just standardize to use byte[]?

Copy link
Member Author

Choose a reason for hiding this comment

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

We should do this. since String convert meet some error in this pr

Copy link
Contributor

Choose a reason for hiding this comment

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

In other auth plugins we're base64 encoding the credential. That would not need any change in the plugin interfaces

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. It is Ok for me. If byte[] will involve too many changes, will try and use base64 later.

Copy link
Member Author

@jiazhai jiazhai Feb 23, 2019

Choose a reason for hiding this comment

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

@merlimat, How about we keep the old methods to use String, and new methods use byte[]?

one concern here is: Is it worth to convert between String and Byte using base64?
As in PulsarApi.proto, we store auth data as bytes in CommandConnected, and in SaslServer and SaslClient, it do the valuate and challenge also use bytes, like this:

byte[]  evaluateResponse(byte[] response)

This means, we need to convert
bytes(proto cmd) <-> String(pulsar api) <-> bytes(sasl api)
each time.
The benefit to use String is the alignment with old api, while the opposite is useless converting.

* After the authentication between client and broker completed.
* Get authenticationId represent for the client
*/
default String getAuthorizationID() {
Copy link
Member

Choose a reason for hiding this comment

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

is this only required by SASL?

* @return authentication data which is stored in a command
*/
default String getCommandData() {
return null;
}


/*
Copy link
Member

Choose a reason for hiding this comment

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

I think the newly introduced methods can just be part of SaslAuthenticationDataSource. Since they are only used by SaslAuthenticationProvider and SaslAuthenticationProvider will check if a data source is a sasl data source, it can cast the data source and access those methods.

We don't need to put the methods here.

if (sslHandler != null) {
sslSession = ((SslHandler) sslHandler).engine().getSession();
// sasl.
if (isSaslAuthenticationMethod()) {
Copy link
Member

Choose a reason for hiding this comment

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

I think this part of code can be refactored by introducing an AuthState interface. so we can have one stage AuthState for existing authentication providers, and a multi-stage authentication implementation for Kerberos (or any future implementation).

An AuthState basically is holding the authentication state, tell broker whether the authentication is completed or not, if completed, what is the AuthRole.

interface AuthState {

    boolean isComplete();
    AuthenticationData getAuthData();
    String getAuthRole();

    /**
      * Returns null if authentication has completed, and no auth data is required to send back to client.
      * Returns the auth data back to client, if authentication has not completed.
      */
    byte[] authenticate(byte[] authData);

}

Then add a newAuthState in the AuthenticationProvider. The default implementation can be the OneStageAuthState (described at the end) to be shared across existing authentication providers. The kerberos plugin can return its own AuthState.

So the implementation in broker can be very simple:

AuthState authState = authenticationProvider.newAuthState();

byte[] clientAuthData = connect.getAuthData().toByteArray();
byte[] brokerAuthData = authState.authenticate(clientAuthData);
if (null == brokerAuthData) {
     // authentication has completed.
     authData = authState.getAuthenticateData();
     authRole = authState.getAuthRole();
     // we are done here
} else {
     // it is a multi-stage authentication mechanism, send the auth data back
     ctx.writeAndFlush(Commands.newConnecting(authMethod, data));
}

for the current existing authentication providers, implement a common OneStageAuthState (basically the logic from line 515 to line 534).

for the kerberos authenciation provider, implement a KeberosAuthState (basically the logic from line 469 to line 513).

This would produce a clean interface between AuthenticationProvider and Brokers and avoiding add Sasl specific logic in ServerCnx.

@jiazhai
Copy link
Member Author

jiazhai commented Feb 22, 2019

@sijie @merlimat Thanks for the comments. will prepare a pip for the mutual auth api changes, then back to this PR again.

@@ -0,0 +1,198 @@
/*
Licensed to Diennea S.r.l. under one
Copy link
Contributor

Choose a reason for hiding this comment

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

This will fail the License check. Either we add an exclusion or we ask the copyirght holder to donate this code to ASF.

Copy link
Member Author

Choose a reason for hiding this comment

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

@merlimat, @eolivelli right, it is copy from bookkeeper before this change. and It is there in BookKeeper.

Copy link
Contributor

Choose a reason for hiding this comment

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

I will send a patch for Bookkeeper

@eolivelli
Copy link
Contributor

eolivelli commented Feb 22, 2019

Was it on Bookkeeper? Its my company

Copy link
Contributor

@eolivelli eolivelli left a comment

Choose a reason for hiding this comment

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

What about using PulsarBroker and PulsarClient for jaas entries?

serviceHostname = null;
}

log.info("serviceHostname is '{}', servicePrincipalName is '{}', SASL mechanism(mech) is '{}'.",
Copy link
Contributor

Choose a reason for hiding this comment

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

This will be logged at every new connection

Copy link
Member Author

Choose a reason for hiding this comment

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

will change it into debug


@BeforeClass
public static void startMiniKdc() throws Exception {
kdcDir = Files.createTempDirectory("test-kdc-dir").toFile();
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't we using TemporaryFolder rule ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. TemporaryFolder is from junit, but pulsar mainly use testng. will try to handle the delete of these folder in cleanup.

@jiazhai jiazhai changed the title kerberos authentication between client and broker [WIP]kerberos authentication between client and broker Feb 23, 2019
@jiazhai
Copy link
Member Author

jiazhai commented Mar 14, 2019

Since changed a lot in PR #3677 , would like to close this pr, and will send a new one. Thanks for the comments.

@jiazhai jiazhai closed this Mar 14, 2019
sijie pushed a commit that referenced this pull request Mar 19, 2019
Fixes #3652

**Motivation**
Currently both Zookeeper and BookKeeper could be secured by using Kerberos, It would be good to support Kerberos in Pulsar Broker and Client.
This is the sub-task for issue in #3491 to support Kerberos in Pulsar Broker and Client.
Will add proxy and web resource support in following prs.
The Kerberos authentication is similar to that in Zookeeper and BookKeeper, which leverage SASL and GSSAPI, so reused some of the code there.
PR #3658 is the first version of PR before #3677 .

**Changes**
provide both client and broker side support for authentication api;
add unit test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/security type/feature The PR added a new feature or issue requested a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants