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