Skip to content
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

Backport #2193: Update getUserName in impersonated security context in Azure SQL database #2197

Merged
merged 1 commit into from Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -1709,12 +1709,30 @@ public String getUserName() throws SQLServerException, SQLTimeoutException {
}
checkClosed();
String result = "";
try (SQLServerStatement s = (SQLServerStatement) connection.createStatement();
SQLServerResultSet rs = s.executeQueryInternal("select system_user")) {
// Select system_user will always return a row.
boolean next = rs.next();
assert next;
result = rs.getString(1);
try (SQLServerStatement s = (SQLServerStatement) connection.createStatement()) {
try (SQLServerResultSet rs = s.executeQueryInternal("SELECT SYSTEM_USER")) {
// Select system_user will always return a row.
boolean next = rs.next();
assert next;
result = rs.getString(1);
} catch (SQLServerException e) {
// execution using impersonated security context is disallowed for Azure SQL Server so return CURRENT_USER instead
if (e.getErrorCode() == SQLServerException.IMPERSONATION_CONTEXT_NOT_SUPPORTED) {
if (loggerExternal.isLoggable(Level.FINEST)) {
loggerExternal.finest(toString()
+ " Impersonation context is not supported in this version of SQL Server. Re-try getting CURRENT_USER");
}

try (SQLServerResultSet rs = s.executeQueryInternal("SELECT CURRENT_USER")) {
boolean next = rs.next();
assert next;
result = rs.getString(1);
}
} else {
// re-throw
throw e;
}
}
}
return result;
}
Expand Down
Expand Up @@ -66,8 +66,9 @@ public final class SQLServerException extends java.sql.SQLException {
static final int LOGON_FAILED = 18456;
static final int PASSWORD_EXPIRED = 18488;
static final int USER_ACCOUNT_LOCKED = 18486;
static final java.util.logging.Logger exLogger = java.util.logging.Logger
.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerException");

// Built-in function '%.*ls' in impersonation context is not supported in this version of SQL Server.
static final int IMPERSONATION_CONTEXT_NOT_SUPPORTED = 40529;

// Facility for driver-specific error codes
static final int DRIVER_ERROR_NONE = 0;
Expand All @@ -84,6 +85,9 @@ public final class SQLServerException extends java.sql.SQLException {
static final int DATA_CLASSIFICATION_INVALID_LABEL_INDEX = 12;
static final int DATA_CLASSIFICATION_INVALID_INFORMATION_TYPE_INDEX = 13;

static final java.util.logging.Logger exLogger = java.util.logging.Logger
.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerException");

/** driver error code */
private int driverErrorCode = DRIVER_ERROR_NONE;

Expand Down
Expand Up @@ -18,6 +18,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
Expand All @@ -43,6 +44,7 @@
import com.microsoft.sqlserver.jdbc.RandomUtil;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData;
import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.microsoft.sqlserver.jdbc.StringUtils;
import com.microsoft.sqlserver.jdbc.TestResource;
import com.microsoft.sqlserver.jdbc.TestUtils;
Expand Down Expand Up @@ -155,8 +157,6 @@ public void testGetURL() throws SQLException {
* @throws SQLException
*/
@Test
@Tag(Constants.xAzureSQLDW)
@Tag(Constants.xAzureSQLDB)
public void testDBUserLogin() throws SQLException {
try (Connection conn = getConnection()) {
DatabaseMetaData databaseMetaData = conn.getMetaData();
Expand Down Expand Up @@ -187,6 +187,45 @@ public void testDBUserLogin() throws SQLException {
}
}

@Test
@Tag(Constants.xAzureSQLDW)
public void testImpersonateGetUserName() throws SQLException {
String newUser = "newUser" + UUID.randomUUID();

try (Connection conn = getConnection(); Statement stmt = conn.createStatement()) {
String escapedNewUser = AbstractSQLGenerator.escapeIdentifier(newUser);
String password = "password" + UUID.randomUUID();

stmt.execute("IF EXISTS (select * from sys.sysusers where name = '" + escapedNewUser + "') DROP USER"
+ escapedNewUser);

// create new user and login
try {
stmt.execute("CREATE USER " + escapedNewUser + " WITH password='" + password + "'");
} catch (SQLServerException e) {
// handle failed cases when database is master
if (e.getMessage().contains("contained database")) {
stmt.execute("CREATE LOGIN " + escapedNewUser + " WITH password='" + password + "'");
stmt.execute("CREATE USER " + escapedNewUser);
}
}

DatabaseMetaData databaseMetaData = conn.getMetaData();
try (CallableStatement asOtherUser = conn.prepareCall("EXECUTE AS USER = '" + newUser + "'")) {
asOtherUser.execute();
assertTrue(newUser.equalsIgnoreCase(databaseMetaData.getUserName()),
TestResource.getResource("R_userNameNotMatch"));
} catch (Exception e) {
fail(TestResource.getResource("R_unexpectedErrorMessage") + e.getMessage());
} finally {
stmt.execute("IF EXISTS (select * from sys.sysusers where name = '" + escapedNewUser + "') DROP USER"
+ escapedNewUser);
stmt.execute("IF EXISTS (select * from sys.sysusers where name = '" + escapedNewUser + "') DROP LOGIN"
+ escapedNewUser);
}
}
}

/**
* Testing of {@link SQLServerDatabaseMetaData#getSchemas()}
*
Expand Down