Java: Add JDBC connection SSRF sinks

This commit is contained in:
p0wn4j
2021-11-14 05:08:32 +04:00
parent 5c04516179
commit ee67d27b56
19 changed files with 1106 additions and 1 deletions

View File

@@ -131,6 +131,8 @@ private module Frameworks {
private import semmle.code.java.security.XPath
private import semmle.code.java.security.XsltInjection
private import semmle.code.java.frameworks.Jdbc
private import semmle.code.java.frameworks.Jdbi
private import semmle.code.java.frameworks.HikariCP
private import semmle.code.java.frameworks.SpringJdbc
private import semmle.code.java.frameworks.MyBatis
private import semmle.code.java.frameworks.Hibernate

View File

@@ -0,0 +1,17 @@
/**
* Definitions of sinks in the Hikari Connection Pool library.
*/
import java
import semmle.code.java.dataflow.ExternalFlow
private class SsrfSinkCsv extends SinkModelCsv {
override predicate row(string row) {
row =
[
//"package;type;overrides;name;signature;ext;spec;kind"
"com.zaxxer.hikari;HikariConfig;false;HikariConfig;(Properties);;Argument[0];jdbc-url",
"com.zaxxer.hikari;HikariConfig;false;setJdbcUrl;(String);;Argument[0];jdbc-url"
]
}
}

View File

@@ -52,3 +52,16 @@ private class SqlSinkCsv extends SinkModelCsv {
]
}
}
private class SsrfSinkCsv extends SinkModelCsv {
override predicate row(string row) {
row =
[
//"package;type;overrides;name;signature;ext;spec;kind"
"java.sql;DriverManager;false;getConnection;(String);;Argument[0];jdbc-url",
"java.sql;DriverManager;false;getConnection;(String,Properties);;Argument[0];jdbc-url",
"java.sql;DriverManager;false;getConnection;(String,String,String);;Argument[0];jdbc-url",
"java.sql;Driver;false;connect;(String,Properties);;Argument[0];jdbc-url"
]
}
}

View File

@@ -0,0 +1,21 @@
/**
* Definitions of sinks in the JDBI library.
*/
import java
import semmle.code.java.dataflow.ExternalFlow
private class SsrfSinkCsv extends SinkModelCsv {
override predicate row(string row) {
row =
[
//"package;type;overrides;name;signature;ext;spec;kind"
"org.jdbi.v3.core;Jdbi;false;create;(String);;Argument[0];jdbc-url",
"org.jdbi.v3.core;Jdbi;false;create;(String,Properties);;Argument[0];jdbc-url",
"org.jdbi.v3.core;Jdbi;false;create;(String,String,String);;Argument[0];jdbc-url",
"org.jdbi.v3.core;Jdbi;false;open;(String);;Argument[0];jdbc-url",
"org.jdbi.v3.core;Jdbi;false;open;(String,Properties);;Argument[0];jdbc-url",
"org.jdbi.v3.core;Jdbi;false;open;(String,String,String);;Argument[0];jdbc-url"
]
}
}

View File

@@ -37,3 +37,17 @@ private class SqlSinkCsv extends SinkModelCsv {
]
}
}
private class SsrfSinkCsv extends SinkModelCsv {
override predicate row(string row) {
row =
[
//"package;type;overrides;name;signature;ext;spec;kind"
"org.springframework.boot.jdbc;DataSourceBuilder;false;url;(String);;Argument[0];jdbc-url",
"org.springframework.jdbc.datasource;AbstractDriverBasedDataSource;false;setUrl;(String);;Argument[0];jdbc-url",
"org.springframework.jdbc.datasource;DriverManagerDataSource;false;DriverManagerDataSource;(String);;Argument[0];jdbc-url",
"org.springframework.jdbc.datasource;DriverManagerDataSource;false;DriverManagerDataSource;(String,String,String);;Argument[0];jdbc-url",
"org.springframework.jdbc.datasource;DriverManagerDataSource;false;DriverManagerDataSource;(String,Properties);;Argument[0];jdbc-url"
]
}
}

View File

