From 24efca7ef5091ed9a4cabb9d38361a0d132e2ae7 Mon Sep 17 00:00:00 2001 From: Andor Molnar Date: Fri, 21 Jan 2022 10:32:24 +0100 Subject: [PATCH 1/2] HBASE-26665. Added e2e test with HBase mini-cluster --- .../token/TestOAuthBearerAuthentication.java | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java new file mode 100644 index 000000000000..3ff84ab41958 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java @@ -0,0 +1,153 @@ +/** + * 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.token; + +import static org.junit.Assert.assertArrayEquals; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.time.LocalDate; +import java.util.UUID; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; +import org.apache.hadoop.hbase.security.User; +import org.apache.hadoop.hbase.testclassification.MediumTests; +import org.apache.hadoop.hbase.testclassification.SecurityTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TestName; + +@Category({ SecurityTests.class, MediumTests.class }) +public class TestOAuthBearerAuthentication extends SecureTestCluster { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestOAuthBearerAuthentication.class); + + private static RSAKey RSA; + private static File JWKS_FILE; + + @BeforeClass + public static void setUp() throws Exception { + initRSA(); + + //TEST_UTIL.getConfiguration().set("hbase.rpc.protection", "privacy"); + TEST_UTIL.getConfiguration().set("hbase.client.sasl.provider.extras", + "org.apache.hadoop.hbase.security.provider.OAuthBearerSaslClientAuthenticationProvider"); + TEST_UTIL.getConfiguration().set("hbase.server.sasl.provider.extras", + "org.apache.hadoop.hbase.security.provider.OAuthBearerSaslServerAuthenticationProvider"); + TEST_UTIL.getConfiguration().set("hbase.client.sasl.provider.class", + "org.apache.hadoop.hbase.security.provider.OAuthBearerSaslProviderSelector"); + TEST_UTIL.getConfiguration().set("hbase.security.oauth.jwt.jwks.file", + JWKS_FILE.getAbsolutePath()); + + SecureTestCluster.setUp(); + } + + @Rule + public TestName testName = new TestName(); + + private static void initRSA() throws JOSEException, IOException { + RSA = new RSAKeyGenerator(2048) + .keyUse(KeyUse.SIGNATURE) // indicate the intended use of the key + .keyID(UUID.randomUUID().toString()) // give the key a unique ID + .generate(); + JWKSet jwkSet = new JWKSet(RSA.toPublicJWK()); + JWKS_FILE = File.createTempFile("oauth_", ".jwks"); + JWKS_FILE.deleteOnExit(); + + try (OutputStream os = new FileOutputStream(JWKS_FILE); + OutputStreamWriter osw = new OutputStreamWriter(os)) { + osw.write(jwkSet.toString(true)); + } + } + + private String generateBase64EncodedToken(String principal) throws JOSEException { + JWSSigner signer = new RSASSASigner(RSA); + LocalDate now = LocalDate.now(); + + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject(principal) + .issuer("https://some.fake.random.url/") + .expirationTime(java.sql.Date.valueOf(now.plusDays(1))) + .build(); + + SignedJWT signedJWT = new SignedJWT( + new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(RSA.getKeyID()).build(), claimsSet); + + signedJWT.sign(signer); + + return signedJWT.serialize(); + } + + private TableName getTestTableName() { + return TableName.valueOf(testName.getMethodName().replaceAll("[^0-9A-Za-z]", "_")); + } + + @Test + public void testOAuthBearerLogin() throws IOException, JOSEException { + TableName tableName = getTestTableName(); + byte[] family = Bytes.toBytes("f"); + byte[] qualifier = Bytes.toBytes("q"); + byte[] row = Bytes.toBytes("row"); + byte[] value = Bytes.toBytes("data"); + + User user = User.createUserForTesting(TEST_UTIL.getConfiguration(), "testuser_jwt", + new String[] {}); + OAuthBearerTokenUtil.addTokenForUser(user, generateBase64EncodedToken(user.getName()), 0); + + try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration(), user)) { + Admin admin = conn.getAdmin(); + TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName) + .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build(); + admin.createTable(tableDescriptor); + try (Table table = conn.getTable(tableName)) { + table.put(new Put(row).addColumn(family, qualifier, value)); + Result result = table.get(new Get(row)); + assertArrayEquals(value, result.getValue(family, qualifier)); + } + } + } +} From 802d7dc0954981541aa5a87a3957c432c9ec3908 Mon Sep 17 00:00:00 2001 From: Andor Molnar Date: Fri, 21 Jan 2022 11:54:17 +0100 Subject: [PATCH 2/2] HBASE-26665. Add issuer and audience filters --- .../security/token/TestOAuthBearerAuthentication.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java index 3ff84ab41958..ad799d7a20c9 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/token/TestOAuthBearerAuthentication.java @@ -66,6 +66,9 @@ public class TestOAuthBearerAuthentication extends SecureTestCluster { public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestOAuthBearerAuthentication.class); + private static final String AUDIENCE = "valid-hbase-instance"; + private static final String ISSUER = "authorized-issuer"; + private static RSAKey RSA; private static File JWKS_FILE; @@ -73,7 +76,6 @@ public class TestOAuthBearerAuthentication extends SecureTestCluster { public static void setUp() throws Exception { initRSA(); - //TEST_UTIL.getConfiguration().set("hbase.rpc.protection", "privacy"); TEST_UTIL.getConfiguration().set("hbase.client.sasl.provider.extras", "org.apache.hadoop.hbase.security.provider.OAuthBearerSaslClientAuthenticationProvider"); TEST_UTIL.getConfiguration().set("hbase.server.sasl.provider.extras", @@ -82,6 +84,8 @@ public static void setUp() throws Exception { "org.apache.hadoop.hbase.security.provider.OAuthBearerSaslProviderSelector"); TEST_UTIL.getConfiguration().set("hbase.security.oauth.jwt.jwks.file", JWKS_FILE.getAbsolutePath()); + TEST_UTIL.getConfiguration().set("hbase.security.oauth.jwt.audience", AUDIENCE); + TEST_UTIL.getConfiguration().set("hbase.security.oauth.jwt.issuer", ISSUER); SecureTestCluster.setUp(); } @@ -110,7 +114,8 @@ private String generateBase64EncodedToken(String principal) throws JOSEException JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() .subject(principal) - .issuer("https://some.fake.random.url/") + .issuer(ISSUER) + .audience(AUDIENCE) .expirationTime(java.sql.Date.valueOf(now.plusDays(1))) .build();