anmolnar commented on a change in pull request #3934: URL: https://github.com/apache/hbase/pull/3934#discussion_r778084206
########## File path: hbase-common/src/main/java/org/apache/hadoop/hbase/security/oauthbearer/internals/knox/OAuthBearerSignedJwtValidatorCallbackHandler.java ########## @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.security.oauthbearer.internals.knox; + +import static org.apache.hadoop.hbase.security.token.OAuthBearerTokenUtil.OAUTHBEARER_MECHANISM; +import com.nimbusds.jose.jwk.JWKSet; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.text.ParseException; +import java.util.Map; +import java.util.Objects; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.UnsupportedCallbackException; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.security.auth.AuthenticateCallbackHandler; +import org.apache.hadoop.hbase.security.oauthbearer.OAuthBearerExtensionsValidatorCallback; +import org.apache.hadoop.hbase.security.oauthbearer.OAuthBearerValidatorCallback; +import org.apache.hadoop.hbase.security.oauthbearer.Utils; +import org.apache.yetus.audience.InterfaceAudience; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@code CallbackHandler} that recognizes + * {@link OAuthBearerValidatorCallback} and validates a secure (signed) OAuth 2 + * bearer token (JWT). + * + * It requires a valid JWK Set to be initialized at startup which holds the available + * RSA public keys that JWT signature can be validated with. The Set can be initialized + * via an URL or a local file. + * + * It requires there to be an <code>"exp" (Expiration Time)</code> + * claim of type Number. If <code>"iat" (Issued At)</code> or + * <code>"nbf" (Not Before)</code> claims are present each must be a number that + * precedes the Expiration Time claim, and if both are present the Not Before + * claim must not precede the Issued At claim. It also accepts the following + * options, none of which are required: + * <ul> + * <li>{@code hbase.security.oauth.jwt.jwks.url} set to a non-empty value if you + * wish to initialize the JWK Set via an URL. HTTPS URLs must have valid certificates. + * </li> + * <li>{@code hbase.security.oauth.jwt.jwks.file} set to a non-empty value if you + * wish to initialize the JWK Set from a local JSON file. + * </li> + * <li>{@code hbase.security.oauth.jwt.audience} set to a String value which + * you want the desired audience ("aud") the JWT to have.</li> + * <li>{@code hbase.security.oauth.jwt.issuer} set to a String value which + * you want the issuer ("iss") of the JWT has to be.</li> + * <li>{@code hbase.security.oauth.jwt.allowableclockskewseconds} set to a positive integer + * value if you wish to allow up to some number of positive seconds of + * clock skew (the default is 0)</li> + * </ul> + * + * It also recognizes {@link OAuthBearerExtensionsValidatorCallback} and validates + * every extension passed to it. + * + * This class is based on Kafka's OAuthBearerUnsecuredValidatorCallbackHandler. + */ [email protected] +public class OAuthBearerSignedJwtValidatorCallbackHandler implements AuthenticateCallbackHandler { + private static final Logger LOG = + LoggerFactory.getLogger(OAuthBearerSignedJwtValidatorCallbackHandler.class); + private static final String OPTION_PREFIX = "hbase.security.oauth.jwt."; + private static final String JWKS_URL = OPTION_PREFIX + "jwks.url"; + private static final String JWKS_FILE = OPTION_PREFIX + "jwks.file"; + private static final String ALLOWABLE_CLOCK_SKEW_SECONDS_OPTION = + OPTION_PREFIX + "allowableclockskewseconds"; + static final String REQUIRED_AUDIENCE_OPTION = OPTION_PREFIX + "audience"; + static final String REQUIRED_ISSUER_OPTION = OPTION_PREFIX + "issuer"; + private Configuration hBaseConfiguration; + private JWKSet jwkSet; + private boolean configured = false; + + @Override + public void handle(Callback[] callbacks) throws UnsupportedCallbackException { + if (!configured) { + throw new RuntimeException( + "OAuthBearerSignedJwtValidatorCallbackHandler handler be configured first."); + } Review comment: In this case checking the `jwkSet` would be enough. I was thinking of this initialization thing a lot and doesn't have a strong opinion. Kafka follows this "configured" pattern pretty much everywhere and I'm not sure if there's convention in HBase for this. Addig a constructor and expecting that `jwkSet` is built by the instantiator would also be an option. What would you recommend? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
