Add support to configure system password for Oracle database#10601
Add support to configure system password for Oracle database#10601cetindogu wants to merge 8 commits intotestcontainers:mainfrom
Conversation
…; fix ORACLE_PASSWORD mapping Introduce an independent system user password for Oracle containers and map it correctly to the ORACLE_PASSWORD env. - Add withOraclePassword(String) to configure SYSTEM/SYS password independently from the app user password - Use system password in SID connections (getPassword returns system password in SID mode) - Keep backward compatibility: withPassword also sets system password unless withOraclePassword was called - Update Oracle XE and Oracle Free containers to use the new internal oraclePassword - Add OracleContainerTest to verify system vs app password behavior in SID and non-SID modes This resolves the issue where ORACLE_PASSWORD was effectively bound to the app user password, making it impossible to set the system user password correctly.
eddumelendez
left a comment
There was a problem hiding this comment.
Hi, thanks for your contribution. Rename the new method to withSystemPassword instead to make it more aligned with the Oracle database user instead of the env var. Regarding to the comments, please revisit it.
| * Password for Oracle system user (e.g. SYSTEM/SYS). Defaults to {@link #APP_USER_PASSWORD} | ||
| * for backwards compatibility, but can be customized independently via {@link #withOraclePassword(String)}. | ||
| */ | ||
| private String oraclePassword = APP_USER_PASSWORD; |
There was a problem hiding this comment.
| private String oraclePassword = APP_USER_PASSWORD; | |
| private String systemPassword = APP_USER_PASSWORD; |
| * @param oraclePassword password for SYSTEM/SYS users inside the container | ||
| * @return this container instance | ||
| */ | ||
| public OracleContainer withOraclePassword(String oraclePassword) { |
There was a problem hiding this comment.
| public OracleContainer withOraclePassword(String oraclePassword) { | |
| public OracleContainer withSystemPassword(String oraclePassword) { |
| * Tracks whether {@link #withOraclePassword(String)} was called to avoid overriding | ||
| * the system password when {@link #withPassword(String)} is used for the application user only. | ||
| */ | ||
| private boolean oraclePasswordExplicitlySet = false; |
There was a problem hiding this comment.
| private boolean oraclePasswordExplicitlySet = false; | |
| private boolean systemPasswordExplicitlySet = false; |
|
|
||
| private void runTestSystemUser(OracleContainer container, String databaseName, String username, String password) | ||
| throws SQLException { | ||
| //Test config was honored |
| assertThat(container.getUsername()).isEqualTo(username); | ||
| assertThat(container.getPassword()).isEqualTo(password); | ||
|
|
||
| //Test we can get a connection and execute a system-level command |
|
|
||
| @Test | ||
| public void testSeparateSystemAndAppPasswords() throws SQLException { | ||
| // SID mode should use system password |
| runTestSystemUser(oracleSid, "xepdb1", "system", "SysP@ss1!"); | ||
| } | ||
|
|
||
| // Non-SID mode should use application user's password |
| } | ||
|
|
||
| @Test | ||
| public void testSeparateSystemAndAppPasswords() throws SQLException { |
There was a problem hiding this comment.
should have two tests instead?
|
@cetindogu can you take a look at the comments I left? |
|
Very nice suggestions, i will update PR. Thanks for the comments
|
…ssword refactor (OracleContainer): oraclePassword rename to systemPassword refactor (OracleContainer): oraclePasswordExplicitlySet rename to systemPasswordExplicitlySet
|
@eddumelendez re-check plz |
|
@cetindogu tests are failing. can you check, please? |
…DBA grant The test now checks the connected session's user rather than verifying DBA grant status, which provides a more direct validation of the system user connection.
|
commit: 63752c5 fyi. |
development note1:The purpose of this test is to prove that the SID connection is indeed logged in as SYSTEM/SYS. runTestSystemUser does just that by comparing the output of SELECT USER FROM DUAL from the session we're currently connected to with the expected username. development note2:runTestSystemUser previously used GRANT DBA TO …, a DDL statement that returns no ResultSet, so AbstractContainerDatabaseTest.performQuery() |
|
@eddumelendez, anything left ? |
There was a problem hiding this comment.
Pull request overview
This PR fixes Oracle container password handling by separating the Oracle system user (SYSTEM/SYS) password from the application user password, ensuring ORACLE_PASSWORD maps to the system password and SID-mode connections authenticate with the correct credentials.
Changes:
- Introduces a dedicated system-user password field and uses it for
ORACLE_PASSWORDand SID-modegetPassword(). - Preserves backward compatibility by having
withPassword(...)also set the system password unless explicitly overridden. - Extends Oracle XE/Free tests to validate system vs app password behavior in SID and non-SID modes.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| modules/oracle-xe/src/main/java/org/testcontainers/containers/OracleContainer.java | Adds separate system password handling and maps ORACLE_PASSWORD to it; uses system password in SID mode. |
| modules/oracle-free/src/main/java/org/testcontainers/oracle/OracleContainer.java | Same as XE, with an internal field for the system password and updated ORACLE_PASSWORD mapping. |
| modules/oracle-xe/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java | Adds SID-focused assertions to verify the connected user and password behavior. |
| modules/oracle-free/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java | Adds SID-focused tests for system/app password separation (but currently includes a failing SQL assertion approach). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| /** | ||
| * Sets the password for the Oracle system user (SYSTEM/SYS). This is independent from the | ||
| * application user password set via {@link #withPassword(String)}. | ||
| * | ||
| * @param oraclePassword password for SYSTEM/SYS users inside the container | ||
| * @return this container instance | ||
| */ | ||
| public OracleContainer withSystemPassword(String oraclePassword) { | ||
| if (StringUtils.isEmpty(oraclePassword)) { | ||
| throw new IllegalArgumentException("Oracle password cannot be null or empty"); | ||
| } | ||
| this.oraclePassword = oraclePassword; | ||
| this.systemPasswordExplicitlySet = true; | ||
| return self(); |
There was a problem hiding this comment.
The PR description/docs mention withOraclePassword(String) as the new API, but this module adds withSystemPassword(String) instead. Because this is part of the public container API, please align the method name with the documented API (or update the docs/PR description to match), and consider an alias/deprecation plan to avoid confusing users.
| /** | ||
| * Password for Oracle system user (e.g. SYSTEM/SYS). Defaults to {@link #APP_USER_PASSWORD} | ||
| * for backwards compatibility, but can be customized independently via {@link #withSystemPassword(String)}. | ||
| */ | ||
| private String oraclePassword = APP_USER_PASSWORD; | ||
|
|
||
| /** | ||
| * Tracks whether {@link #withSystemPassword(String)} was called to avoid overriding | ||
| * the system password when {@link #withPassword(String)} is used for the application user only. | ||
| */ | ||
| private boolean systemPasswordExplicitlySet = false; |
There was a problem hiding this comment.
In this class the system-user password is stored in a field named oraclePassword, while related state is systemPasswordExplicitlySet and the other Oracle module uses systemPassword. This inconsistency makes it harder to reason about which password is which (system vs app) and increases the chance of future mapping bugs. Consider standardizing the field name (e.g., systemPassword) and updating references accordingly.
| // Maintain backwards compatibility: if oracle password wasn't set explicitly, | ||
| // align it with the application user's password. | ||
| if (!systemPasswordExplicitlySet) { | ||
| this.systemPassword = password; | ||
| } |
There was a problem hiding this comment.
The inline comment says "if oracle password wasn't set explicitly" but the code is tracking the system password via systemPasswordExplicitlySet. Updating the comment to refer to the system password would avoid confusion when maintaining this logic.
| //Test we can get a connection and execute a system-level command | ||
| container.start(); | ||
| ResultSet resultSet = performQuery(container, "GRANT DBA TO " + username); | ||
| int resultSetInt = resultSet.getInt(1); | ||
| assertThat(resultSetInt).as("A basic system user query succeeds").isEqualTo(1); |
There was a problem hiding this comment.
performQuery(...) expects the SQL to produce a ResultSet (it calls Statement#getResultSet() and then resultSet.next()). GRANT DBA TO ... does not return a result set, so statement.getResultSet() will be null and this test will fail with a NullPointerException. Use a SELECT-based assertion (e.g., SELECT USER FROM DUAL) or change the helper to use executeUpdate/check update count for DDL/DCL statements.
| /** | ||
| * Sets the password for the Oracle system user (SYSTEM/SYS). This is independent from the | ||
| * application user password set via {@link #withPassword(String)}. | ||
| * | ||
| * @param oraclePassword password for SYSTEM/SYS users inside the container | ||
| * @return this container instance | ||
| */ | ||
| public OracleContainer withSystemPassword(String oraclePassword) { | ||
| if (StringUtils.isEmpty(oraclePassword)) { | ||
| throw new IllegalArgumentException("Oracle password cannot be null or empty"); | ||
| } | ||
| this.systemPassword = oraclePassword; | ||
| this.systemPasswordExplicitlySet = true; | ||
| return self(); |
There was a problem hiding this comment.
The PR description and usage examples refer to a new public API withOraclePassword(String), but the implementation introduces withSystemPassword(String) instead. Since this is a user-facing API, please either rename the method to match the documented API (and keep withSystemPassword as a deprecated alias if needed), or update the PR description/docs accordingly so users know which method to call.
…; fix ORACLE_PASSWORD mapping
Introduce an independent system user password for Oracle containers and map it correctly to the ORACLE_PASSWORD env.
This resolves the issue where ORACLE_PASSWORD was effectively bound to the app user password, making it impossible to set the system user password correctly.
Summary
Fix Oracle container password handling so
ORACLE_PASSWORDconfigures the system user (SYSTEM/SYS) password, not the app user’s password. AddwithOraclePassword(String)to configure it independently while keeping backward compatibility.Problem
ORACLE_PASSWORDwas populated from the application user password.getUsername()returnssystem, butgetPassword()returned the app user’s password, causing authentication mismatches and preventing a distinct system user password.Changes
withOraclePassword(String oraclePassword)for SYSTEM/SYS.withPassword(String password)continues to set the application user password.ORACLE_PASSWORD← system user password.APP_USER_PASSWORD← app user password.getUsername()returnssystem.getPassword()now returns the system password.withOraclePassword(...)is not used,withPassword(...)sets both the app and system passwords (preserving previous behavior).Why
getPassword()changedsystem. Returning the app user’s password was incorrect and led to login failures. Now the password matches the user being used.Affected modules
testcontainers-oracle-xetestcontainers-oracle-freeTests
SimpleOracleTest(no new test classes):Usage examples
Migration / Compatibility
.withPassword(...)continues to work (sets both passwords unless.withOraclePassword(...)is used)..withOraclePassword(...)to set a distinct system password.How to verify locally
./gradlew checkstyleMain checkstyleTest spotlessApply.\gradlew.bat checkstyleMain checkstyleTest spotlessApply./gradlew :testcontainers-oracle-xe:test :testcontainers-oracle-free:testDocumentation
ORACLE_PASSWORDconfigures the SYSTEM/SYS password.APP_USER_PASSWORDconfigures the app user’s password.Changelog entry
withOraclePasswordand fixORACLE_PASSWORDmapping to system user; use system password in SID mode; maintain backward compatibility withwithPassword.Related issues