Implemented Azure AD plus tests

This commit is contained in:
yitam 2017-05-05 16:28:33 -07:00
Родитель ae0368f8d2
Коммит 1e527865a9
12 изменённых файлов: 232 добавлений и 2 удалений

Просмотреть файл

@ -41,6 +41,7 @@ const char APP[] = "APP";
const char ApplicationIntent[] = "ApplicationIntent";
const char AttachDBFileName[] = "AttachDbFileName";
const char ConnectionPooling[] = "ConnectionPooling";
const char Authentication[] = "Authentication";
#ifdef _WIN32
const char ConnectRetryCount[] = "ConnectRetryCount";
const char ConnectRetryInterval[] = "ConnectRetryInterval";
@ -200,6 +201,15 @@ const connection_option PDO_CONN_OPTS[] = {
CONN_ATTR_STRING,
conn_str_append_func::func
},
{
PDOConnOptionNames::Authentication,
sizeof( PDOConnOptionNames::Authentication ),
SQLSRV_CONN_OPTION_AUTHENTICATION,
ODBCConnOptions::Authentication,
sizeof( ODBCConnOptions::Authentication ),
CONN_ATTR_STRING,
conn_str_append_func::func
},
{
PDOConnOptionNames::ConnectionPooling,
sizeof( PDOConnOptionNames::ConnectionPooling ),

Просмотреть файл

@ -169,6 +169,31 @@ void conn_string_parser::validate_key(const char *key, int key_len TSRMLS_DC )
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, static_cast<char*>( key_name ) );
}
void conn_string_parser::add_key_value_pair( const char* value, int len TSRMLS_DC )
{
// first need to check if the option for Authention is supported
bool valid = true;
if ( stricmp( this->current_key_name, ODBCConnOptions::Authentication ) == 0 ) {
if (len <= 0)
valid = false;
else {
// extract option from the value by len
sqlsrv_malloc_auto_ptr<char> option;
option = static_cast<char*>( sqlsrv_malloc( len + 1 ) );
memcpy_s( option, len + 1, value, len );
option[len] = '\0';
valid = core_is_authentication_option_valid( option, len );
}
}
if( !valid ) {
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, this->current_key_name );
}
string_parser::add_key_value_pair( value, len );
}
inline bool sql_string_parser::is_placeholder_char( char c )
{
// placeholder only accepts numbers, upper and lower case alphabets and underscore

Просмотреть файл

@ -377,6 +377,10 @@ pdo_error PDO_ERRORS[] = {
PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED,
{ IMSSP, (SQLCHAR*) "Statement with emulate prepare on does not support output or input_output parameters.", -72, false }
},
{
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -73, false }
},
{ UINT_MAX, {} }
};

Просмотреть файл

@ -165,6 +165,9 @@ class conn_string_parser : private string_parser
int discard_trailing_white_spaces(const char* str, int len);
void validate_key(const char *key, int key_len TSRMLS_DC);
protected:
void add_key_value_pair(const char* value, int len TSRMLS_DC);
public:
conn_string_parser( sqlsrv_context& ctx, const char* dsn, int len, _Inout_ HashTable* conn_options_ht );
void parse_conn_string( TSRMLS_D );
@ -390,6 +393,7 @@ enum PDO_ERROR_CODES {
PDO_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE,
PDO_SQLSRV_ERROR_INVALID_CURSOR_WITH_SCROLL_TYPE,
PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED,
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION
};
extern pdo_error PDO_ERRORS[];

Просмотреть файл

@ -550,6 +550,20 @@ bool core_is_conn_opt_value_escaped( const char* value, size_t value_len )
return true;
}
// core_is_authentication_option_valid
// if the option for the authentication is valid, returns true. This returns false otherwise.
bool core_is_authentication_option_valid(const char* value, size_t value_len)
{
if (value_len <= 0)
return false;
if( ! stricmp( value, AzureADOptions::AZURE_AUTH_SQL_PASSWORD ) || ! stricmp( value, AzureADOptions::AZURE_AUTH_AD_PASSWORD ) ) {
return true;
}
return false;
}
// *** internal connection functions and classes ***

Просмотреть файл