@@ -7,6 +7,7 @@ import semmle.code.java.frameworks.spring.Spring
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.javase.Http
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.frameworks.Properties
private import semmle.code.java.dataflow.StringPrefixes
private import semmle.code.java.dataflow.ExternalFlow
@@ -33,6 +34,20 @@ private class DefaultRequestForgeryAdditionalTaintStep extends RequestForgeryAdd
}
}
private class TypePropertiesRequestForgeryAdditionalTaintStep extends RequestForgeryAdditionalTaintStep {
override predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ) {
exists(MethodAccess ma |
// Properties props = new Properties();
// props.setProperty("jdbcUrl", tainted);
// Propagate tainted value to the qualifier `props`
ma.getMethod() instanceof PropertiesSetPropertyMethod and
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "jdbcUrl" and
pred.asExpr() = ma.getArgument(1) and
succ.asExpr() = ma.getQualifier()
)
}
}
/** A data flow sink for server-side request forgery (SSRF) vulnerabilities. */
abstract class RequestForgerySink extends DataFlow::Node { }
@@ -40,6 +55,10 @@ private class UrlOpenSinkAsRequestForgerySink extends RequestForgerySink {
UrlOpenSinkAsRequestForgerySink() { sinkNode(this, "open-url") }
}
private class JdbcUrlSinkAsRequestForgerySink extends RequestForgerySink {
JdbcUrlSinkAsRequestForgerySink() { sinkNode(this, "jdbc-url") }
}
/** A sanitizer for request forgery vulnerabilities. */
abstract class RequestForgerySanitizer extends DataFlow::Node { }

View File

@@ -0,0 +1,91 @@
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.DriverManager;
import java.sql.Driver;
import java.sql.SQLException;
import java.io.IOException;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.util.*;
import org.springframework.jdbc.datasource.*;
import org.jdbi.v3.core.Jdbi;
import org.springframework.boot.jdbc.DataSourceBuilder;
public class JdbcUrlSSRF extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String jdbcUrl = request.getParameter("jdbcUrl");
Driver driver = new org.postgresql.Driver();
DataSourceBuilder dsBuilder = new DataSourceBuilder();
try {
driver.connect(jdbcUrl, null); // $ SSRF
DriverManager.getConnection(jdbcUrl); // $ SSRF
DriverManager.getConnection(jdbcUrl, "user", "password"); // $ SSRF
DriverManager.getConnection(jdbcUrl, null); // $ SSRF
dsBuilder.url(jdbcUrl); // $ SSRF
}
catch(SQLException e) {}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String jdbcUrl = request.getParameter("jdbcUrl");
HikariConfig config = new HikariConfig();
config.setJdbcUrl(jdbcUrl); // $ SSRF
config.setUsername("database_username");
config.setPassword("database_password");
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl(jdbcUrl); // $ SSRF
Properties props = new Properties();
props.setProperty("driverClassName", "org.postgresql.Driver");
props.setProperty("jdbcUrl", jdbcUrl);
HikariConfig config2 = new HikariConfig(props); // $ SSRF
}
protected void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String jdbcUrl = request.getParameter("jdbcUrl");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl(jdbcUrl); // $ SSRF
DriverManagerDataSource dataSource2 = new DriverManagerDataSource(jdbcUrl); // $ SSRF
dataSource2.setDriverClassName("org.postgresql.Driver");
DriverManagerDataSource dataSource3 = new DriverManagerDataSource(jdbcUrl, "user", "pass"); // $ SSRF
dataSource3.setDriverClassName("org.postgresql.Driver");
DriverManagerDataSource dataSource4 = new DriverManagerDataSource(jdbcUrl, null); // $ SSRF
dataSource4.setDriverClassName("org.postgresql.Driver");
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String jdbcUrl = request.getParameter("jdbcUrl");
Jdbi.create(jdbcUrl); // $ SSRF
Jdbi.create(jdbcUrl, null); // $ SSRF
Jdbi.create(jdbcUrl, "user", "pass"); // $ SSRF
Jdbi.open(jdbcUrl); // $ SSRF
Jdbi.open(jdbcUrl, null); // $ SSRF
Jdbi.open(jdbcUrl, "user", "pass"); // $ SSRF
}
}

View File

