Hi Committers. One more binding affirmative vote is required if KIP 255 is to have a chance of being included in the 2.0.0 release. Please vote today.
Ron > On May 18, 2018, at 9:27 PM, Ron Dagostino <rndg...@gmail.com> wrote: > > Hi committers. KIP 255 still needs 1 more binding vote. Currently there are > two binding + 1 votes, from Rajini and Jun, and three non-binding +1 votes, > from Mickael, Manikumar, and myself. > > Please vote by the Monday deadline. > > Ron > >> On Thu, May 17, 2018 at 10:59 AM, Ron Dagostino <rndg...@gmail.com> wrote: >> Hi Jun. I've updated the KIP to add a new section titled "Summary for >> Production Use" that includes this information along with a consolidated set >> of references to the applicable specifications. Thanks for the questions. >> >> *We still need another binding vote* (currently there are two binding + 1 >> votes, from Rajini and Jun, and three non-binding +1 votes, from Mickael, >> Manikumar, and myself). >> >> Please vote before the May 22nd KIP Freeze deadline so this KIP can be >> included in the 2.0.0 release. >> >> A pull request is available and includes additional commits reflecting >> initial review comments: https://github.com/apache/kafka/pull/4994 >> >> Ron >> >>> On Wed, May 16, 2018 at 8:09 PM, Jun Rao <j...@confluent.io> wrote: >>> Hi, Ron, >>> >>> Thanks. I understand now. It may be useful to add a reference to JWT in the >>> KIP. >>> >>> Jun >>> >>> On Tue, May 15, 2018 at 6:51 PM, Ron Dagostino <rndg...@gmail.com> wrote: >>> >>> > Hi Jun. I think you are getting at the fact that OAuth 2 is a flexible >>> > framework that allows different installations to do things differently. >>> > It >>> > is true that the principal name in Kafka could come from any claim in the >>> > token. Most of the time it would come from the 'sub' claim, but it could >>> > certainly come from another claim, or it could be only indirectly based on >>> > a claim value (maybe certain text would be trimmed or prefixed/suffixed). >>> > The point, which I think you are getting at, is that because the framework >>> > is flexible we need to accommodate that flexibility. The callback handler >>> > class defined by the listener.name.sasl_ssl.oauthbearer.sasl.server. >>> > callback.handler.class configuration value gives us the required >>> > flexibility. As an example, I have an implementation that leverages a >>> > popular open source JOSE library to parse the compact serialization, >>> > retrieve the public key if it has not yet been retrieved, verify the >>> > digital signature, and map the 'sub' claim to the OAuthBearerToken's >>> > principal name (which becomes the SASL authorization ID, which becomes the >>> > Kafka principal name). I could just as easily have mapped a different >>> > claim to the OAuthBearerToken's principal name, manipulated the 'sub' >>> > claim >>> > value in some way, etc. I write the callback handler code, so I complete >>> > flexibility to do whatever my OAuth 2 installation requires me to do. >>> > >>> > Ron >>> > >>> > On Tue, May 15, 2018 at 1:39 PM, Jun Rao <j...@confluent.io> wrote: >>> > >>> > > Hi, Ron, >>> > > >>> > > Thanks for the reply. I understood your answers to #2 and #3. >>> > > >>> > > For #1, will the server map all clients' principal name to the value >>> > > associated with "sub" claim? How do we support mapping different clients >>> > to >>> > > different principal names? >>> > > >>> > > Jun >>> > > >>> > > On Mon, May 14, 2018 at 7:02 PM, Ron Dagostino <rndg...@gmail.com> >>> > wrote: >>> > > >>> > > > Hi Jun. Thanks for the +1 vote. >>> > > > >>> > > > Regarding the first question about token claims, yes, you have it >>> > correct >>> > > > about translating the OAuth token to a principle name via a JAAS >>> > > > module >>> > > > option in the default unsecured case. Specifically, the OAuth SASL >>> > > Server >>> > > > implementation is responsible for setting the authorization ID, and it >>> > > gets >>> > > > the authorization ID from the OAuthBearerToken's principalName() >>> > method. >>> > > > The listener.name.sasl_ssl.oauthbearer.sasl.server. >>> > > callback.handler.class >>> > > > is responsible for handling an instance of >>> > > > OAuthBearerValidatorCallback >>> > > to >>> > > > accept a token compact serialization from the client and return an >>> > > instance >>> > > > of OAuthBearerToken (assuming the compact serialization validates), >>> > > > and >>> > > in >>> > > > the default unsecured case the builtin unsecured validator callback >>> > > handler >>> > > > defines the OAuthBearerToken.principalName() method to return the >>> > 'sub' >>> > > > claim value by default (with the actual claim it uses being >>> > configurable >>> > > > via the unsecuredValidatorPrincipalClaimName JAAS module option). So >>> > > that >>> > > > is how we translate from a token to a principal name in the default >>> > > > unsecured (out-of-the-box) case. >>> > > > >>> > > > For production use cases, the implementation associated with >>> > > > listener.name.sasl_ssl.oauthbearer.sasl.server.callback.handler.class >>> > > can >>> > > > do whatever it wants. As an example, I have written a class that >>> > wraps a >>> > > > com.nimbusds.jwt.SignedJWT instance (see >>> > > > https://connect2id.com/products/nimbus-jose-jwt/) and presents it as >>> > an >>> > > > OAuthBearerToken: >>> > > > >>> > > > public class NimbusSignedJwtOAuthBearerToken implements >>> > > OAuthBearerToken { >>> > > > private final SignedJWT signedJwt; >>> > > > private final String principalName; >>> > > > private final Set<String> scope; >>> > > > private final Long startTimeMs; >>> > > > private final long lifetimeMs; >>> > > > >>> > > > /** >>> > > > * Constructor >>> > > > * >>> > > > * @param signedJwt >>> > > > * the mandatory signed JWT >>> > > > * @param principalClaimName >>> > > > * the mandatory claim name identifying the claim from >>> > > which >>> > > > the >>> > > > * principal name will be extracted. The claim must >>> > exist >>> > > > and must be >>> > > > * a String. >>> > > > * @param optionalScopeClaimName >>> > > > * the optional claim name identifying the claim from >>> > > which >>> > > > any scope >>> > > > * will be extracted. If specified and the claim exists >>> > > then >>> > > > the >>> > > > * value must be either a String or a String List. >>> > > > * @throws ParseException >>> > > > * if the principal claim does not exist or is not a >>> > > > String; the >>> > > > * scope claim is neither a String nor a String List; >>> > the >>> > > > 'exp' >>> > > > * claim does not exist or is not a number; the 'iat' >>> > > claim >>> > > > exists >>> > > > * but is not a number; or the 'nbf' claim exists and >>> > is >>> > > > not a >>> > > > * number. >>> > > > */ >>> > > > public NimbusSignedJwtOAuthBearerToken(SignedJWT signedJwt, String >>> > > > principalClaimName, >>> > > > String optionalScopeClaimName) throws ParseException { >>> > > > // etc... >>> > > > } >>> > > > >>> > > > The callback handler runs the following code if the digital signature >>> > > > validates: >>> > > > >>> > > > callback.token(new NimbusSignedJwtOAuthBearerToken(signedJwt, >>> > "sub", >>> > > > null)); >>> > > > >>> > > > I hope that answers the first question. If not let me know what I >>> > > > missed/misunderstood and I'll be glad to try to address it. >>> > > > >>> > > > Regarding the second question, the classes OAuthBearerTokenCallback >>> > > > and >>> > > > OAuthBearerValidatorCallback implement the Callback interface -- they >>> > are >>> > > > the callbacks that the AuthenticateCallbackHandler implementations >>> > > > need >>> > > to >>> > > > handle. Specifically, unless the unsecured functionality is what is >>> > > > desired, the two configuration values [listener.name.sasl_ssl. >>> > > oauthbearer. >>> > > > ]sasl.login.callback.handler.class and >>> > > > listener.name.sasl_ssl.oauthbearer.sasl.server.callback.handler.class >>> > > > define the callback handlers that need to handle >>> > OAuthBearerTokenCallback >>> > > > and OAuthBearerValidatorCallback, respectively. >>> > > > >>> > > > Regarding the third question, yes, I see your point that the way the >>> > spec >>> > > > is worded could be taken to imply that the error code is a single >>> > > > character: "A single ASCII..." ( >>> > > > https://tools.ietf.org/html/rfc6749#section-5.2). However, it is not >>> > a >>> > > > single character. See the end of that section 5.2 for an example that >>> > > > shows "error":"invalid_request" as the response. >>> > > > >>> > > > Thanks again for the +1 vote, Jun, and please do let me know if I can >>> > > cover >>> > > > anything else. >>> > > > >>> > > > Ron >>> > > > >>> > > > >>> > > > On Mon, May 14, 2018 at 7:10 PM, Jun Rao <j...@confluent.io> wrote: >>> > > > >>> > > > > Hi, Ron, >>> > > > > >>> > > > > Thanks for the KIP. +1 from me. Just a few minor comments below. >>> > > > > >>> > > > > 1. It seems that we can translate an OAuth token to a principle name >>> > > > > through the claim name configured in JASS. However, it's not clear >>> > > > > to >>> > > me >>> > > > > how an OAuth token is mapped to a claim. Could you clarify that? >>> > > > > >>> > > > > 2. The wiki has the following code. It seems that >>> > > > OAuthBearerTokenCallback >>> > > > > should implement AuthenticateCallbackHandler? Ditto >>> > > > > for OAuthBearerValidatorCallback. >>> > > > > >>> > > > > public class OAuthBearerTokenCallback implements Callback >>> > > > > >>> > > > > 3. In OAuthBearerTokenCallback, we have the following method. The >>> > OAuth >>> > > > > spec says the error code is a single ASCII. So, should we return a >>> > Char >>> > > > or >>> > > > > a String? >>> > > > > >>> > > > > public String errorCode() >>> > > > > >>> > > > > Jun >>> > > > > >>> > > > > >>> > > > > On Thu, May 3, 2018 at 8:55 PM, Ron Dagostino <rndg...@gmail.com> >>> > > wrote: >>> > > > > >>> > > > > > Hi everyone. I would like to start the vote for KIP-255: >>> > > > > > https://cwiki.apache.org/confluence/pages/viewpage. >>> > > > > action?pageId=75968876 >>> > > > > > >>> > > > > > This KIP proposes to add the following functionality related to >>> > > > > > SASL/OAUTHBEARER: >>> > > > > > >>> > > > > > 1) Allow clients (both brokers when SASL/OAUTHBEARER is the >>> > > > inter-broker >>> > > > > > protocol as well as non-broker clients) to flexibly retrieve an >>> > > access >>> > > > > > token from an OAuth 2 authorization server based on the >>> > > > > > declaration >>> > > of >>> > > > a >>> > > > > > custom login CallbackHandler implementation and have that access >>> > > token >>> > > > > > transparently and automatically transmitted to a broker for >>> > > > > authentication. >>> > > > > > >>> > > > > > 2) Allow brokers to flexibly validate provided access tokens when >>> > > > > > a >>> > > > > client >>> > > > > > establishes a connection based on the declaration of a custom SASL >>> > > > Server >>> > > > > > CallbackHandler implementation. >>> > > > > > >>> > > > > > 3) Provide implementations of the above retrieval and validation >>> > > > features >>> > > > > > based on an unsecured JSON Web Token that function out-of-the-box >>> > > with >>> > > > > > minimal configuration required (i.e. implementations of the two >>> > types >>> > > > of >>> > > > > > callback handlers mentioned above will be used by default with no >>> > > need >>> > > > to >>> > > > > > explicitly declare them). >>> > > > > > >>> > > > > > 4) Allow clients (both brokers when SASL/OAUTHBEARER is the >>> > > > inter-broker >>> > > > > > protocol as well as non-broker clients) to transparently retrieve >>> > > > > > a >>> > > new >>> > > > > > access token in the background before the existing access token >>> > > expires >>> > > > > in >>> > > > > > case the client has to open new connections. >>> > > > > > >>> > > > > > Thanks, >>> > > > > > >>> > > > > > Ron >>> > > > > > >>> > > > > >>> > > > >>> > > >>> > >> >