Bug: OAuth Bearer authentication mech plugin for SASL
Status: In Progress | Priority: Major | Resolution: 
Created: 09/Dec/21 11:35

Implementation of a new SASL plugin to add support for OAuth Bearer token authentication for HBase client RPC.
 * The plugin supports secured (cryptographically signed) JSON Web Token authentication as defined in [RFC-7628|https://datatracker.ietf.org/doc/html/rfc7628]  and the JWT format in [RFC-7519|https://datatracker.ietf.org/doc/html/rfc7519] .
 * The implementation is inspired by [Apache Kafka's OAuth Bearer token|https://docs.confluent.io/platform/current/kafka/authentication_sasl/authentication_sasl_oauth.html] support with the important difference that HBase version is intended for production usage. The two main differences are that Kafka supports unsecured tokens only and it issues the tokens for itself which breaks the principle of OAuth token authentication.
 * We use the [Nimbus JOSE + JWT|https://bitbucket.org/connect2id/nimbus-jose-jwt/src/master/] Java library for signature verification and token processing and we add it as a new dependency to HBase.
 * We add secure JWT support and verification of digital signatures with multiple algorithms as supported by Nimbus. Json-formatted JWK set is required for the signature verification as defined in [RFC-7517|https://datatracker.ietf.org/doc/html/rfc7517].
 * The impl is verified with Apache Knox issued tokens, because that's the primary use case of this new feature.
 * New client example is added to the hbase-examples project to showcase the feature.
 * It's important that this Jira does not cover the solution for obtaining a token from Knox. The assumption is that the client already has a valid token in base64 encoded string and we only provide a helper method for adding it to user's credentials.
 * Renewing expired tokens is also the responsibility of the client. We don't provide a mechanism for that in this Jira, but it's planned to be covered in a follow-up ticket.

The following new parameters are introduced in hbase-site.xml:
 * hbase.security.oauth.jwt.jwks.file - Path of a local file for JWK set. (required if URL not specified)
 * hbase.security.oauth.jwt.jwks.url - URL to download the JWK set. (required if File not specified)
 * hbase.security.oauth.jwt.audience - Required audience, "aud" claim of the JWT. (optional)
 * hbase.security.oauth.jwt.issuer - Required issuer, "iss" claim of the JWT. (optional)

The feature will be behind feature-flag. No code part is executed unless the following configuration is set in hbase-site.xml:
{noformat}
  <property>
    <name>hbase.client.sasl.provider.extras</name>
    <value>org.apache.hadoop.hbase.security.provider.OAuthBearerSaslClientAuthenticationProvider</value>
  </property>
  <property>
    <name>hbase.server.sasl.provider.extras</name>
    <value>org.apache.hadoop.hbase.security.provider.OAuthBearerSaslServerAuthenticationProvider</value>
  </property>
  <property>
    <name>hbase.client.sasl.provider.class</name>
    <value>org.apache.hadoop.hbase.security.provider.OAuthBearerSaslProviderSelector</value>
  </property>
{noformat}
Example of Knox provided JWKS file:
{noformat}
{
  "keys":
  [{
    "kty": "RSA",
    "e": "<RSA_e>",
    "use": "sig",
    "kid": "<key_id>",
    "alg": "RS256",
    "n": "<RSA_n>"
  }]
}{noformat}
Example of Knox issued JWT header:
{noformat}
{
"jku": "https://path/to/homepage/knoxtoken/api/v1/jwks.json",
"kid": "<key_id>",
"alg": "RS256"
}{noformat}
And payload:
{noformat}
{
  "sub": "user_andor",
  "aud": "knox-proxy-token",
  "jku": "https://path/to/homepage/knoxtoken/api/v1/jwks.json",
  "kid": "<key_id>",
  "iss": "KNOXSSO",
  "exp": 1636644029,
  "managed.token": "true",
  "knox.id": "<knox_uuid>"
}{noformat}