@@ -1,2 +1,2 @@
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/projectreactor-3.4.3/
//semmle-extractor-options: --javac-args -source 11 -target 11 -cp ${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/javax-ws-rs-api-2.1.1:${testdir}/../../../stubs/javax-ws-rs-api-3.0.0:${testdir}/../../../stubs/apache-http-4.4.13/:${testdir}/../../../stubs/servlet-api-2.4/:${testdir}/../../../stubs/projectreactor-3.4.3/:${testdir}/../../../stubs/postgresql-42.3.3/:${testdir}/../../../stubs/HikariCP-3.4.5/:${testdir}/../../../stubs/spring-jdbc-5.3.8/:${testdir}/../../../stubs/jdbi3-core-3.27.2/

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zaxxer.hikari;
public class HikariConfig implements HikariConfigMXBean {
private String jdbcUrl;
public HikariConfig() {
}
public HikariConfig(java.util.Properties properties) {
}
public HikariConfig(String propertyFileName) {
}
public String getJdbcUrl() {
return jdbcUrl;
}
public void setJdbcUrl(String jdbcUrl) {
this.jdbcUrl = jdbcUrl;
}
public long getConnectionTimeout() { return 0; }
public void setConnectionTimeout(long connectionTimeoutMs) {}
public long getValidationTimeout() { return 0; }
public void setValidationTimeout(long validationTimeoutMs) {}
public long getIdleTimeout() { return 0; }
public void setIdleTimeout(long idleTimeoutMs) {}
public long getLeakDetectionThreshold() { return 0; }
public void setLeakDetectionThreshold(long leakDetectionThresholdMs) {}
public long getMaxLifetime() { return 0; }
public void setMaxLifetime(long maxLifetimeMs) {}
public int getMinimumIdle() { return 0; }
public void setMinimumIdle(int minIdle) {}
public int getMaximumPoolSize() { return 0; }
public void setMaximumPoolSize(int maxPoolSize) {}
public void setPassword(String password) {}
public void setUsername(String username) {}
public String getPoolName() {return "";}
public String getCatalog() {return "";}
public void setCatalog(String catalog) {}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright (C) 2013 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zaxxer.hikari;
/**
* The javax.management MBean for a Hikari pool configuration.
*
* @author Brett Wooldridge
*/
public interface HikariConfigMXBean
{
/**
* Get the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @return the connection timeout in milliseconds
*/
long getConnectionTimeout();
/**
* Set the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @param connectionTimeoutMs the connection timeout in milliseconds
*/
void setConnectionTimeout(long connectionTimeoutMs);
/**
* Get the maximum number of milliseconds that the pool will wait for a connection to be validated as
* alive.
*
* @return the validation timeout in milliseconds
*/
long getValidationTimeout();
/**
* Sets the maximum number of milliseconds that the pool will wait for a connection to be validated as
* alive.
*
* @param validationTimeoutMs the validation timeout in milliseconds
*/
void setValidationTimeout(long validationTimeoutMs);
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @return the idle timeout in milliseconds
*/
long getIdleTimeout();
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @param idleTimeoutMs the idle timeout in milliseconds
*/
void setIdleTimeout(long idleTimeoutMs);
/**
* This property controls the amount of time that a connection can be out of the pool before a message is
* logged indicating a possible connection leak. A value of 0 means leak detection is disabled.
*
* @return the connection leak detection threshold in milliseconds
*/
long getLeakDetectionThreshold();
/**
* This property controls the amount of time that a connection can be out of the pool before a message is
* logged indicating a possible connection leak. A value of 0 means leak detection is disabled.
*
* @param leakDetectionThresholdMs the connection leak detection threshold in milliseconds
*/
void setLeakDetectionThreshold(long leakDetectionThresholdMs);
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @return the maximum connection lifetime in milliseconds
*/
long getMaxLifetime();
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @param maxLifetimeMs the maximum connection lifetime in milliseconds
*/
void setMaxLifetime(long maxLifetimeMs);
/**
* The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool,
* including both idle and in-use connections. If the idle connections dip below this value, HikariCP will
* make a best effort to restore them quickly and efficiently.
*
* @return the minimum number of connections in the pool
*/
int getMinimumIdle();
/**
* The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool,
* including both idle and in-use connections. If the idle connections dip below this value, HikariCP will
* make a best effort to restore them quickly and efficiently.
*
* @param minIdle the minimum number of idle connections in the pool to maintain
*/
void setMinimumIdle(int minIdle);
/**
* The property controls the maximum number of connections that HikariCP will keep in the pool,
* including both idle and in-use connections.
*
* @return the maximum number of connections in the pool
*/
int getMaximumPoolSize();
/**
* The property controls the maximum size that the pool is allowed to reach, including both idle and in-use
* connections. Basically this value will determine the maximum number of actual connections to the database
* backend.
* <p>
* When the pool reaches this size, and no idle connections are available, calls to getConnection() will
* block for up to connectionTimeout milliseconds before timing out.
*
* @param maxPoolSize the maximum number of connections in the pool
*/
void setMaximumPoolSize(int maxPoolSize);
/**
* Set the password used for authentication. Changing this at runtime will apply to new connections only.
* Altering this at runtime only works for DataSource-based connections, not Driver-class or JDBC URL-based
* connections.
*
* @param password the database password
*/
void setPassword(String password);
/**
* Set the username used for authentication. Changing this at runtime will apply to new connections only.
* Altering this at runtime only works for DataSource-based connections, not Driver-class or JDBC URL-based
* connections.
*
* @param username the database username
*/
void setUsername(String username);
/**
* The name of the connection pool.
*
* @return the name of the connection pool
*/
String getPoolName();
/**
* Get the default catalog name to be set on connections.
*
* @return the default catalog name
*/
String getCatalog();
/**
* Set the default catalog name to be set on connections.
* <p>
* WARNING: THIS VALUE SHOULD ONLY BE CHANGED WHILE THE POOL IS SUSPENDED, AFTER CONNECTIONS HAVE BEEN EVICTED.
*
* @param catalog the catalog name, or null
*/
void setCatalog(String catalog);
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2013 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zaxxer.hikari;
import javax.sql.DataSource;
import java.io.Closeable;
import java.sql.*;
import java.util.logging.Logger;
public class HikariDataSource extends HikariConfig implements DataSource, Closeable {
public HikariDataSource() {
}
public HikariDataSource(HikariConfig configuration) {
}
public Connection getConnection() throws SQLException {
return null;
}
public Connection getConnection(String username, String password)
throws SQLException {
return null;
}
public java.io.PrintWriter getLogWriter() throws SQLException {
return null;
}
public void setLogWriter(java.io.PrintWriter out) throws SQLException {
}
public void setLoginTimeout(int seconds) throws SQLException {
}
public int getLoginTimeout() throws SQLException {
return 0;
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public <T> T unwrap(java.lang.Class<T> iface) throws java.sql.SQLException {
return null;
}
public boolean isWrapperFor(java.lang.Class<?> iface) throws java.sql.SQLException {
return true;
}
public void close() {
}
}

View File

@@ -0,0 +1,30 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jdbi.v3.core;
import java.io.Closeable;
import java.sql.Connection;
import org.jdbi.v3.core.config.Configurable;
/**
* This represents a connection to the database system. It is a wrapper around
* a JDBC Connection object. Handle provides essential methods for transaction
* management, statement creation, and other operations tied to the database session.
*/
public class Handle implements Closeable, Configurable<Handle> {
public void close() {
}
}

View File

@@ -0,0 +1,78 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jdbi.v3.core;
import org.jdbi.v3.core.config.Configurable;
import java.util.Properties;
public class Jdbi implements Configurable<Jdbi> {
public static Jdbi create(final String url) {
return null;
}
/**
* Creates a new {@link Jdbi} instance from a database URL.
*
* @param url JDBC URL for connections
* @param properties Properties to pass to DriverManager.getConnection(url, props) for each new handle
*
* @return a Jdbi which uses {@link DriverManager} as a connection factory.
*/
public static Jdbi create(final String url, final Properties properties) {
return null;
}
/**
* Creates a new {@link Jdbi} instance from a database URL.
*
* @param url JDBC URL for connections
* @param username User name for connection authentication
* @param password Password for connection authentication
*
* @return a Jdbi which uses {@link DriverManager} as a connection factory.
*/
public static Jdbi create(final String url, final String username, final String password) {
return null;
}
public static Handle open(final String url) {
return null;
}
/**
* Obtain a handle with just a JDBC URL
*
* @param url JDBC Url
* @param username JDBC username for authentication
* @param password JDBC password for authentication
*
* @return newly opened Handle
*/
public static Handle open(final String url, final String username, final String password) {
return null;
}
/**
* Obtain a handle with just a JDBC URL
*
* @param url JDBC Url
* @param props JDBC properties
*
* @return newly opened Handle
*/
public static Handle open(final String url, final Properties props) {
return null;
}
}

View File

@@ -0,0 +1,24 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jdbi.v3.core.config;
/**
* A type with access to access and modify arbitrary Jdbi configuration.
*
* @param <This> The subtype that implements this interface.
*/
public interface Configurable<This> {
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2003, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql;
import java.util.logging.Logger;
import java.sql.*;
public class Driver implements java.sql.Driver {
public Connection connect(String url, java.util.Properties info) throws SQLException {
return null;
}
public boolean acceptsURL(String url) throws SQLException {
return true;
}
public DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
throws SQLException {
return null;
}
public int getMajorVersion() {
return 0;
}
public int getMinorVersion() {
return 0;
}
public boolean jdbcCompliant() {
return true;
}
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.datasource;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.logging.Logger;
import javax.sql.DataSource;
public abstract class AbstractDataSource implements DataSource {
/**
* Returns 0, indicating the default system timeout is to be used.
*/
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
/**
* Setting a login timeout is not supported.
*/
@Override
public void setLoginTimeout(int timeout) throws SQLException {
throw new UnsupportedOperationException("setLoginTimeout");
}
/**
* LogWriter methods are not supported.
*/
@Override
public PrintWriter getLogWriter() {
throw new UnsupportedOperationException("getLogWriter");
}
/**
* LogWriter methods are not supported.
*/
@Override
public void setLogWriter(PrintWriter pw) throws SQLException {
throw new UnsupportedOperationException("setLogWriter");
}
//---------------------------------------------------------------------
// Implementation of JDBC 4.0's Wrapper interface
//---------------------------------------------------------------------
@Override
@SuppressWarnings("unchecked")
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return (T) this;
}
throw new SQLException("DataSource of type [" + getClass().getName() +
"] cannot be unwrapped as [" + iface.getName() + "]");
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
//---------------------------------------------------------------------
// Implementation of JDBC 4.1's getParentLogger method
//---------------------------------------------------------------------
@Override
public Logger getParentLogger() {
return null;
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.datasource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
private String url;
private String username;
private String password;
private String catalog;
private String schema;
private Properties connectionProperties;
/**
* Set the JDBC URL to use for connecting through the Driver.
* @see java.sql.Driver#connect(String, java.util.Properties)
*/
public void setUrl(String url) {
this.url = (url != null ? url.trim() : null);
}
/**
* Return the JDBC URL to use for connecting through the Driver.
*/
public String getUrl() {
return this.url;
}
/**
* Set the JDBC username to use for connecting through the Driver.
* @see java.sql.Driver#connect(String, java.util.Properties)
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Return the JDBC username to use for connecting through the Driver.
*/
public String getUsername() {
return this.username;
}
/**
* Set the JDBC password to use for connecting through the Driver.
* @see java.sql.Driver#connect(String, java.util.Properties)
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Return the JDBC password to use for connecting through the Driver.
*/
public String getPassword() {
return this.password;
}
/**
* Specify a database catalog to be applied to each Connection.
* @since 4.3.2
* @see Connection#setCatalog
*/
public void setCatalog(String catalog) {
this.catalog = catalog;
}
/**
* Return the database catalog to be applied to each Connection, if any.
* @since 4.3.2
*/
public String getCatalog() {
return this.catalog;
}
/**
* Specify a database schema to be applied to each Connection.
* @since 4.3.2
* @see Connection#setSchema
*/
public void setSchema(String schema) {
this.schema = schema;
}
/**
* Return the database schema to be applied to each Connection, if any.
* @since 4.3.2
*/
public String getSchema() {
return this.schema;
}
/**
* Specify arbitrary connection properties as key/value pairs,
* to be passed to the Driver.
* <p>Can also contain "user" and "password" properties. However,
* any "username" and "password" bean properties specified on this
* DataSource will override the corresponding connection properties.
* @see java.sql.Driver#connect(String, java.util.Properties)
*/
public void setConnectionProperties(Properties connectionProperties) {
this.connectionProperties = connectionProperties;
}
/**
* Return the connection properties to be passed to the Driver, if any.
*/
public Properties getConnectionProperties() {
return this.connectionProperties;
}
/**
* This implementation delegates to {@code getConnectionFromDriver},
* using the default username and password of this DataSource.
* @see #getConnectionFromDriver(String, String)
* @see #setUsername
* @see #setPassword
*/
@Override
public Connection getConnection() throws SQLException {
return getConnectionFromDriver(getUsername(), getPassword());
}
/**
* This implementation delegates to {@code getConnectionFromDriver},
* using the given username and password.
* @see #getConnectionFromDriver(String, String)
*/
@Override
public Connection getConnection(String username, String password) throws SQLException {
return getConnectionFromDriver(username, password);
}
/**
* Build properties for the Driver, including the given username and password (if any),
* and obtain a corresponding Connection.
* @param username the name of the user
* @param password the password to use
* @return the obtained Connection
* @throws SQLException in case of failure
* @see java.sql.Driver#connect(String, java.util.Properties)
*/
protected Connection getConnectionFromDriver(String username, String password) throws SQLException {
Properties mergedProps = new Properties();
Properties connProps = getConnectionProperties();
if (connProps != null) {
mergedProps.putAll(connProps);
}
if (username != null) {
mergedProps.setProperty("user", username);
}
if (password != null) {
mergedProps.setProperty("password", password);
}
Connection con = getConnectionFromDriver(mergedProps);
if (this.catalog != null) {
con.setCatalog(this.catalog);
}
if (this.schema != null) {
con.setSchema(this.schema);
}
return con;
}
/**
* Obtain a Connection using the given properties.
* <p>Template method to be implemented by subclasses.
* @param props the merged connection properties
* @return the obtained Connection
* @throws SQLException in case of failure
*/
protected abstract Connection getConnectionFromDriver(Properties props) throws SQLException;
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.datasource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class DriverManagerDataSource extends AbstractDriverBasedDataSource {
/**
* Constructor for bean-style configuration.
*/
public DriverManagerDataSource() {
}
/**
* Create a new DriverManagerDataSource with the given JDBC URL,
* not specifying a username or password for JDBC access.
* @param url the JDBC URL to use for accessing the DriverManager
* @see java.sql.DriverManager#getConnection(String)
*/
public DriverManagerDataSource(String url) {
}
/**
* Create a new DriverManagerDataSource with the given standard
* DriverManager parameters.
* @param url the JDBC URL to use for accessing the DriverManager
* @param username the JDBC username to use for accessing the DriverManager
* @param password the JDBC password to use for accessing the DriverManager
* @see java.sql.DriverManager#getConnection(String, String, String)
*/
public DriverManagerDataSource(String url, String username, String password) {
}
/**
* Create a new DriverManagerDataSource with the given JDBC URL,
* not specifying a username or password for JDBC access.
* @param url the JDBC URL to use for accessing the DriverManager
* @param conProps the JDBC connection properties
* @see java.sql.DriverManager#getConnection(String)
*/
public DriverManagerDataSource(String url, Properties conProps) {
}
/**
* Set the JDBC driver class name. This driver will get initialized
* on startup, registering itself with the JDK's DriverManager.
* <p><b>NOTE: DriverManagerDataSource is primarily intended for accessing
* <i>pre-registered</i> JDBC drivers.</b> If you need to register a new driver,
* consider using {@link SimpleDriverDataSource} instead. Alternatively, consider
* initializing the JDBC driver yourself before instantiating this DataSource.
* The "driverClassName" property is mainly preserved for backwards compatibility,
* as well as for migrating between Commons DBCP and this DataSource.
* @see java.sql.DriverManager#registerDriver(java.sql.Driver)
* @see SimpleDriverDataSource
*/
public void setDriverClassName(String driverClassName) {
}
@Override
protected Connection getConnectionFromDriver(Properties props) throws SQLException {
String url = getUrl();
return getConnectionFromDriverManager(url, props);
}
/**
* Getting a Connection using the nasty static from DriverManager is extracted
* into a protected method to allow for easy unit testing.
* @see java.sql.DriverManager#getConnection(String, java.util.Properties)
*/
protected Connection getConnectionFromDriverManager(String url, Properties props) throws SQLException {
return DriverManager.getConnection(url, props);
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.jdbc;
import javax.sql.DataSource;
public final class DataSourceBuilder<T extends DataSource> {
public DataSourceBuilder<T> url(String url) {
return this;
}
}