-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Conversation
@eolivelli Since you are familiar with BookKeeper Kerberos auth, Would you please help review this? |
### --- SASL Authentication Provider --- ### | ||
|
||
# Whether Use SASL Authentication or not. | ||
isSaslAuthentication= |
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.
This should be enabled through the authentication plugins list instead of an ad hoc flag
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.
|
||
/** | ||
* | ||
* @return authentication data which will be stored in a command |
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.
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. |
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.
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= |
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.
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?
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.
...h-sasl/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderSasl.java
Outdated
Show resolved
Hide resolved
...h-sasl/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationProviderSasl.java
Outdated
Show resolved
Hide resolved
} | ||
} | ||
|
||
// will get authenticated client id like: "client/[email protected]" |
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.
is the comment needed?
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.
will remove it.
...broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/PulsarSaslServer.java
Outdated
Show resolved
Hide resolved
* | ||
* @return authentication data which will be stored in a command | ||
*/ | ||
default byte[] getCommandDataBytes() { |
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.
shall we just standardize to use byte[]
?
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.
We should do this. since String convert meet some error in this pr
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.
In other auth plugins we're base64 encoding the credential. That would not need any change in the plugin interfaces
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.
Thanks. It is Ok for me. If byte[] will involve too many changes, will try and use base64 later.
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.
@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.
...r-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationDataSource.java
Show resolved
Hide resolved
* After the authentication between client and broker completed. | ||
* Get authenticationId represent for the client | ||
*/ | ||
default String getAuthorizationID() { |
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.
is this only required by SASL?
pulsar-broker/src/main/java/org/apache/pulsar/broker/service/ServerCnx.java
Show resolved
Hide resolved
* @return authentication data which is stored in a command | ||
*/ | ||
default String getCommandData() { | ||
return null; | ||
} | ||
|
||
|
||
/* |
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.
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()) { |
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.
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.
@@ -0,0 +1,198 @@ | |||
/* | |||
Licensed to Diennea S.r.l. under one |
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.
This will fail the License check. Either we add an exclusion or we ask the copyirght holder to donate this code to ASF.
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.
@merlimat, @eolivelli right, it is copy from bookkeeper before this change. and It is there in BookKeeper.
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.
I will send a patch for Bookkeeper
Was it on Bookkeeper? Its my company |
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.
What about using PulsarBroker and PulsarClient for jaas entries?
serviceHostname = null; | ||
} | ||
|
||
log.info("serviceHostname is '{}', servicePrincipalName is '{}', SASL mechanism(mech) is '{}'.", |
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.
This will be logged at every new connection
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.
will change it into debug
|
||
@BeforeClass | ||
public static void startMiniKdc() throws Exception { | ||
kdcDir = Files.createTempDirectory("test-kdc-dir").toFile(); |
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.
Aren't we using TemporaryFolder rule ?
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.
Thanks. TemporaryFolder is from junit, but pulsar mainly use testng. will try to handle the delete of these folder in cleanup.
…/authentication/PulsarSaslServer.java Co-Authored-By: jiazhai <[email protected]>
Since changed a lot in PR #3677 , would like to close this pr, and will send a new one. Thanks for the comments. |
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.
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.