From e644a17a8b18115327cab0585c940d6566374cd7 Mon Sep 17 00:00:00 2001 From: Prashant Pogde Date: Fri, 10 Jul 2020 17:03:05 -0700 Subject: [PATCH 1/4] HDDS-3926. OM Token Identifier table should use in-house serialization. --- .../ozone/security/OzoneTokenIdentifier.java | 122 +++++++++++++++++- .../ozone/om/codec/TokenIdentifierCodec.java | 8 +- 2 files changed, 124 insertions(+), 6 deletions(-) diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java index 290dd1d4f95f..fe6df19b0e36 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java @@ -21,6 +21,9 @@ import java.io.DataInputStream; import java.io.DataOutput; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import org.apache.commons.lang3.builder.EqualsBuilder; @@ -77,6 +80,122 @@ public Text getKind() { return KIND_NAME; } + /** Instead of relying on proto serialization, this + * provides explicit serialization for OzoneTokenIdentifier. + * @return byte[] + */ + public byte[] toUniqueSerializedKey() { + ByteBuffer result = + ByteBuffer.allocate(4096); + result.order(ByteOrder.BIG_ENDIAN); + try { + result.putLong(getIssueDate()); + result.putInt(getMasterKeyId()); + result.putInt(getSequenceNumber()); + + result.putLong(getMaxDate()); + + result.putInt(getOwner().toString().length()); + result.put(getOwner().toString().getBytes(StandardCharsets.UTF_8)); + + result.putInt(getRealUser().toString().length()); + result.put(getRealUser().toString().getBytes(StandardCharsets.UTF_8)); + + result.putInt(getRenewer().toString().length()); + result.put(getRenewer().toString().getBytes(StandardCharsets.UTF_8)); + + result.putInt(getTokenType().getNumber()); + // Set s3 specific fields. + if (getTokenType().equals(S3AUTHINFO)) { + result.putInt(getAwsAccessId().length()); + result.put(getAwsAccessId().getBytes(StandardCharsets.UTF_8)); + + result.putInt(getSignature().length()); + result.put(getSignature().getBytes(StandardCharsets.UTF_8)); + + result.putInt(getStrToSign().length()); + result.put(getStrToSign().getBytes(StandardCharsets.UTF_8)); + } else { + result.putInt(getOmCertSerialId().length()); + result.put(getOmCertSerialId().getBytes(StandardCharsets.UTF_8)); + if (getOmServiceId() != null) { + result.putInt(getOmServiceId().length()); + result.put(getOmServiceId().getBytes(StandardCharsets.UTF_8)); + } else { + result.putInt(0); + } + } + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException( + "Can't encode the the raw data ", e); + } + return result.array(); + } + + /** Instead of relying on proto deserialization, this + * provides explicit deserialization for OzoneTokenIdentifier. + * @return byte[] + */ + public static OzoneTokenIdentifier fromUniqueSerializedKey(byte[] rawData) { + OzoneTokenIdentifier result = newInstance(); + ByteBuffer inbuf = ByteBuffer.wrap(rawData); + inbuf.order(ByteOrder.BIG_ENDIAN); + result.setIssueDate(inbuf.getLong()); + result.setMasterKeyId(inbuf.getInt()); + result.setSequenceNumber(inbuf.getInt()); + + result.setMaxDate(inbuf.getLong()); + + int strsize = 0; + strsize = inbuf.getInt(); + byte[] ownerBytes = new byte[strsize]; + inbuf.get(ownerBytes); + result.setOwner(new Text(ownerBytes)); + + strsize = inbuf.getInt(); + byte[] ruserBytes = new byte[strsize]; + inbuf.get(ruserBytes); + result.setRealUser(new Text(ruserBytes)); + + strsize = inbuf.getInt(); + byte[] renewerBytes = new byte[strsize]; + inbuf.get(renewerBytes); + result.setRenewer(new Text(renewerBytes)); + + // Set s3 specific fields. + if (inbuf.getInt() == S3AUTHINFO.getNumber()) { + strsize = inbuf.getInt(); + byte[] awsAccessIdBytes = new byte[strsize]; + inbuf.get(awsAccessIdBytes); + result.setAwsAccessId(new String(awsAccessIdBytes, + StandardCharsets.UTF_8)); + + strsize = inbuf.getInt(); + byte[] signatureBytes = new byte[strsize]; + inbuf.get(signatureBytes); + result.setSignature(new String(signatureBytes, StandardCharsets.UTF_8)); + + strsize = inbuf.getInt(); + byte[] strToSignBytes = new byte[strsize]; + inbuf.get(strToSignBytes); + result.setStrToSign(new String(strToSignBytes, StandardCharsets.UTF_8)); + } else { + strsize = inbuf.getInt(); + byte[] omCertIdBytes = new byte[strsize]; + inbuf.get(omCertIdBytes); + result.setOmCertSerialId(new String(omCertIdBytes, + StandardCharsets.UTF_8)); + int nextStrsize = inbuf.getInt(); + if (nextStrsize != 0) { + byte[] omServiceIdBytes = new byte[nextStrsize]; + inbuf.get(omServiceIdBytes); + result.setOmServiceId(new String(omServiceIdBytes, + StandardCharsets.UTF_8)); + } + } + return result; + } + /** * Overrides default implementation to write using Protobuf. * @@ -92,7 +211,6 @@ public void write(DataOutput out) throws IOException { .setRealUser(getRealUser().toString()) .setRenewer(getRenewer().toString()) .setIssueDate(getIssueDate()) - .setMaxDate(getMaxDate()) .setSequenceNumber(getSequenceNumber()) .setMasterKeyId(getMasterKeyId()); @@ -332,4 +450,4 @@ public String toString() { .append(", omServiceId=").append(getOmServiceId()); return buffer.toString(); } -} \ No newline at end of file +} diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java index 22656d887b66..0b1a62d9a0af 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java @@ -18,11 +18,11 @@ package org.apache.hadoop.ozone.om.codec; import com.google.common.base.Preconditions; -import com.google.protobuf.InvalidProtocolBufferException; import org.apache.hadoop.ozone.security.OzoneTokenIdentifier; import org.apache.hadoop.hdds.utils.db.Codec; import java.io.IOException; +import java.nio.BufferUnderflowException; /** * Codec to encode TokenIdentifierCodec as byte array. @@ -33,7 +33,7 @@ public class TokenIdentifierCodec implements Codec { public byte[] toPersistedFormat(OzoneTokenIdentifier object) { Preconditions .checkNotNull(object, "Null object can't be converted to byte array."); - return object.getBytes(); + return object.toUniqueSerializedKey(); } @Override @@ -42,8 +42,8 @@ public OzoneTokenIdentifier fromPersistedFormat(byte[] rawData) Preconditions.checkNotNull(rawData, "Null byte array can't converted to real object."); try { - return OzoneTokenIdentifier.readProtoBuf(rawData); - } catch (InvalidProtocolBufferException e) { + return OzoneTokenIdentifier.fromUniqueSerializedKey(rawData); + } catch (BufferUnderflowException e) { throw new IllegalArgumentException( "Can't encode the the raw data from the byte array", e); } From ba3da0e52b99ce26d8475ee815144c6a1921519d Mon Sep 17 00:00:00 2001 From: Prashant Pogde Date: Tue, 14 Jul 2020 00:03:48 -0700 Subject: [PATCH 2/4] HDDS-3926. OM Token Identifier: Serialization changes after code review. --- .../ozone/security/OzoneTokenIdentifier.java | 122 +++++------------- .../ozone/om/codec/TokenIdentifierCodec.java | 3 +- 2 files changed, 31 insertions(+), 94 deletions(-) diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java index fe6df19b0e36..181c79bdd790 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java @@ -21,21 +21,22 @@ import java.io.DataInputStream; import java.io.DataOutput; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.annotation.InterfaceStability; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.io.DataOutputBuffer; import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.WritableUtils; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMTokenProto; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMTokenProto.Type; import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMTokenProto.Type.S3AUTHINFO; + /** * The token identifier for Ozone Master. */ @@ -85,115 +86,50 @@ public Text getKind() { * @return byte[] */ public byte[] toUniqueSerializedKey() { - ByteBuffer result = - ByteBuffer.allocate(4096); - result.order(ByteOrder.BIG_ENDIAN); + DataOutputBuffer buf = new DataOutputBuffer(); try { - result.putLong(getIssueDate()); - result.putInt(getMasterKeyId()); - result.putInt(getSequenceNumber()); - - result.putLong(getMaxDate()); - - result.putInt(getOwner().toString().length()); - result.put(getOwner().toString().getBytes(StandardCharsets.UTF_8)); - - result.putInt(getRealUser().toString().length()); - result.put(getRealUser().toString().getBytes(StandardCharsets.UTF_8)); - - result.putInt(getRenewer().toString().length()); - result.put(getRenewer().toString().getBytes(StandardCharsets.UTF_8)); - - result.putInt(getTokenType().getNumber()); + super.write(buf); + WritableUtils.writeVInt(buf, getTokenType().getNumber()); // Set s3 specific fields. if (getTokenType().equals(S3AUTHINFO)) { - result.putInt(getAwsAccessId().length()); - result.put(getAwsAccessId().getBytes(StandardCharsets.UTF_8)); - - result.putInt(getSignature().length()); - result.put(getSignature().getBytes(StandardCharsets.UTF_8)); - - result.putInt(getStrToSign().length()); - result.put(getStrToSign().getBytes(StandardCharsets.UTF_8)); + WritableUtils.writeString(buf, getAwsAccessId()); + WritableUtils.writeString(buf, getSignature()); + WritableUtils.writeString(buf, getStrToSign()); } else { - result.putInt(getOmCertSerialId().length()); - result.put(getOmCertSerialId().getBytes(StandardCharsets.UTF_8)); + WritableUtils.writeString(buf, getOmCertSerialId()); if (getOmServiceId() != null) { - result.putInt(getOmServiceId().length()); - result.put(getOmServiceId().getBytes(StandardCharsets.UTF_8)); - } else { - result.putInt(0); + WritableUtils.writeString(buf, getOmServiceId()); } } - } catch (IndexOutOfBoundsException e) { + } catch (java.io.IOException e) { throw new IllegalArgumentException( "Can't encode the the raw data ", e); } - return result.array(); + return buf.getData(); } /** Instead of relying on proto deserialization, this * provides explicit deserialization for OzoneTokenIdentifier. * @return byte[] */ - public static OzoneTokenIdentifier fromUniqueSerializedKey(byte[] rawData) { - OzoneTokenIdentifier result = newInstance(); - ByteBuffer inbuf = ByteBuffer.wrap(rawData); - inbuf.order(ByteOrder.BIG_ENDIAN); - result.setIssueDate(inbuf.getLong()); - result.setMasterKeyId(inbuf.getInt()); - result.setSequenceNumber(inbuf.getInt()); - - result.setMaxDate(inbuf.getLong()); - - int strsize = 0; - strsize = inbuf.getInt(); - byte[] ownerBytes = new byte[strsize]; - inbuf.get(ownerBytes); - result.setOwner(new Text(ownerBytes)); - - strsize = inbuf.getInt(); - byte[] ruserBytes = new byte[strsize]; - inbuf.get(ruserBytes); - result.setRealUser(new Text(ruserBytes)); - - strsize = inbuf.getInt(); - byte[] renewerBytes = new byte[strsize]; - inbuf.get(renewerBytes); - result.setRenewer(new Text(renewerBytes)); - + public OzoneTokenIdentifier fromUniqueSerializedKey(byte[] rawData) + throws IOException { + DataInputBuffer in = new DataInputBuffer(); + in.reset(rawData, rawData.length); + super.readFields(in); + int type = WritableUtils.readVInt(in); // Set s3 specific fields. - if (inbuf.getInt() == S3AUTHINFO.getNumber()) { - strsize = inbuf.getInt(); - byte[] awsAccessIdBytes = new byte[strsize]; - inbuf.get(awsAccessIdBytes); - result.setAwsAccessId(new String(awsAccessIdBytes, - StandardCharsets.UTF_8)); - - strsize = inbuf.getInt(); - byte[] signatureBytes = new byte[strsize]; - inbuf.get(signatureBytes); - result.setSignature(new String(signatureBytes, StandardCharsets.UTF_8)); - - strsize = inbuf.getInt(); - byte[] strToSignBytes = new byte[strsize]; - inbuf.get(strToSignBytes); - result.setStrToSign(new String(strToSignBytes, StandardCharsets.UTF_8)); + if (type == S3AUTHINFO.getNumber()) { + this.tokenType = Type.S3AUTHINFO; + setAwsAccessId(WritableUtils.readString(in)); + setSignature(WritableUtils.readString(in)); + setStrToSign(WritableUtils.readString(in)); } else { - strsize = inbuf.getInt(); - byte[] omCertIdBytes = new byte[strsize]; - inbuf.get(omCertIdBytes); - result.setOmCertSerialId(new String(omCertIdBytes, - StandardCharsets.UTF_8)); - int nextStrsize = inbuf.getInt(); - if (nextStrsize != 0) { - byte[] omServiceIdBytes = new byte[nextStrsize]; - inbuf.get(omServiceIdBytes); - result.setOmServiceId(new String(omServiceIdBytes, - StandardCharsets.UTF_8)); - } + this.tokenType = Type.DELEGATION_TOKEN; + setOmCertSerialId(WritableUtils.readString(in)); + setOmServiceId(WritableUtils.readString(in)); } - return result; + return this; } /** diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java index 0b1a62d9a0af..d11353d2d4ec 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java @@ -42,7 +42,8 @@ public OzoneTokenIdentifier fromPersistedFormat(byte[] rawData) Preconditions.checkNotNull(rawData, "Null byte array can't converted to real object."); try { - return OzoneTokenIdentifier.fromUniqueSerializedKey(rawData); + OzoneTokenIdentifier object = OzoneTokenIdentifier.newInstance(); + return object.fromUniqueSerializedKey(rawData); } catch (BufferUnderflowException e) { throw new IllegalArgumentException( "Can't encode the the raw data from the byte array", e); From a164a675f953579b7226e298a829f15ff1bfc87e Mon Sep 17 00:00:00 2001 From: Prashant Pogde Date: Tue, 14 Jul 2020 09:33:51 -0700 Subject: [PATCH 3/4] HDDS-3926. Part3: OM Token Identifier: Serialization changes after code review. --- .../apache/hadoop/ozone/security/OzoneTokenIdentifier.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java index 181c79bdd790..c0b1ddbd1dd9 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneTokenIdentifier.java @@ -97,9 +97,7 @@ public byte[] toUniqueSerializedKey() { WritableUtils.writeString(buf, getStrToSign()); } else { WritableUtils.writeString(buf, getOmCertSerialId()); - if (getOmServiceId() != null) { - WritableUtils.writeString(buf, getOmServiceId()); - } + WritableUtils.writeString(buf, getOmServiceId()); } } catch (java.io.IOException e) { throw new IllegalArgumentException( From cd999130a8485f07f852da6da947798117439913 Mon Sep 17 00:00:00 2001 From: Prashant Pogde Date: Thu, 16 Jul 2020 11:03:54 -0700 Subject: [PATCH 4/4] HDDS-3926. Part4: OM Token Identifier: Serialization changes after code review. --- .../ozone/om/codec/TokenIdentifierCodec.java | 9 +++++++++ .../security/TestOzoneTokenIdentifier.java | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java index d11353d2d4ec..592cae3a366c 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/TokenIdentifierCodec.java @@ -18,6 +18,8 @@ package org.apache.hadoop.ozone.om.codec; import com.google.common.base.Preconditions; +import com.google.protobuf.InvalidProtocolBufferException; + import org.apache.hadoop.ozone.security.OzoneTokenIdentifier; import org.apache.hadoop.hdds.utils.db.Codec; @@ -44,6 +46,13 @@ public OzoneTokenIdentifier fromPersistedFormat(byte[] rawData) try { OzoneTokenIdentifier object = OzoneTokenIdentifier.newInstance(); return object.fromUniqueSerializedKey(rawData); + } catch (IOException ex) { + try { + return OzoneTokenIdentifier.readProtoBuf(rawData); + } catch (InvalidProtocolBufferException e) { + throw new IllegalArgumentException( + "Can't encode the the raw data from the byte array", e); + } } catch (BufferUnderflowException e) { throw new IllegalArgumentException( "Can't encode the the raw data from the byte array", e); diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestOzoneTokenIdentifier.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestOzoneTokenIdentifier.java index 518953f91c62..391759a8df54 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestOzoneTokenIdentifier.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestOzoneTokenIdentifier.java @@ -47,6 +47,7 @@ import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.conf.OzoneConfiguration; import org.apache.hadoop.io.Text; +import org.apache.hadoop.ozone.om.codec.TokenIdentifierCodec; import org.apache.hadoop.security.ssl.KeyStoreTestUtil; import org.apache.hadoop.security.ssl.TestSSLFactory; import org.apache.hadoop.security.token.Token; @@ -327,4 +328,22 @@ public void testTokenSerialization() throws IOException { idDecode.readFields(in); Assert.assertEquals(idEncode, idDecode); } + + @Test + public void testTokenPersistence() throws IOException { + OzoneTokenIdentifier idWrite = getIdentifierInst(); + idWrite.setOmServiceId("defaultServiceId"); + + byte[] oldIdBytes = idWrite.getBytes(); + TokenIdentifierCodec idCodec = new TokenIdentifierCodec(); + + OzoneTokenIdentifier idRead = null; + try { + idRead = idCodec.fromPersistedFormat(oldIdBytes); + } catch (IOException ex) { + Assert.fail("Should not fail to load old token format"); + } + Assert.assertEquals("Deserialize Serialized Token should equal.", + idWrite, idRead); + } } \ No newline at end of file