@ -180,6 +180,12 @@ const int SQL_SERVER_2005_DEFAULT_DATETIME_SCALE = 3;
const int SQL_SERVER_2008_DEFAULT_DATETIME_PRECISION = 34;
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7;
namespace AzureADOptions {
const char AZURE_AUTH_SQL_PASSWORD[] = "SqlPassword";
const char AZURE_AUTH_AD_PASSWORD[] = "ActiveDirectoryPassword";
}
// types for conversions on output parameters (though they can be used for input parameters, they are ignored)
enum SQLSRV_PHPTYPE {
MIN_SQLSRV_PHPTYPE = 1, // lowest value for a php type
@ -1077,6 +1083,7 @@ namespace ODBCConnOptions {
const char APP[] = "APP";
const char ApplicationIntent[] = "ApplicationIntent";
const char AttachDBFileName[] = "AttachDbFileName";
const char Authentication[] = "Authentication";
const char CharacterSet[] = "CharacterSet";
const char ConnectionPooling[] = "ConnectionPooling";
#ifdef _WIN32
@ -1121,6 +1128,7 @@ enum SQLSRV_CONN_OPTIONS {
SQLSRV_CONN_OPTION_ATTACHDBFILENAME,
SQLSRV_CONN_OPTION_APPLICATION_INTENT,
SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER,
SQLSRV_CONN_OPTION_AUTHENTICATION,
#ifdef _WIN32
SQLSRV_CONN_OPTION_CONN_RETRY_COUNT,
SQLSRV_CONN_OPTION_CONN_RETRY_INTERVAL,
@ -1190,6 +1198,7 @@ void core_sqlsrv_get_server_version( sqlsrv_conn* conn, _Out_ zval *server_versi
void core_sqlsrv_get_client_info( sqlsrv_conn* conn, _Out_ zval *client_info TSRMLS_DC );
bool core_is_conn_opt_value_escaped( const char* value, size_t value_len );
size_t core_str_zval_is_true( zval* str_zval );
bool core_is_authentication_option_valid( const char* value, size_t value_len );
//*********************************************************************************************************************************
// Statement

Просмотреть файл

@ -90,7 +90,8 @@
#define SQL_COPT_SS_AEKEYSTOREPROVIDER (SQL_COPT_SS_BASE_EX+11) /* Load a keystore provider or read the list of loaded keystore providers */
#define SQL_COPT_SS_AEKEYSTOREDATA (SQL_COPT_SS_BASE_EX+12) /* Communicate with a loaded keystore provider */
#define SQL_COPT_SS_AETRUSTEDCMKPATHS (SQL_COPT_SS_BASE_EX+13) /* List of trusted CMK paths */
#define SQL_COPT_SS_AECEKCACHETTL (SQL_COPT_SS_BASE_EX+14)// Symmetric Key Cache TTL
#define SQL_COPT_SS_AECEKCACHETTL (SQL_COPT_SS_BASE_EX+14) /* Symmetric Key Cache TTL */
#define SQL_COPT_SS_AUTHENTICATION (SQL_COPT_SS_BASE_EX+15) /* The authentication method used for the connection */
/*
* SQLColAttributes driver specific defines.

Просмотреть файл

@ -186,6 +186,7 @@ const char APP[] = "APP";
const char ApplicationIntent[] = "ApplicationIntent";
const char AttachDBFileName[] = "AttachDbFileName";
const char CharacterSet[] = "CharacterSet";
const char Authentication[] = "Authentication";
const char ConnectionPooling[] = "ConnectionPooling";
#ifdef _WIN32
const char ConnectRetryCount[] = "ConnectRetryCount";
@ -282,6 +283,15 @@ const connection_option SS_CONN_OPTS[] = {
CONN_ATTR_STRING,
conn_char_set_func::func
},
{
SSConnOptionNames::Authentication,
sizeof( SSConnOptionNames::Authentication ),
SQLSRV_CONN_OPTION_AUTHENTICATION,
ODBCConnOptions::Authentication,
sizeof( ODBCConnOptions::Authentication ),
CONN_ATTR_STRING,
conn_str_append_func::func
},
{
SSConnOptionNames::ConnectionPooling,
sizeof( SSConnOptionNames::ConnectionPooling ),
@ -1205,6 +1215,17 @@ int get_conn_option_key( sqlsrv_context& ctx, zend_string* key, size_t key_len,
throw ss::SSException();
}
bool valid = true;
if( stricmp( SS_CONN_OPTS[i].sqlsrv_name, ODBCConnOptions::Authentication ) == 0 ) {
valid = core_is_authentication_option_valid( value, value_len );
}
CHECK_CUSTOM_ERROR( !valid, ctx, SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, SS_CONN_OPTS[ i ].sqlsrv_name ) {
throw ss::SSException();
}
break;
}
}

Просмотреть файл

@ -352,7 +352,8 @@ enum SS_ERROR_CODES {
SS_SQLSRV_ERROR_CONNECT_ILLEGAL_ENCODING,
SS_SQLSRV_ERROR_CONNECT_BRACES_NOT_ESCAPED,
SS_SQLSRV_ERROR_INVALID_OUTPUT_PARAM_TYPE,
SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF
SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF,
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION
};
extern ss_error SS_ERRORS[];

Просмотреть файл

@ -366,6 +366,10 @@ ss_error SS_ERRORS[] = {
"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."
, -61, true }
},
{
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
{ IMSSP, (SQLCHAR*)"Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -62, false }
},
// internal warning definitions
{

Просмотреть файл

@ -0,0 +1,63 @@
--TEST--
Test the Authentication keyword and its accepted values: SqlPassword and ActiveDirectoryPassword.
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
$connectionInfo = " Authentication = SqlPassword; TrustServerCertificate = true;";
try
{
$conn = new PDO( "sqlsrv:server = $serverName ; $connectionInfo", $username, $password );
echo "Connected successfully with Authentication=SqlPassword.\n";
}
catch( PDOException $e )
{
echo "Could not connect with Authentication=SqlPassword.\n";
print_r( $e->getMessage() );
echo "\n";
}
$stmt = $conn->query( "SELECT name FROM master.dbo.sysdatabases" );
if ( $stmt === false )
{
echo "Query failed.\n";
}
else
{
$first_db = $stmt->fetch();
var_dump( $first_db );
}
$conn = null;
////////////////////////////////////////
$connectionInfo = "Authentication = ActiveDirectoryIntegrated; TrustServerCertificate = true;";
try
{
$conn = new PDO( "sqlsrv:server = $serverName ; $connectionInfo" );
echo "Connected successfully with Authentication=ActiveDirectoryIntegrated.\n";
$conn = null;
}
catch( PDOException $e )
{
echo "Could not connect with Authentication=ActiveDirectoryIntegrated.\n";
print_r( $e->getMessage() );
echo "\n";
}
?>
--EXPECT--
Connected successfully with Authentication=SqlPassword.
array(2) {
["name"]=>
string(6) "master"
[0]=>
string(6) "master"
}
Could not connect with Authentication=ActiveDirectoryIntegrated.
SQLSTATE[IMSSP]: Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.

Просмотреть файл

@ -0,0 +1,74 @@
--TEST--
Test the Authentication keyword and its accepted values: SqlPassword and ActiveDirectoryPassword.
--SKIPIF--
--FILE--
<?php
require_once("autonomous_setup.php");
$connectionInfo = array( "UID"=>$username, "PWD"=>$password,
"Authentication"=>'SqlPassword', "TrustServerCertificate"=>true );
$conn = sqlsrv_connect( $serverName, $connectionInfo );
if( $conn === false )
{
echo "Could not connect with Authentication=SqlPassword.\n";
print_r( sqlsrv_errors() );
}
else
{
echo "Connected successfully with Authentication=SqlPassword.\n";
}
$stmt = sqlsrv_query( $conn, "SELECT name FROM master.dbo.sysdatabases" );
if ( $stmt === false )
{
echo "Query failed.\n";
}
else
{
$first_db = sqlsrv_fetch_array( $stmt );
var_dump( $first_db );
}
sqlsrv_close( $conn );
////////////////////////////////////////
$connectionInfo = array( "Authentication"=>'ActiveDirectoryIntegrated', "TrustServerCertificate"=>true );
$conn = sqlsrv_connect( $serverName, $connectionInfo );
if( $conn === false )
{
echo "Could not connect with Authentication=ActiveDirectoryIntegrated.\n";
print_r( sqlsrv_errors() );
}
else
{
echo "Connected successfully with Authentication=ActiveDirectoryIntegrated.\n";
sqlsrv_close( $conn );
}
?>
--EXPECT--
Connected successfully with Authentication=SqlPassword.
array(2) {
[0]=>
string(6) "master"
["name"]=>
string(6) "master"
}
Could not connect with Authentication=ActiveDirectoryIntegrated.
Array
(
[0] => Array
(
[0] => IMSSP
[SQLSTATE] => IMSSP
[1] => -62
[code] => -62
[2] => Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.
[message] => Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.
)
)