Thanks for the KIP,
+1 (non binding)

On Wed, May 16, 2018 at 2:51 AM, 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
>> > > >
>> > >
>> >
>>

Reply via email to