Skip to content

Commit cbfc763

Browse files
authored
Let ODBC driver verify azure ad authentications (#1326)
1 parent a570522 commit cbfc763

12 files changed

+6
-250
lines changed

source/pdo_sqlsrv/pdo_parser.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -173,31 +173,6 @@ void conn_string_parser::validate_key( _In_reads_(key_len) const char *key, _Ino
173173
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, static_cast<char*>( key_name ) );
174174
}
175175

176-
void conn_string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len )
177-
{
178-
// if the keyword is 'Authentication', check whether the user specified option is supported
179-
bool valid = true;
180-
if ( stricmp( this->current_key_name, ODBCConnOptions::Authentication ) == 0 ) {
181-
if (len <= 0)
182-
valid = false;
183-
else {
184-
// extract option from the value by len
185-
sqlsrv_malloc_auto_ptr<char> option;
186-
option = static_cast<char*>( sqlsrv_malloc( len + 1 ) );
187-
memcpy_s( option, len + 1, value, len );
188-
option[len] = '\0';
189-
190-
valid = AzureADOptions::isAuthValid(option, len);
191-
}
192-
}
193-
if( !valid ) {
194-
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, this->current_key_name );
195-
}
196-
197-
string_parser::add_key_value_pair( value, len );
198-
}
199-
200-
201176
inline bool sql_string_parser::is_placeholder_char( char c )
202177
{
203178
// placeholder only accepts numbers, upper and lower case alphabets and underscore

source/pdo_sqlsrv/pdo_util.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,6 @@ pdo_error PDO_ERRORS[] = {
377377
PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED,
378378
{ IMSSP, (SQLCHAR*) "Statement with emulate prepare on does not support output or input_output parameters.", -72, false }
379379
},
380-
{
381-
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
382-
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectoryServicePrincipal is supported.", -73, false }
383-
},
384380
{
385381
SQLSRV_ERROR_CE_DRIVER_REQUIRED,
386382
{ IMSSP, (SQLCHAR*) "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server (or above) for %1!s!.", -78, true }
@@ -441,10 +437,6 @@ pdo_error PDO_ERRORS[] = {
441437
SQLSRV_ERROR_INVALID_DECIMAL_PLACES,
442438
{ IMSSP, (SQLCHAR*) "Expected an integer to specify number of decimals to format the output values of decimal data types.", -92, false}
443439
},
444-
{
445-
SQLSRV_ERROR_AAD_MSI_UID_PWD_NOT_NULL,
446-
{ IMSSP, (SQLCHAR*) "When using ActiveDirectoryMsi Authentication, PWD must be NULL. UID can be NULL, but if not, an empty string is not accepted.", -93, false}
447-
},
448440
{
449441
SQLSRV_ERROR_DATA_CLASSIFICATION_PRE_EXECUTION,
450442
{ IMSSP, (SQLCHAR*) "The statement must be executed to retrieve Data Classification Sensitivity Metadata.", -94, false}

source/pdo_sqlsrv/php_pdo_sqlsrv_int.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,6 @@ class conn_string_parser : private string_parser
149149
int discard_trailing_white_spaces( _In_reads_(len) const char* str, _Inout_ int len );
150150
void validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len);
151151

152-
protected:
153-
void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len);
154-
155152
public:
156153
conn_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* dsn, _In_ int len, _In_ HashTable* conn_options_ht );
157154
void parse_conn_string( void );
@@ -391,7 +388,6 @@ enum PDO_ERROR_CODES {
391388
PDO_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE,
392389
PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE,
393390
PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED,
394-
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
395391
PDO_SQLSRV_ERROR_CE_DIRECT_QUERY_UNSUPPORTED,
396392
PDO_SQLSRV_ERROR_CE_EMULATE_PREPARE_UNSUPPORTED,
397393
PDO_SQLSRV_ERROR_EXTENDED_STRING_TYPE_INVALID

source/shared/core_conn.cpp

Lines changed: 6 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -704,41 +704,6 @@ bool core_is_conn_opt_value_escaped( _Inout_ const char* value, _Inout_ size_t v
704704
return true;
705705
}
706706

707-
namespace AzureADOptions {
708-
enum AAD_AUTH_TYPE {
709-
MIN_AAD_AUTH_TYPE = 0,
710-
SQL_PASSWORD = 0,
711-
AAD_PASSWORD,
712-
AAD_MSI,
713-
AAD_SPA,
714-
MAX_AAD_AUTH_TYPE
715-
};
716-
717-
const char *AADAuths[] = { "SqlPassword", "ActiveDirectoryPassword", "ActiveDirectoryMsi", "ActiveDirectoryServicePrincipal" };
718-
719-
bool isAuthValid(_In_z_ const char* value, _In_ size_t value_len)
720-
{
721-
if (value_len <= 0)
722-
return false;
723-
724-
bool isValid = false;
725-
for (short i = MIN_AAD_AUTH_TYPE; i < MAX_AAD_AUTH_TYPE && !isValid; i++)
726-
{
727-
if (!stricmp(value, AADAuths[i])) {
728-
isValid = true;
729-
}
730-
}
731-
732-
return isValid;
733-
}
734-
735-
bool isAADMsi(_In_z_ const char* value)
736-
{
737-
return (value != NULL && !stricmp(value, AADAuths[AAD_MSI]));
738-
}
739-
}
740-
741-
742707
// *** internal connection functions and classes ***
743708

744709
namespace {
@@ -792,10 +757,11 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou
792757
access_token_used = true;
793758
}
794759

795-
// Check if Authentication is ActiveDirectoryMSI
760+
// Check if Authentication is ActiveDirectoryMSI because we have to handle this case differently
796761
// https://docs.microsoft.com/en-ca/azure/active-directory/managed-identities-azure-resources/overview
797762
bool activeDirectoryMSI = false;
798763
if (authentication_option_used) {
764+
const char aadMSIoption[] = "ActiveDirectoryMSI";
799765
zval* auth_option = NULL;
800766
auth_option = zend_hash_index_find(options, SQLSRV_CONN_OPTION_AUTHENTICATION);
801767

@@ -804,34 +770,16 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou
804770
option = Z_STRVAL_P(auth_option);
805771
}
806772

807-
//if (option != NULL && !stricmp(option, AzureADOptions::AZURE_AUTH_AD_MSI)) {
808-
activeDirectoryMSI = AzureADOptions::isAADMsi(option);
809-
if (activeDirectoryMSI) {
810-
// There are two types of managed identities:
811-
// (1) A system-assigned managed identity: UID must be NULL
812-
// (2) A user-assigned managed identity: UID defined but must not be an empty string
813-
// In both cases, PWD must be NULL
814-
815-
bool invalid = false;
816-
if (pwd != NULL) {
817-
invalid = true;
818-
} else {
819-
if (uid != NULL && strnlen_s(uid) == 0) {
820-
invalid = true;
821-
}
822-
}
823-
824-
CHECK_CUSTOM_ERROR(invalid, conn, SQLSRV_ERROR_AAD_MSI_UID_PWD_NOT_NULL ) {
825-
throw core::CoreException();
826-
}
773+
if (option != NULL && !stricmp(option, aadMSIoption)) {
774+
activeDirectoryMSI = true;
827775
}
828776
}
829777

830778
// Add the server name
831779
common_conn_str_append_func( ODBCConnOptions::SERVER, server, strnlen_s( server ), connection_string );
832780

833-
// If uid is not present then we use trusted connection -- but not when access token or ActiveDirectoryMSI is used,
834-
// because they are incompatible
781+
// If uid is not present then we use trusted connection -- but not when connecting
782+
// using the access token or Authentication is ActiveDirectoryMSI
835783
if (!access_token_used && !activeDirectoryMSI) {
836784
if (uid == NULL || strnlen_s(uid) == 0) {
837785
connection_string += CONNECTION_OPTION_NO_CREDENTIALS; // "Trusted_Connection={Yes};"

source/shared/core_sqlsrv.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,6 @@ const int SQL_SERVER_2005_DEFAULT_DATETIME_SCALE = 3;
190190
const int SQL_SERVER_2008_DEFAULT_DATETIME_PRECISION = 34;
191191
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7;
192192

193-
namespace AzureADOptions {
194-
bool isAuthValid(_In_z_ const char* value, _In_ size_t value_len);
195-
bool isAADMsi(_In_z_ const char* value);
196-
}
197-
198193
// the message returned by ODBC Driver for SQL Server
199194
const char ODBC_CONNECTION_BUSY_ERROR[] = "Connection is busy with results for another command";
200195

@@ -2011,7 +2006,6 @@ enum SQLSRV_ERROR_CODES {
20112006
SQLSRV_ERROR_INVALID_OPTION_WITH_ACCESS_TOKEN,
20122007
SQLSRV_ERROR_EMPTY_ACCESS_TOKEN,
20132008
SQLSRV_ERROR_INVALID_DECIMAL_PLACES,
2014-
SQLSRV_ERROR_AAD_MSI_UID_PWD_NOT_NULL,
20152009
SQLSRV_ERROR_DATA_CLASSIFICATION_PRE_EXECUTION,
20162010
SQLSRV_ERROR_DATA_CLASSIFICATION_NOT_AVAILABLE,
20172011
SQLSRV_ERROR_DATA_CLASSIFICATION_FAILED,

source/sqlsrv/conn.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,16 +1362,6 @@ int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In
13621362
throw ss::SSException();
13631363
}
13641364

1365-
bool valid = true;
1366-
if( stricmp( SS_CONN_OPTS[i].sqlsrv_name, SSConnOptionNames::Authentication ) == 0 ) {
1367-
valid = AzureADOptions::isAuthValid(value, value_len);
1368-
}
1369-
1370-
CHECK_CUSTOM_ERROR( !valid, ctx, SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, SS_CONN_OPTS[i].sqlsrv_name ) {
1371-
1372-
throw ss::SSException();
1373-
}
1374-
13751365
break;
13761366
}
13771367
case CONN_ATTR_INVALID:

source/sqlsrv/php_sqlsrv_int.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ enum SS_ERROR_CODES {
206206
SS_SQLSRV_ERROR_CONNECT_BRACES_NOT_ESCAPED,
207207
SS_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE,
208208
SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF,
209-
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
210209
SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED
211210
};
212211

source/sqlsrv/util.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,6 @@ ss_error SS_ERRORS[] = {
363363
"Output or bidirectional variable parameters (SQLSRV_PARAM_OUT and SQLSRV_PARAM_INOUT) passed to sqlsrv_prepare or sqlsrv_query should be passed by reference, not by value."
364364
, -61, true }
365365
},
366-
{
367-
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
368-
{ IMSSP, (SQLCHAR*)"Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectoryServicePrincipal is supported.", -62, false }
369-
},
370366
{
371367
SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED,
372368
{ IMSSP, (SQLCHAR*)"Must specify the SQL type for each parameter in a parameterized query when using sqlsrv_query in a column encryption enabled connection.", -63, false }
@@ -429,10 +425,6 @@ ss_error SS_ERRORS[] = {
429425
SQLSRV_ERROR_INVALID_DECIMAL_PLACES,
430426
{ IMSSP, (SQLCHAR*) "Expected an integer to specify number of decimals to format the output values of decimal data types.", -117, false}
431427
},
432-
{
433-
SQLSRV_ERROR_AAD_MSI_UID_PWD_NOT_NULL,
434-
{ IMSSP, (SQLCHAR*) "When using ActiveDirectoryMsi Authentication, PWD must be NULL. UID can be NULL, but if not, an empty string is not accepted.", -118, false}
435-
},
436428
{
437429
SQLSRV_ERROR_DATA_CLASSIFICATION_PRE_EXECUTION,
438430
{ IMSSP, (SQLCHAR*) "The statement must be executed to retrieve Data Classification Sensitivity Metadata.", -119, false}

test/functional/pdo_sqlsrv/pdo_azure_ad_authentication.phpt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,6 @@ if ($stmt === false) {
3434

3535
unset($conn);
3636

37-
///////////////////////////////////////////////////////////////////////////////////////////
38-
// Test Azure AD with integrated authentication. This should fail because
39-
// we don't support it.
40-
//
41-
$connectionInfo = "Authentication = ActiveDirectoryIntegrated; TrustServerCertificate = true;";
42-
43-
try {
44-
$conn = new PDO("sqlsrv:server = $server ; $connectionInfo");
45-
echo "Connected successfully with Authentication=ActiveDirectoryIntegrated.\n";
46-
unset($conn);
47-
} catch (PDOException $e) {
48-
echo "Could not connect with Authentication=ActiveDirectoryIntegrated.\n";
49-
print_r($e->getMessage());
50-
echo "\n";
51-
}
52-
5337
///////////////////////////////////////////////////////////////////////////////////////////
5438
// Test Azure AD on an Azure database instance. Replace $azureServer, etc with
5539
// your credentials to test, or this part is skipped.
@@ -95,6 +79,4 @@ if ($azureServer != 'TARGET_AD_SERVER') {
9579
--EXPECTF--
9680
Connected successfully with Authentication=SqlPassword.
9781
string(1) "%d"
98-
Could not connect with Authentication=ActiveDirectoryIntegrated.
99-
SQLSTATE[IMSSP]: Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectoryServicePrincipal is supported.
10082
%s with Authentication=ActiveDirectoryPassword.

test/functional/pdo_sqlsrv/pdo_azure_ad_managed_identity.phpt

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,58 +18,6 @@ function verifyErrorMessage($exception, $expectedError, $msg)
1818
}
1919
}
2020

21-
function connectWithInvalidOptions()
22-
{
23-
global $server;
24-
25-
$message = 'AzureAD Managed Identity test: expected to fail with ';
26-
$expectedError = 'When using ActiveDirectoryMsi Authentication, PWD must be NULL. UID can be NULL, but if not, an empty string is not accepted';
27-
28-
$uid = '';
29-
$connectionInfo = "Authentication = ActiveDirectoryMsi;";
30-
$testCase = 'empty UID provided';
31-
try {
32-
$conn = new PDO("sqlsrv:server = $server; $connectionInfo", $uid);
33-
echo $message . $testCase . PHP_EOL;
34-
} catch(PDOException $e) {
35-
verifyErrorMessage($e, $expectedError, $testCase);
36-
}
37-
unset($connectionInfo);
38-
39-
$pwd = '';
40-
$connectionInfo = "Authentication = ActiveDirectoryMsi;";
41-
$testCase = 'empty PWD provided';
42-
try {
43-
$conn = new PDO("sqlsrv:server = $server; $connectionInfo", null, $pwd);
44-
echo $message . $testCase . PHP_EOL;
45-
} catch(PDOException $e) {
46-
verifyErrorMessage($e, $expectedError, $testCase);
47-
}
48-
unset($connectionInfo);
49-
50-
$pwd = 'dummy';
51-
$connectionInfo = "Authentication = ActiveDirectoryMsi;";
52-
$testCase = 'PWD provided';
53-
try {
54-
$conn = new PDO("sqlsrv:server = $server; $connectionInfo", null, $pwd);
55-
echo $message . $testCase . PHP_EOL;
56-
} catch(PDOException $e) {
57-
verifyErrorMessage($e, $expectedError, $testCase);
58-
}
59-
unset($connectionInfo);
60-
61-
$expectedError = 'When using Azure AD Access Token, the connection string must not contain UID, PWD, or Authentication keywords.';
62-
$connectionInfo = "Authentication = ActiveDirectoryMsi; AccessToken = '123';";
63-
$testCase = 'AccessToken option';
64-
try {
65-
$conn = new PDO("sqlsrv:server = $server; $connectionInfo");
66-
echo $message . $testCase . PHP_EOL;
67-
} catch(PDOException $e) {
68-
verifyErrorMessage($e, $expectedError, $testCase);
69-
}
70-
unset($connectionInfo);
71-
}
72-
7321
function connectInvalidServer()
7422
{
7523
global $server, $driver, $uid, $pwd;
@@ -102,9 +50,6 @@ function connectInvalidServer()
10250

10351
require_once('MsSetup.inc');
10452

105-
// Test some error conditions
106-
connectWithInvalidOptions();
107-
10853
// Make a connection to an invalid server
10954
connectInvalidServer();
11055

0 commit comments

Comments
 (0)