Obtendo uma DataSource
implementação
Normalmente, seu driver JDBC fornece uma implementação de
javax.sql.DataSource
. Para obter mais detalhes, consulte minha resposta para uma pergunta semelhante.
PGSimpleDataSource
Se estiver usando o driver JDBC de jdbc.postgresql.org , você pode usar o
org.postgresql.ds.PGSimpleDataSource
class como seu DataSource
implementação. Instanciar um objeto do tipo
PGSimpleDataSource
, chame os métodos setter para fornecer todas as informações necessárias para se conectar ao servidor de banco de dados. A página da Web no site da DigitalOcean lista todas essas informações para sua instância de banco de dados específica. Basicamente isso:
PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setServerName( "your-server-address-goes-here" );
dataSource.setPortNumber( your-port-number-goes-here );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "doadmin" );
dataSource.setPassword( "your-password-goes-here" );
Nomes de servidor e números de porta no plural
Infelizmente, a versão singular dos métodos
setServerName
e setPortNumber
são preteridos. Embora irritante, provavelmente devemos usar a versão plural desses métodos (setServerNames
&setPortNumbers
) que cada um recebe uma matriz. Preenchemos um par de arrays de elemento único, String[]
e int[]
, com o endereço do nosso servidor e número da porta
usando literais de matriz:- { "seu-servidor-endereço-vai-aqui" }
- { your-port-number-goes-here }
PGSimpleDataSource dataSource = new PGSimpleDataSource();
String[] serverAddresses = { "your-server-address-goes-here" };
dataSource.setServerNames( serverAddresses );
int[] serverPortNumbers = { your-port-number-goes-here };
dataSource.setPortNumbers( serverPortNumbers );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "doadmin" );
dataSource.setPassword( "your-password-goes-here" );
Criptografia SSL/TLS
Por fim, precisamos adicionar informações para a criptografia SSL/TLS abordada na pergunta.
Ironicamente, não chame setSsl( true )
Você pensaria que chamaríamos o
setSsl
e passe true
. Mas não. Embora seja contra-intuitivo, definir isso como verdadeiro fará com que suas tentativas de conexão falhem. Eu não sei por que isso é. Mas tentativa e erro me levaram a evitar essa ligação. Certificado de CA
Para que seu aplicativo Java do lado do cliente inicie a conexão SSL/TLS, o driver JDBC deve ter acesso ao certificado CA usado pela Digital Ocean. Na página de administração do Digital Ocean, clique em
Download CA certificate
link para baixar um pequeno arquivo de texto. Esse arquivo será nomeado ca-certificate.crt
. Precisamos alimentar o texto desse arquivo para nosso driver JDBC como uma string. Faça o seguinte para carregar o arquivo em uma string de texto.
// Get CA certificate used in TLS connections.
Path path = Paths.get( "/Users/basilbourque/Downloads/ca-certificate.crt" );
String cert = null;
try
{
cert = Files.readString( path , StandardCharsets.UTF_8 );
System.out.println( "cert = " + cert );
}
catch ( IOException ex )
{
throw new IllegalStateException( "Unable to load the TLS certificate needed to make database connections." );
}
Objects.requireNonNull( cert );
if ( cert.isEmpty() ) {throw new IllegalStateException( "Failed to load TLS cert." ); }
Passe o texto do certificado de CA para o driver JDBC com uma chamada para
DataSource::setSslCert
. Observe que não chamando setSslRootCert
. Não misture os dois métodos com nomes semelhantes. dataSource.setSslCert( cert );
Testando a conexão
Por fim, podemos usar o
DataSource
configurado objeto para fazer uma conexão com o banco de dados. Esse código ficará assim:// Test connection
try (
Connection conn = dataSource.getConnection() ;
// …
)
{
System.out.println( "DEBUG - Postgres connection made. " + Instant.now() );
// …
}
catch ( SQLException e )
{
e.printStackTrace();
}
Código de exemplo completo
Juntando tudo isso, veja algo assim.
// Get CA certificate used in TLS connections.
Path path = Paths.get( "/Users/basilbourque/Downloads/ca-certificate.crt" );
String cert = null;
try
{
cert = Files.readString( path , StandardCharsets.UTF_8 );
System.out.println( "cert = " + cert );
}
catch ( IOException ex )
{
throw new IllegalStateException( "Unable to load the TLS certificate needed to make database connections." );
}
Objects.requireNonNull( cert );
if ( cert.isEmpty() ) {throw new IllegalStateException( "Failed to load TLS cert." ); }
// PGSimpleDataSource configuration
PGSimpleDataSource dataSource = new PGSimpleDataSource();
String[] serverAddresses = { "your-server-address-goes-here" };
dataSource.setServerNames( serverAddresses );
int[] serverPortNumbers = { your-port-number-goes-here };
dataSource.setPortNumbers( serverPortNumbers );
dataSource.setSslCert( cert );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "doadmin" );
dataSource.setPassword( "your-password-goes-here" );
// Test connection
try (
Connection conn = dataSource.getConnection() ;
// …
)
{
System.out.println( "DEBUG - Postgres connection made. " + Instant.now() );
// …
}
catch ( SQLException e )
{
e.printStackTrace();
}
Fonte confiável
Ao criar sua instância do Postgres no DigitalOcean.com, você terá a capacidade de restringir as solicitações de conexão recebidas. Você pode especificar um único endereço IP a ser esperado pelo servidor Postgres, uma “fonte confiável” no jargão da Digital Ocean. Quaisquer hackers que tentem se conectar ao seu servidor Postgres serão ignorados, pois são originários de outros endereços IP.
Dica:Clique dentro do campo de entrada de dados para este número de endereço IP para que a página da web detecte automaticamente e ofereça o endereço IP que está sendo usado atualmente pelo seu navegador da web. Se você estiver executando seu código Java no mesmo computador, use esse mesmo número IP como sua única fonte confiável.
Caso contrário, digite o endereço IP do computador que está executando seu código Java JDBC.
Outros problemas
Não abordei elaborações, como protocolos de segurança adequados para usar para gerenciar seu arquivo de certificado de CA ou como externalizar suas informações de conexão obtendo um
DataSource
objeto de um JNDI
servidor em vez de hard-coding
. Mas espero que os exemplos acima ajudem você a começar.