-
Notifications
You must be signed in to change notification settings - Fork 435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce support for "Data Classification Specifications" on fetched resultsets #709
Changes from all commits
0132425
8831a5c
afcce51
f093457
4b8017f
9d8c15f
7844c4e
46a2062
0224a03
d696cf3
6a7da23
29e33c5
dd14563
c62fbcf
aea2736
b9d8988
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,9 @@ | |
import javax.net.ssl.TrustManager; | ||
import javax.net.ssl.TrustManagerFactory; | ||
import javax.net.ssl.X509TrustManager; | ||
|
||
import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityClassification; | ||
|
||
import java.nio.Buffer; | ||
|
||
final class TDS { | ||
|
@@ -100,9 +103,11 @@ final class TDS { | |
static final int TDS_DONEPROC = 0xFE; | ||
static final int TDS_DONEINPROC = 0xFF; | ||
static final int TDS_FEDAUTHINFO = 0xEE; | ||
static final int TDS_SQLRESCOLSRCS = 0xa2; | ||
static final int TDS_SQLDATACLASSIFICATION = 0xa3; | ||
|
||
// FedAuth | ||
static final int TDS_FEATURE_EXT_FEDAUTH = 0x02; | ||
static final byte TDS_FEATURE_EXT_FEDAUTH = 0x02; | ||
static final int TDS_FEDAUTH_LIBRARY_SECURITYTOKEN = 0x01; | ||
static final int TDS_FEDAUTH_LIBRARY_ADAL = 0x02; | ||
static final int TDS_FEDAUTH_LIBRARY_RESERVED = 0x7F; | ||
|
@@ -112,9 +117,17 @@ final class TDS { | |
static final byte FEDAUTH_INFO_ID_SPN = 0x02; // FedAuthInfoData is the SPN to use for acquiring fed auth token | ||
|
||
// AE constants | ||
static final int TDS_FEATURE_EXT_AE = 0x04; | ||
static final int MAX_SUPPORTED_TCE_VERSION = 0x01; // max version | ||
// 0x03 is for x_eFeatureExtensionId_Rcs | ||
static final byte TDS_FEATURE_EXT_AE = 0x04; | ||
static final byte MAX_SUPPORTED_TCE_VERSION = 0x01; // max version | ||
static final int CUSTOM_CIPHER_ALGORITHM_ID = 0; // max version | ||
// 0x06 is for x_eFeatureExtensionId_LoginToken | ||
// 0x07 is for x_eFeatureExtensionId_ClientSideTelemetry | ||
// Data Classification constants | ||
static final byte TDS_FEATURE_EXT_DATACLASSIFICATION = 0x09; | ||
static final byte DATA_CLASSIFICATION_NOT_ENABLED = 0x00; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
static final byte MAX_SUPPORTED_DATA_CLASSIFICATION_VERSION = 0x01; | ||
|
||
static final int AES_256_CBC = 1; | ||
static final int AEAD_AES_256_CBC_HMAC_SHA256 = 2; | ||
static final int AE_METADATA = 0x08; | ||
|
@@ -179,6 +192,8 @@ static final String getTokenName(int tdsTokenType) { | |
return "TDS_DONEINPROC (0xFF)"; | ||
case TDS_FEDAUTHINFO: | ||
return "TDS_FEDAUTHINFO (0xEE)"; | ||
case TDS_FEATURE_EXT_DATACLASSIFICATION: | ||
return "TDS_FEATURE_EXT_DATACLASSIFICATION (0x09)"; | ||
case TDS_FEATURE_EXT_UTF8SUPPORT: | ||
return "TDS_FEATURE_EXT_UTF8SUPPORT (0x0A)"; | ||
default: | ||
|
@@ -6335,7 +6350,7 @@ final TDSCommand getCommand() { | |
final SQLServerConnection getConnection() { | ||
return con; | ||
} | ||
|
||
private TDSPacket currentPacket = new TDSPacket(0); | ||
private TDSPacket lastPacket = currentPacket; | ||
private int payloadOffset = 0; | ||
|
@@ -6344,8 +6359,12 @@ final SQLServerConnection getConnection() { | |
private boolean isStreaming = true; | ||
private boolean useColumnEncryption = false; | ||
private boolean serverSupportsColumnEncryption = false; | ||
private boolean serverSupportsDataClassification = false; | ||
|
||
private final byte valueBytes[] = new byte[256]; | ||
|
||
protected SensitivityClassification sensitivityClassification; | ||
|
||
private static final AtomicInteger lastReaderID = new AtomicInteger(0); | ||
|
||
private static int nextReaderID() { | ||
|
@@ -6372,6 +6391,7 @@ private static int nextReaderID() { | |
useColumnEncryption = true; | ||
} | ||
serverSupportsColumnEncryption = con.getServerSupportsColumnEncryption(); | ||
serverSupportsDataClassification = con.getServerSupportsDataClassification(); | ||
} | ||
|
||
final boolean isColumnEncryptionSettingEnabled() { | ||
|
@@ -6382,6 +6402,10 @@ final boolean getServerSupportsColumnEncryption() { | |
return serverSupportsColumnEncryption; | ||
} | ||
|
||
final boolean getServerSupportsDataClassification() { | ||
return serverSupportsDataClassification; | ||
} | ||
|
||
final void throwInvalidTDS() throws SQLServerException { | ||
if (logger.isLoggable(Level.SEVERE)) | ||
logger.severe(toString() + " got unexpected value in TDS response at offset:" + payloadOffset); | ||
|
@@ -7073,7 +7097,7 @@ final void skip(int bytesToSkip) throws SQLServerException { | |
} | ||
} | ||
|
||
final void TryProcessFeatureExtAck(boolean featureExtAckReceived) throws SQLServerException { | ||
final void tryProcessFeatureExtAck(boolean featureExtAckReceived) throws SQLServerException { | ||
// in case of redirection, do not check if TDS_FEATURE_EXTENSION_ACK is received or not. | ||
if (null != this.con.getRoutingInfo()) { | ||
return; | ||
|
@@ -7082,6 +7106,10 @@ final void TryProcessFeatureExtAck(boolean featureExtAckReceived) throws SQLServ | |
if (isColumnEncryptionSettingEnabled() && !featureExtAckReceived) | ||
throw new SQLServerException(this, SQLServerException.getErrString("R_AE_NotSupportedByServer"), null, 0, false); | ||
} | ||
|
||
final void trySetSensitivityClassification(SensitivityClassification sensitivityClassification) { | ||
this.sensitivityClassification = sensitivityClassification; | ||
} | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,16 @@ | |
|
||
package com.microsoft.sqlserver.jdbc; | ||
|
||
import java.util.List; | ||
|
||
import com.microsoft.sqlserver.jdbc.dataclassification.ColumnSensitivity; | ||
import com.microsoft.sqlserver.jdbc.dataclassification.InformationType; | ||
import com.microsoft.sqlserver.jdbc.dataclassification.Label; | ||
import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityClassification; | ||
import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityProperty; | ||
|
||
import java.util.ArrayList; | ||
|
||
/** | ||
* StreamColumns stores the column meta data for a result set. StreamColumns parses the inbound TDS packet stream to determine column meta data. | ||
*/ | ||
|
@@ -210,6 +220,95 @@ void setFromTDS(TDSReader tdsReader) throws SQLServerException { | |
this.columns[numColumns] = new Column(typeInfo, columnName, tableName, null); | ||
} | ||
} | ||
|
||
// Data Classification | ||
if (tdsReader.getServerSupportsDataClassification() && tdsReader.peekTokenType() == TDS.TDS_SQLDATACLASSIFICATION) { | ||
// Read and parse | ||
tdsReader.trySetSensitivityClassification(processDataClassification(tdsReader)); | ||
} | ||
} | ||
|
||
private String readByteString(TDSReader tdsReader) throws SQLServerException { | ||
String value = ""; | ||
int byteLen = (int) tdsReader.readUnsignedByte(); | ||
value = tdsReader.readUnicodeString(byteLen); | ||
return value; | ||
} | ||
|
||
private Label readSensitivityLabel(TDSReader tdsReader) throws SQLServerException { | ||
String name = readByteString(tdsReader); | ||
String id = readByteString(tdsReader); | ||
return new Label(name, id); | ||
} | ||
|
||
private InformationType readSensitivityInformationType(TDSReader tdsReader) throws SQLServerException { | ||
String name = readByteString(tdsReader); | ||
String id = readByteString(tdsReader); | ||
return new InformationType(name, id); | ||
} | ||
|
||
private SensitivityClassification processDataClassification(TDSReader tdsReader) throws SQLServerException { | ||
if (!tdsReader.getServerSupportsDataClassification()) { | ||
tdsReader.throwInvalidTDS(); | ||
} | ||
|
||
int dataClassificationToken = tdsReader.readUnsignedByte(); | ||
assert dataClassificationToken == TDS.TDS_SQLDATACLASSIFICATION; | ||
|
||
SensitivityClassification sensitivityClassification = null; | ||
|
||
// get the label count | ||
int numLabels = tdsReader.readUnsignedShort(); | ||
List<Label> labels = new ArrayList<Label>(numLabels); | ||
|
||
for (int i = 0; i < numLabels; i++) { | ||
labels.add(readSensitivityLabel(tdsReader)); | ||
} | ||
|
||
// get the information type count | ||
int numInformationTypes = tdsReader.readUnsignedShort(); | ||
|
||
List<InformationType> informationTypes = new ArrayList<InformationType>(numInformationTypes); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should generally use LinkedLists over ArrayLists, seeing how little we do random access compared to iteration. Also |
||
for (int i = 0; i < numInformationTypes; i++) { | ||
informationTypes.add(readSensitivityInformationType(tdsReader)); | ||
} | ||
|
||
// get the per column classification data (corresponds to order of output columns for query) | ||
int numResultColumns = tdsReader.readUnsignedShort(); | ||
|
||
List<ColumnSensitivity> columnSensitivities = new ArrayList<ColumnSensitivity>(numResultColumns); | ||
for (int columnNum = 0; columnNum < numResultColumns; columnNum++) { | ||
|
||
// get sensitivity properties for all the different sources which were used in generating the column output | ||
int numSources = tdsReader.readUnsignedShort(); | ||
List<SensitivityProperty> sensitivityProperties = new ArrayList<SensitivityProperty>(numSources); | ||
for (int sourceNum = 0; sourceNum < numSources; sourceNum++) { | ||
|
||
// get the label index and then lookup label to use for source | ||
int labelIndex = tdsReader.readUnsignedShort(); | ||
Label label = null; | ||
if (labelIndex != Integer.MAX_VALUE) { | ||
if (labelIndex >= labels.size()) { | ||
tdsReader.throwInvalidTDS(); | ||
} | ||
label = labels.get(labelIndex); | ||
} | ||
|
||
// get the information type index and then lookup information type to use for source | ||
int informationTypeIndex = tdsReader.readUnsignedShort(); | ||
InformationType informationType = null; | ||
if (informationTypeIndex != Integer.MAX_VALUE) { | ||
if (informationTypeIndex >= informationTypes.size()) { | ||
} | ||
informationType = informationTypes.get(informationTypeIndex); | ||
} | ||
// add sensitivity properties for the source | ||
sensitivityProperties.add(new SensitivityProperty(label, informationType)); | ||
} | ||
columnSensitivities.add(new ColumnSensitivity(sensitivityProperties)); | ||
} | ||
sensitivityClassification = new SensitivityClassification(labels, informationTypes, columnSensitivities); | ||
return sensitivityClassification; | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TDS_SQLRESCOLSRCS
is not used anywhere