Skip to content

Commit bbc2ebc

Browse files
authored
Merge pull request #133 from utPLSQL/feature/connect_as_sysdba
- Adds some Unit-Tests around parsing connectString - Allows user-part of the connectstring to contain "/" if enclosed in double quotes (e.g. "my/user"/pass@connectstring) - Allows password-part of the connectstring to contain "@" if enclosed in double quotes (e.g. app/"myP@ssw/rd="@connecstring) - Allows to connect as sysdba via adding the "as" part to the username (e.g. "sys as sysdba"/pass@connectstring) (Fixes #115)
2 parents 31dd9b7 + 9b1714f commit bbc2ebc

File tree

9 files changed

+140
-16
lines changed

9 files changed

+140
-16
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ To connect using TNS, you need to have the ORACLE_HOME environment variable set.
7474
The file tnsnames.ora must exist in path %ORACLE_HOME%/network/admin
7575
The file tnsnames.ora must contain valid TNS entries.
7676

77+
In case you use a username containing `/` or a password containing `@` you should encapsulate it with double quotes `"`:
78+
```
79+
utplsql run "my/Username"/"myP@ssword"@connectstring
80+
```
81+
7782
### run
7883
`utplsql run <ConnectionURL> [<options>]`
7984

@@ -235,6 +240,16 @@ UT_XUNIT_REPORTER:
235240
Provides outcomes in a format conforming with JUnit 4 and above as defined in: https://gist.github.com/kuzuha/232902acab1344d6b578
236241
```
237242

243+
## Using utPLSQL-cli as sysdba
244+
245+
Since 3.1.3 it is possible to run utPLSQL-cli as sysdba by running
246+
247+
```
248+
utplsql run "sys as sysdba"/pw@connectstring
249+
```
250+
251+
It is, however, __not recommended__ to run utPLSQL with sysdba privileges.
252+
238253
## Enabling Color Outputs on Windows
239254

240255
To enable color outputs on Windows cmd you need to install an open-source utility called [ANSICON](http://adoxa.altervista.org/ansicon/).

src/main/java/org/utplsql/cli/ConnectionConfig.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,26 @@ public class ConnectionConfig {
1010
private final String connect;
1111

1212
public ConnectionConfig( String connectString ) {
13-
Matcher m = Pattern.compile("^([^/]+)/([^@]+)@(.*)$").matcher(connectString);
13+
Matcher m = Pattern.compile("^(\".+\"|[^/]+)/(\".+\"|[^@]+)@(.*)$").matcher(connectString);
1414
if ( m.find() ) {
15-
user = m.group(1);
16-
password = m.group(2);
15+
user = stripEnclosingQuotes(m.group(1));
16+
password = stripEnclosingQuotes(m.group(2));
1717
connect = m.group(3);
1818
}
1919
else
2020
throw new IllegalArgumentException("Not a valid connectString: '" + connectString + "'");
2121
}
2222

23+
private String stripEnclosingQuotes( String value ) {
24+
if ( value.length() > 1
25+
&& value.startsWith("\"")
26+
&& value.endsWith("\"")) {
27+
return value.substring(1, value.length()-1);
28+
} else {
29+
return value;
30+
}
31+
}
32+
2333
public String getConnect() {
2434
return connect;
2535
}
@@ -35,4 +45,10 @@ public String getPassword() {
3545
public String getConnectString() {
3646
return user + "/" + password + "@" + connect;
3747
}
48+
49+
public boolean isSysDba() {
50+
return user != null &&
51+
(user.toLowerCase().endsWith(" as sysdba")
52+
|| user.toLowerCase().endsWith(" as sysoper"));
53+
}
3854
}

src/main/java/org/utplsql/cli/DataSourceProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static DataSource getDataSource(ConnectionInfo info, int maxConnections )
2626
requireOjdbc();
2727

2828
ConnectionConfig config = new ConnectionConfig(info.getConnectionString());
29+
warnIfSysDba(config);
2930

3031
HikariDataSource pds = new TestedDataSourceProvider(config).getDataSource();
3132
pds.setAutoCommit(false);
@@ -43,4 +44,10 @@ private static void requireOjdbc() {
4344
throw new RuntimeException("Can't run utPLSQL-cli without Oracle JDBC driver");
4445
}
4546
}
47+
48+
private static void warnIfSysDba(ConnectionConfig config) {
49+
if ( config.isSysDba() ) {
50+
System.out.println("WARNING: You are connecting to the database as SYSDBA or SYSOPER, which is NOT RECOMMENDED and can put your database at risk!");
51+
}
52+
}
4653
}

src/main/java/org/utplsql/cli/RunCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public class RunCommand implements ICommand {
124124
private ReporterFactory reporterFactory;
125125
private ReporterManager reporterManager;
126126

127-
private ConnectionInfo getConnectionInfo() {
127+
ConnectionInfo getConnectionInfo() {
128128
return connectionInfoList.get(0);
129129
}
130130

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.utplsql.cli;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.junit.jupiter.api.Assertions.*;
6+
7+
public class ConnectionConfigTest {
8+
9+
@Test
10+
void parse() {
11+
ConnectionConfig info = new ConnectionConfig("test/[email protected]/service");
12+
13+
assertEquals("test", info.getUser());
14+
assertEquals("pw", info.getPassword());
15+
assertEquals("my.local.host/service", info.getConnect());
16+
assertFalse(info.isSysDba());
17+
}
18+
19+
@Test
20+
void parseSysDba() {
21+
ConnectionConfig info = new ConnectionConfig("sys as sysdba/[email protected]/service");
22+
23+
assertEquals("sys as sysdba", info.getUser());
24+
assertEquals("pw", info.getPassword());
25+
assertEquals("my.local.host/service", info.getConnect());
26+
assertTrue(info.isSysDba());
27+
}
28+
@Test
29+
void parseSysOper() {
30+
ConnectionConfig info = new ConnectionConfig("myOperUser as sysoper/[email protected]/service");
31+
32+
assertEquals("myOperUser as sysoper", info.getUser());
33+
assertEquals("passw0rd", info.getPassword());
34+
assertEquals("my.local.host/service", info.getConnect());
35+
assertTrue(info.isSysDba());
36+
}
37+
38+
@Test
39+
void parseSpecialCharsPW() {
40+
ConnectionConfig info = new ConnectionConfig("test/\"p@ssw0rd=\"@my.local.host/service");
41+
42+
assertEquals("test", info.getUser());
43+
assertEquals("p@ssw0rd=", info.getPassword());
44+
assertEquals("my.local.host/service", info.getConnect());
45+
assertFalse(info.isSysDba());
46+
}
47+
48+
@Test
49+
void parseSpecialCharsUser() {
50+
ConnectionConfig info = new ConnectionConfig("\"User/Mine@=\"/[email protected]/service");
51+
52+
assertEquals("User/Mine@=", info.getUser());
53+
assertEquals("pw", info.getPassword());
54+
assertEquals("my.local.host/service", info.getConnect());
55+
assertFalse(info.isSysDba());
56+
}
57+
}

src/test/java/org/utplsql/cli/DataSourceProviderIT.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ void connectToDatabase() throws SQLException {
2020
assertNotNull(dataSource);
2121
}
2222

23+
//@Test
24+
void connectAsSysdba() throws SQLException {
25+
ConnectionConfig config = new ConnectionConfig("sys as sysdba/oracle@localhost:1522/ORCLPDB1");
26+
DataSource dataSource = new TestedDataSourceProvider(config).getDataSource();
27+
28+
assertNotNull(dataSource);
29+
}
30+
2331
@Test
2432
void initNlsLang() throws SQLException {
2533
System.setProperty("NLS_LANG", "BRAZILIAN PORTUGUESE_BRAZIL.WE8ISO8859P1");

src/test/java/org/utplsql/cli/RunCommandIT.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.utplsql.api.reporter.CoreReporters;
66

77
import java.nio.file.Paths;
8+
import java.sql.SQLException;
89

910
import static org.junit.jupiter.api.Assertions.assertEquals;
1011

@@ -13,6 +14,14 @@
1314
*/
1415
class RunCommandIT extends AbstractFileOutputTest {
1516

17+
private void assertValidReturnCode(int returnCode) throws SQLException {
18+
// Only expect failure-exit-code to work on several framework versions
19+
if (OptionalFeatures.FAIL_ON_ERROR.isAvailableFor(TestHelper.getFrameworkVersion()))
20+
assertEquals(2, returnCode);
21+
else
22+
assertEquals(0, returnCode);
23+
}
24+
1625
@Test
1726
void run_Default() throws Exception {
1827

@@ -23,21 +32,18 @@ void run_Default() throws Exception {
2332
"-c",
2433
"--failure-exit-code=2");
2534

26-
// Only expect failure-exit-code to work on several framework versions
27-
if (OptionalFeatures.FAIL_ON_ERROR.isAvailableFor(TestHelper.getFrameworkVersion()))
28-
assertEquals(2, result);
29-
else
30-
assertEquals(0, result);
35+
assertValidReturnCode(result);
3136
}
3237

3338
@Test
3439
void run_Debug() throws Exception {
3540

3641
int result = TestHelper.runApp("run",
3742
TestHelper.getConnectionString(),
38-
"--debug");
43+
"--debug",
44+
"--failure-exit-code=2");
3945

40-
assertEquals(1, result);
46+
assertValidReturnCode(result);
4147
}
4248

4349
@Test
@@ -55,11 +61,7 @@ void run_MultipleReporters() throws Exception {
5561
"-c",
5662
"--failure-exit-code=2");
5763

58-
// Only expect failure-exit-code to work on several framework versions
59-
if (OptionalFeatures.FAIL_ON_ERROR.isAvailableFor(TestHelper.getFrameworkVersion()))
60-
assertEquals(2, result);
61-
else
62-
assertEquals(0, result);
64+
assertValidReturnCode(result);
6365
}
6466

6567

src/test/java/org/utplsql/cli/RunCommandTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,11 @@ void reporterOptions_TwoReporters() {
8585
assertTrue(reporterOptions2.outputToScreen());
8686
}
8787

88+
@Test
89+
void connectionString_asSysdba() {
90+
RunCommand runCmd = TestHelper.createRunCommand("sys as sysdba/mypass@connectstring/service");
91+
92+
assertEquals("sys as sysdba/mypass@connectstring/service",
93+
runCmd.getConnectionInfo().getConnectionString());
94+
}
8895
}

src/test/java/org/utplsql/cli/TestHelper.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,16 @@ static Version getFrameworkVersion() throws SQLException {
4545
static String getConnectionString() {
4646
return sUser + "/" + sPass + "@" + sUrl;
4747
}
48+
49+
static String getUser() {
50+
return sUser;
51+
}
52+
53+
static String getPass() {
54+
return sPass;
55+
}
56+
57+
static String getUrl() {
58+
return sUrl;
59+
}
4860
}

0 commit comments

Comments
 (0)