diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/utils/CRLCodec.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLCodec.java similarity index 99% rename from hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/utils/CRLCodec.java rename to hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLCodec.java index 19a6f58dd3ba..e9a52be2bd3b 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/utils/CRLCodec.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLCodec.java @@ -16,7 +16,7 @@ * limitations under the License. * */ -package org.apache.hadoop.hdds.security.x509.certificate.utils; +package org.apache.hadoop.hdds.security.x509.crl; import org.apache.commons.io.IOUtils; import org.apache.hadoop.hdds.security.exception.SCMSecurityException; diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfo.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfo.java similarity index 98% rename from hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfo.java rename to hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfo.java index cd9c218469f5..633cbcb2238a 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfo.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfo.java @@ -20,7 +20,6 @@ import org.apache.hadoop.hdds.protocol.proto.HddsProtos; import org.apache.hadoop.hdds.security.exception.SCMSecurityException; -import org.apache.hadoop.hdds.security.x509.certificate.utils.CRLCodec; import org.jetbrains.annotations.NotNull; import java.io.IOException; diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/CRLInfoCodec.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfoCodec.java similarity index 94% rename from hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/CRLInfoCodec.java rename to hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfoCodec.java index 0280d7bb0d5f..3178cfdc3bbf 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/CRLInfoCodec.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/CRLInfoCodec.java @@ -16,11 +16,10 @@ * limitations under the License. * */ -package org.apache.hadoop.hdds.scm.metadata; +package org.apache.hadoop.hdds.security.x509.crl; import com.google.common.base.Preconditions; import org.apache.hadoop.hdds.protocol.proto.HddsProtos; -import org.apache.hadoop.hdds.security.x509.crl.CRLInfo; import org.apache.hadoop.hdds.utils.db.Codec; import java.io.IOException; diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/package-info.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/package-info.java new file mode 100644 index 000000000000..4fa5c7679cb8 --- /dev/null +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/crl/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + * + */ + + +/** + * This package contains common routines used in creating an x509 CRL. + */ +package org.apache.hadoop.hdds.security.x509.crl; diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/Codec.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/Codec.java similarity index 100% rename from hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/Codec.java rename to hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/Codec.java diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/package-info.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/package-info.java new file mode 100644 index 000000000000..5bd80b2dc4e1 --- /dev/null +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/utils/db/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This package contains common db util classes. + */ +package org.apache.hadoop.hdds.utils.db; diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java index 90ea07339c30..62e916ad3c73 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java @@ -125,7 +125,10 @@ public final class OzoneConsts { */ public static final String CONTAINER_DB_SUFFIX = "container.db"; public static final String PIPELINE_DB_SUFFIX = "pipeline.db"; + public static final String CRL_DB_SUFFIX = "crl.db"; public static final String DN_CONTAINER_DB = "-dn-"+ CONTAINER_DB_SUFFIX; + public static final String DN_CRL_DB = "dn-"+ CRL_DB_SUFFIX; + public static final String CRL_DB_DIRECTORY_NAME = "crl"; public static final String OM_DB_NAME = "om.db"; public static final String SCM_DB_NAME = "scm.db"; public static final String OM_DB_BACKUP_PREFIX = "om.db.backup."; diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/CRLDBDefinition.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/CRLDBDefinition.java new file mode 100644 index 000000000000..5dbb49e5d8c1 --- /dev/null +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/CRLDBDefinition.java @@ -0,0 +1,99 @@ +/* + * 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.hdds.datanode.metadata; + +import com.google.common.base.Preconditions; + +import org.apache.hadoop.hdds.HddsUtils; +import org.apache.hadoop.hdds.conf.ConfigurationSource; +import org.apache.hadoop.hdds.security.x509.certificate.client.DNCertificateClient; +import org.apache.hadoop.hdds.security.x509.crl.CRLInfo; +import org.apache.hadoop.hdds.security.x509.crl.CRLInfoCodec; +import org.apache.hadoop.hdds.utils.db.DBColumnFamilyDefinition; +import org.apache.hadoop.hdds.utils.db.DBDefinition; +import org.apache.hadoop.hdds.utils.db.LongCodec; +import org.apache.hadoop.hdds.utils.db.StringCodec; +import org.apache.hadoop.ozone.OzoneConsts; + +import java.io.File; + +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_METADATA_DIR_NAME; +import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS; +import static org.apache.hadoop.hdds.scm.ScmConfigKeys.HDDS_DATANODE_DIR_KEY; + +/** + * Class defines the structure and types of the crl.db. + */ +public class CRLDBDefinition implements DBDefinition { + + public static final DBColumnFamilyDefinition PENDING_CRLS = + new DBColumnFamilyDefinition<>( + "pendingCrls", + Long.class, + new LongCodec(), + CRLInfo.class, + new CRLInfoCodec()); + + public static final DBColumnFamilyDefinition + CRL_SEQUENCE_ID = + new DBColumnFamilyDefinition<>( + "crlSequenceId", + String.class, + new StringCodec(), + Long.class, + new LongCodec()); + + @Override + public String getName() { + return OzoneConsts.DN_CRL_DB; + } + + @Override + public String getLocationConfigKey() { + throw new UnsupportedOperationException( + "No location config key available for datanode databases."); + } + + @Override + public File getDBLocation(ConfigurationSource conf) { + // Please Note: To make it easy for our customers we will attempt to read + // HDDS metadata dir and if that is not set, we will use Ozone directory. + // TODO: We might want to fix this later. + String metadataDir = conf.get(HDDS_METADATA_DIR_NAME, + conf.get(OZONE_METADATA_DIRS, + conf.get(HDDS_DATANODE_DIR_KEY))); + Preconditions.checkNotNull(metadataDir, "Metadata directory can't be" + + " null. Please check configs."); + + // create directories in the path if they do not already exist + HddsUtils.createDir(metadataDir + + File.separator + + DNCertificateClient.COMPONENT_NAME); + + return HddsUtils.createDir(metadataDir + + File.separator + + DNCertificateClient.COMPONENT_NAME + + File.separator + + OzoneConsts.CRL_DB_DIRECTORY_NAME); + } + + @Override + public DBColumnFamilyDefinition[] getColumnFamilies() { + return new DBColumnFamilyDefinition[] {PENDING_CRLS, CRL_SEQUENCE_ID}; + } +} diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/DatanodeCRLStore.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/DatanodeCRLStore.java new file mode 100644 index 000000000000..0dc606f860ed --- /dev/null +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/DatanodeCRLStore.java @@ -0,0 +1,84 @@ +/* + * 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.hdds.datanode.metadata; + +import com.google.common.annotations.VisibleForTesting; +import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.security.x509.crl.CRLInfo; +import org.apache.hadoop.hdds.utils.db.DBStore; +import org.apache.hadoop.hdds.utils.db.Table; + +import java.io.IOException; +import java.util.List; + +/** + * Generic interface for data stores for Datanode. + * This is similar to the OMMetadataStore class, + * where we write classes into some underlying storage system. + */ +public interface DatanodeCRLStore { + + /** + * Start metadata manager. + * + * @param configuration - Configuration + * @throws IOException - Unable to start metadata store. + */ + void start(OzoneConfiguration configuration) throws IOException; + + /** + * Stop metadata manager. + */ + void stop() throws Exception; + + /** + * Get metadata store. + * + * @return metadata store. + */ + @VisibleForTesting + DBStore getStore(); + + /** + * A table to store the latest processed CRL sequence Id. + * @return Table + */ + Table getCRLSequenceIdTable(); + + /** + * A table to store all the pending CRLs for future revocation of + * certificates. + * @return Table + */ + Table getPendingCRLsTable(); + + /** + * Returns the latest processed CRL Sequence ID. + * @return CRL Sequence ID. + * @throws IOException on error. + */ + Long getLatestCRLSequenceID() throws IOException; + + /** + * Return a list of CRLs that are pending revocation. + * @return a list of CRLInfo. + * @throws IOException on error. + */ + List getPendingCRLs() throws IOException; + +} diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/DatanodeCRLStoreImpl.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/DatanodeCRLStoreImpl.java new file mode 100644 index 000000000000..67827b962ee6 --- /dev/null +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/DatanodeCRLStoreImpl.java @@ -0,0 +1,127 @@ +/* + * 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.hdds.datanode.metadata; + +import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.security.x509.crl.CRLInfo; +import org.apache.hadoop.hdds.utils.db.DBStore; +import org.apache.hadoop.hdds.utils.db.DBStoreBuilder; +import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.hdds.utils.db.TableIterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.apache.hadoop.hdds.datanode.metadata.CRLDBDefinition.CRL_SEQUENCE_ID; +import static org.apache.hadoop.hdds.datanode.metadata.CRLDBDefinition.PENDING_CRLS; +import static org.apache.hadoop.ozone.OzoneConsts.CRL_SEQUENCE_ID_KEY; + +/** + * A RocksDB based implementation of the Datanode CRL Store. + */ +public class DatanodeCRLStoreImpl implements DatanodeCRLStore { + + private static final Logger LOG = + LoggerFactory.getLogger(DatanodeCRLStore.class); + private DBStore store; + private Table crlSequenceIdTable; + private Table pendingCRLsTable; + + /** + * Constructs the metadata store and starts the DB Services. + * + * @param configuration - Ozone Configuration. + * @throws IOException - on Failure. + */ + public DatanodeCRLStoreImpl(OzoneConfiguration configuration) + throws IOException { + start(configuration); + } + + @Override + public void start(OzoneConfiguration configuration) throws IOException { + if (this.store == null) { + this.store = DBStoreBuilder.createDBStore(configuration, + new CRLDBDefinition()); + + crlSequenceIdTable = CRL_SEQUENCE_ID.getTable(store); + checkTableStatus(crlSequenceIdTable, CRL_SEQUENCE_ID.getName()); + + pendingCRLsTable = PENDING_CRLS.getTable(store); + checkTableStatus(pendingCRLsTable, PENDING_CRLS.getName()); + } + } + + @Override + public void stop() throws Exception { + if (store != null) { + store.close(); + store = null; + } + } + + @Override + public DBStore getStore() { + return this.store; + } + + @Override + public Table getCRLSequenceIdTable() { + return crlSequenceIdTable; + } + + @Override + public Table getPendingCRLsTable() { + return pendingCRLsTable; + } + + @Override + public Long getLatestCRLSequenceID() throws IOException { + Long sequenceId = crlSequenceIdTable.get(CRL_SEQUENCE_ID_KEY); + // If the CRL_SEQUENCE_ID_KEY does not exist in DB return 0 + if (sequenceId == null) { + return 0L; + } + return sequenceId; + } + + @Override + public List getPendingCRLs() throws IOException { + TableIterator> iter = + pendingCRLsTable.iterator(); + List pendingCRLs = new ArrayList<>(); + while (iter.hasNext()) { + pendingCRLs.add(iter.next().getValue()); + } + return pendingCRLs; + } + + private void checkTableStatus(Table table, String name) throws IOException { + String logMessage = "Unable to get a reference to %s table. Cannot " + + "continue."; + String errMsg = "Inconsistent DB state, Table - %s. Please check the logs" + + "for more info."; + if (table == null) { + LOG.error(String.format(logMessage, name)); + throw new IOException(String.format(errMsg, name)); + } + } +} diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/package-info.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/package-info.java new file mode 100644 index 000000000000..4ca917c4747b --- /dev/null +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/hdds/datanode/metadata/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This package contains classes for Datanode metadata definitions. + */ +package org.apache.hadoop.hdds.datanode.metadata; diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/HddsDatanodeService.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/HddsDatanodeService.java index b582e4990d9a..baa5889f140c 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/HddsDatanodeService.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/HddsDatanodeService.java @@ -40,6 +40,8 @@ import org.apache.hadoop.hdds.cli.HddsVersionProvider; import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.datanode.metadata.DatanodeCRLStore; +import org.apache.hadoop.hdds.datanode.metadata.DatanodeCRLStoreImpl; import org.apache.hadoop.hdds.protocol.DatanodeDetails; import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto; import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB; @@ -104,6 +106,7 @@ public class HddsDatanodeService extends GenericCli implements ServicePlugin { private DNMXBeanImpl serviceRuntimeInfo = new DNMXBeanImpl(HddsVersionInfo.HDDS_VERSION_INFO) {}; private ObjectName dnInfoBeanName; + private DatanodeCRLStore dnCRLStore; //Constructor for DataNode PluginService public HddsDatanodeService(){} @@ -242,6 +245,10 @@ public void start() { } LOG.info("Hdds Datanode login successful."); } + + // initialize datanode CRL store + dnCRLStore = new DatanodeCRLStoreImpl(conf); + if (OzoneSecurityUtil.isSecurityEnabled(conf)) { initializeCertificateClient(conf); } @@ -523,6 +530,11 @@ public DatanodeStateMachine getDatanodeStateMachine() { return datanodeStateMachine; } + @VisibleForTesting + public DatanodeCRLStore getCRLStore() { + return dnCRLStore; + } + public void join() { if (datanodeStateMachine != null) { try { @@ -539,7 +551,6 @@ public void terminateDatanode() { terminate(1); } - @Override public void stop() { if (!isStopped.getAndSet(true)) { @@ -564,6 +575,12 @@ public void stop() { } } unregisterMXBean(); + // stop dn crl store + try { + dnCRLStore.stop(); + } catch (Exception ex) { + LOG.error("Datanode CRL store stop failed", ex); + } } } diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/hdds/datanode/metadata/TestDatanodeCRLStoreImpl.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/hdds/datanode/metadata/TestDatanodeCRLStoreImpl.java new file mode 100644 index 000000000000..eddec1f8e21b --- /dev/null +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/hdds/datanode/metadata/TestDatanodeCRLStoreImpl.java @@ -0,0 +1,127 @@ +/* + * 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.hdds.datanode.metadata; + +import org.apache.hadoop.fs.FileUtil; +import org.apache.hadoop.hdds.HddsConfigKeys; +import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.security.x509.SecurityConfig; +import org.apache.hadoop.hdds.security.x509.certificate.authority.CRLApprover; +import org.apache.hadoop.hdds.security.x509.certificate.authority.DefaultCRLApprover; +import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec; +import org.apache.hadoop.hdds.security.x509.crl.CRLInfo; +import org.apache.hadoop.ozone.OzoneConsts; +import org.apache.hadoop.security.ssl.KeyStoreTestUtil; +import org.apache.hadoop.test.GenericTestUtils; +import org.bouncycastle.asn1.x509.CRLReason; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v2CRLBuilder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.security.KeyPair; +import java.security.cert.X509Certificate; +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Test class for {@link DatanodeCRLStoreImpl}. + */ +public class TestDatanodeCRLStoreImpl { + private File testDir; + private OzoneConfiguration conf; + private DatanodeCRLStore dnCRLStore; + private KeyPair keyPair; + private CRLApprover crlApprover; + private SecurityConfig securityConfig; + + @Before + public void setUp() throws Exception { + testDir = GenericTestUtils.getRandomizedTestDir(); + conf = new OzoneConfiguration(); + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, testDir.getPath()); + dnCRLStore = new DatanodeCRLStoreImpl(conf); + keyPair = KeyStoreTestUtil.generateKeyPair("RSA"); + securityConfig = new SecurityConfig(conf); + } + + @Before + public void initCRLApprover() { + crlApprover = new DefaultCRLApprover(securityConfig, + keyPair.getPrivate()); + } + + @After + public void tearDown() { + FileUtil.fullyDelete(testDir); + } + + @After + public void destroyDbStore() throws Exception { + if (dnCRLStore.getStore() != null) { + dnCRLStore.getStore().close(); + } + } + @Test + public void testCRLStore() throws Exception { + assertNotNull(dnCRLStore.getStore()); + + dnCRLStore.getCRLSequenceIdTable().put(OzoneConsts.CRL_SEQUENCE_ID_KEY, 5L); + Date now = new Date(); + X509Certificate x509Certificate = generateX509Cert(); + X509CertificateHolder caCertificateHolder = + new X509CertificateHolder(generateX509Cert().getEncoded()); + X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder( + caCertificateHolder.getIssuer(), now); + crlBuilder.addCRLEntry(x509Certificate.getSerialNumber(), now, + CRLReason.lookup(CRLReason.PRIVILEGE_WITHDRAWN).getValue().intValue()); + dnCRLStore.getPendingCRLsTable().put(1L, + new CRLInfo.Builder() + .setCrlSequenceID(1L) + .setCreationTimestamp(now.getTime()) + .setX509CRL(crlApprover.sign(crlBuilder)) + .build()); + + assertEquals(5L, (long) dnCRLStore.getLatestCRLSequenceID()); + assertEquals(1L, dnCRLStore.getPendingCRLs().size()); + CRLInfo crlInfo = dnCRLStore.getPendingCRLs().get(0); + assertEquals(1L, crlInfo.getCrlSequenceID()); + assertEquals(x509Certificate.getSerialNumber(), + crlInfo.getX509CRL().getRevokedCertificates() + .iterator().next().getSerialNumber()); + + // Test that restarting the store does not affect the data already persisted + dnCRLStore.stop(); + dnCRLStore = new DatanodeCRLStoreImpl(conf); + assertEquals(5L, (long) dnCRLStore.getLatestCRLSequenceID()); + assertEquals(1L, dnCRLStore.getPendingCRLs().size()); + dnCRLStore.stop(); + } + + private X509Certificate generateX509Cert() throws Exception { + return CertificateCodec.getX509Certificate( + CertificateCodec.getPEMEncodedString( + KeyStoreTestUtil.generateCertificate("CN=Test", keyPair, 30, + "SHA256withRSA"))); + } +} + diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/hdds/datanode/metadata/package-info.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/hdds/datanode/metadata/package-info.java new file mode 100644 index 000000000000..acc91fe727a9 --- /dev/null +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/hdds/datanode/metadata/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + * + */ +/** + * Datanode metadata Testing. + */ +package org.apache.hadoop.hdds.datanode.metadata; \ No newline at end of file diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java index 4aa4cabfc91f..dfec9a7a7fda 100644 --- a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -30,6 +30,7 @@ import org.junit.After; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import org.junit.Before; import org.junit.Test; @@ -67,8 +68,11 @@ public void testStartup() throws IOException { assertNotNull(service.getDatanodeDetails()); assertNotNull(service.getDatanodeDetails().getHostName()); assertFalse(service.getDatanodeStateMachine().isDaemonStopped()); + assertNotNull(service.getCRLStore()); service.stop(); + // CRL store must be stopped when the service stops + assertNull(service.getCRLStore().getStore()); service.join(); service.close(); } diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCRLApprover.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCRLApprover.java index 683905af6f87..a5a545b83ec7 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCRLApprover.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCRLApprover.java @@ -20,7 +20,7 @@ package org.apache.hadoop.hdds.security.x509.certificate.authority; import org.apache.hadoop.hdds.security.x509.SecurityConfig; -import org.apache.hadoop.hdds.security.x509.certificate.utils.CRLCodec; +import org.apache.hadoop.hdds.security.x509.crl.CRLCodec; import org.bouncycastle.cert.X509CRLHolder; import org.bouncycastle.cert.X509v2CRLBuilder; import org.bouncycastle.operator.OperatorCreationException; diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/utils/TestCRLCodec.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/utils/TestCRLCodec.java index 9413611f1d64..3d32a3312c79 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/utils/TestCRLCodec.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/utils/TestCRLCodec.java @@ -50,6 +50,7 @@ import org.apache.hadoop.hdds.conf.OzoneConfiguration; import org.apache.hadoop.hdds.security.x509.SecurityConfig; import org.apache.hadoop.hdds.security.x509.certificates.utils.SelfSignedCertificate; +import org.apache.hadoop.hdds.security.x509.crl.CRLCodec; import org.apache.hadoop.hdds.security.x509.keys.HDDSKeyGenerator; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.CRLReason; diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/SCMDBDefinition.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/SCMDBDefinition.java index 9150c05f475e..7da36d10a9cf 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/SCMDBDefinition.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/metadata/SCMDBDefinition.java @@ -25,6 +25,7 @@ import org.apache.hadoop.hdds.scm.container.ContainerID; import org.apache.hadoop.hdds.scm.container.ContainerInfo; import org.apache.hadoop.hdds.security.x509.certificate.CertInfo; +import org.apache.hadoop.hdds.security.x509.crl.CRLInfoCodec; import org.apache.hadoop.hdds.utils.TransactionInfo; import org.apache.hadoop.hdds.security.x509.crl.CRLInfo; import org.apache.hadoop.hdds.scm.pipeline.Pipeline;