use of org.postgresql.util.PSQLException in project teiid by teiid.
the class ConnectionFactoryImpl method doAuthentication.
private void doAuthentication(PGStream pgStream, String host, String user, Properties info) throws IOException, SQLException {
// Now get the response from the backend, either an error message
// or an authentication request
String password = PGProperty.PASSWORD.get(info);
/* SSPI negotiation state, if used */
ISSPIClient sspiClient = null;
try {
authloop: while (true) {
int beresp = pgStream.receiveChar();
switch(beresp) {
case 'E':
// An error occurred, so pass the error message to the
// user.
//
// The most common one to be thrown here is:
// "User authentication failed"
//
int l_elen = pgStream.receiveInteger4();
if (l_elen > 30000) {
// server, so trigger fallback.
throw new UnsupportedProtocolException();
}
ServerErrorMessage errorMsg = new ServerErrorMessage(pgStream.receiveErrorString(l_elen - 4));
LOGGER.log(Level.FINEST, " <=BE ErrorMessage({0})", errorMsg);
throw new PSQLException(errorMsg);
case 'R':
// Authentication request.
// Get the message length
int l_msgLen = pgStream.receiveInteger4();
// Get the type of request
int areq = pgStream.receiveInteger4();
// Process the request.
switch(areq) {
case AUTH_REQ_CRYPT:
{
byte[] salt = pgStream.receive(2);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, " <=BE AuthenticationReqCrypt(salt=''{0}'')", new String(salt, "US-ASCII"));
}
if (password == null) {
throw new PSQLException(GT.tr("The server requested password-based authentication, but no password was provided."), PSQLState.CONNECTION_REJECTED);
}
byte[] encodedResult = UnixCrypt.crypt(salt, password.getBytes("UTF-8"));
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, " FE=> Password(crypt=''{0}'')", new String(encodedResult, "US-ASCII"));
}
pgStream.sendChar('p');
pgStream.sendInteger4(4 + encodedResult.length + 1);
pgStream.send(encodedResult);
pgStream.sendChar(0);
pgStream.flush();
break;
}
case AUTH_REQ_MD5:
{
byte[] md5Salt = pgStream.receive(4);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, " <=BE AuthenticationReqMD5(salt={0})", Utils.toHexString(md5Salt));
}
if (password == null) {
throw new PSQLException(GT.tr("The server requested password-based authentication, but no password was provided."), PSQLState.CONNECTION_REJECTED);
}
byte[] digest = MD5Digest.encode(user.getBytes("UTF-8"), password.getBytes("UTF-8"), md5Salt);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, " FE=> Password(md5digest={0})", new String(digest, "US-ASCII"));
}
pgStream.sendChar('p');
pgStream.sendInteger4(4 + digest.length + 1);
pgStream.send(digest);
pgStream.sendChar(0);
pgStream.flush();
break;
}
case AUTH_REQ_PASSWORD:
{
LOGGER.log(Level.FINEST, "<=BE AuthenticationReqPassword");
LOGGER.log(Level.FINEST, " FE=> Password(password=<not shown>)");
if (password == null) {
throw new PSQLException(GT.tr("The server requested password-based authentication, but no password was provided."), PSQLState.CONNECTION_REJECTED);
}
byte[] encodedPassword = password.getBytes("UTF-8");
pgStream.sendChar('p');
pgStream.sendInteger4(4 + encodedPassword.length + 1);
pgStream.send(encodedPassword);
pgStream.sendChar(0);
pgStream.flush();
break;
}
case AUTH_REQ_GSS:
case AUTH_REQ_SSPI:
/*
* Use GSSAPI if requested on all platforms, via JSSE.
*
* For SSPI auth requests, if we're on Windows attempt native SSPI authentication if
* available, and if not disabled by setting a kerberosServerName. On other
* platforms, attempt JSSE GSSAPI negotiation with the SSPI server.
*
* Note that this is slightly different to libpq, which uses SSPI for GSSAPI where
* supported. We prefer to use the existing Java JSSE Kerberos support rather than
* going to native (via JNA) calls where possible, so that JSSE system properties
* etc continue to work normally.
*
* Note that while SSPI is often Kerberos-based there's no guarantee it will be; it
* may be NTLM or anything else. If the client responds to an SSPI request via
* GSSAPI and the other end isn't using Kerberos for SSPI then authentication will
* fail.
*/
final String gsslib = PGProperty.GSS_LIB.get(info);
final boolean usespnego = PGProperty.USE_SPNEGO.getBoolean(info);
boolean useSSPI = false;
/*
* Use SSPI if we're in auto mode on windows and have a request for SSPI auth, or if
* it's forced. Otherwise use gssapi. If the user has specified a Kerberos server
* name we'll always use JSSE GSSAPI.
*/
if (gsslib.equals("gssapi")) {
LOGGER.log(Level.FINE, "Using JSSE GSSAPI, param gsslib=gssapi");
} else if (areq == AUTH_REQ_GSS && !gsslib.equals("sspi")) {
LOGGER.log(Level.FINE, "Using JSSE GSSAPI, gssapi requested by server and gsslib=sspi not forced");
} else {
/* Determine if SSPI is supported by the client */
sspiClient = createSSPI(pgStream, PGProperty.SSPI_SERVICE_CLASS.get(info), /* Use negotiation for SSPI, or if explicitly requested for GSS */
areq == AUTH_REQ_SSPI || (areq == AUTH_REQ_GSS && usespnego));
useSSPI = sspiClient.isSSPISupported();
LOGGER.log(Level.FINE, "SSPI support detected: {0}", useSSPI);
if (!useSSPI) {
/* No need to dispose() if no SSPI used */
sspiClient = null;
if (gsslib.equals("sspi")) {
throw new PSQLException("SSPI forced with gsslib=sspi, but SSPI not available; set loglevel=2 for details", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
}
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Using SSPI: {0}, gsslib={1} and SSPI support detected", new Object[] { useSSPI, gsslib });
}
}
if (useSSPI) {
/* SSPI requested and detected as available */
sspiClient.startSSPI();
} else {
/* Use JGSS's GSSAPI for this request */
org.postgresql.gss.MakeGSS.authenticate(pgStream, host, user, password, PGProperty.JAAS_APPLICATION_NAME.get(info), PGProperty.KERBEROS_SERVER_NAME.get(info), usespnego);
}
break;
case AUTH_REQ_GSS_CONTINUE:
/*
* Only called for SSPI, as GSS is handled by an inner loop in MakeGSS.
*/
sspiClient.continueSSPI(l_msgLen - 8);
break;
case AUTH_REQ_OK:
/* Cleanup after successful authentication */
LOGGER.log(Level.FINEST, " <=BE AuthenticationOk");
// We're done.
break authloop;
default:
LOGGER.log(Level.FINEST, " <=BE AuthenticationReq (unsupported type {0})", areq);
throw new PSQLException(GT.tr("The authentication type {0} is not supported. Check that you have configured the pg_hba.conf file to include the client''s IP address or subnet, and that it is using an authentication scheme supported by the driver.", areq), PSQLState.CONNECTION_REJECTED);
}
break;
default:
throw new PSQLException(GT.tr("Protocol error. Session setup failed."), PSQLState.PROTOCOL_VIOLATION);
}
}
} finally {
/* Cleanup after successful or failed authentication attempts */
if (sspiClient != null) {
try {
sspiClient.dispose();
} catch (RuntimeException ex) {
LOGGER.log(Level.WARNING, "Unexpected error during SSPI context disposal", ex);
}
}
}
}
use of org.postgresql.util.PSQLException in project teiid by teiid.
the class ConnectionFactoryImpl method openConnectionImpl.
public QueryExecutor openConnectionImpl(HostSpec[] hostSpecs, String user, String database, Properties info) throws SQLException {
// Extract interesting values from the info properties:
// - the SSL setting
boolean requireSSL;
boolean trySSL;
String sslmode = PGProperty.SSL_MODE.get(info);
if (sslmode == null) {
// Fall back to the ssl property
// assume "true" if the property is set but empty
requireSSL = trySSL = PGProperty.SSL.getBoolean(info) || "".equals(PGProperty.SSL.get(info));
} else {
if ("disable".equals(sslmode)) {
requireSSL = trySSL = false;
} else if ("require".equals(sslmode) || "verify-ca".equals(sslmode) || "verify-full".equals(sslmode)) {
requireSSL = trySSL = true;
} else {
throw new PSQLException(GT.tr("Invalid sslmode value: {0}", sslmode), PSQLState.CONNECTION_UNABLE_TO_CONNECT);
}
}
// - the TCP keep alive setting
boolean requireTCPKeepAlive = PGProperty.TCP_KEEP_ALIVE.getBoolean(info);
// NOTE: To simplify this code, it is assumed that if we are
// using the V3 protocol, then the database is at least 7.4. That
// eliminates the need to check database versions and maintain
// backward-compatible code here.
//
// Change by Chris Smith <cdsmith@twu.net>
int connectTimeout = PGProperty.CONNECT_TIMEOUT.getInt(info) * 1000;
// - the targetServerType setting
HostRequirement targetServerType;
try {
targetServerType = HostRequirement.valueOf(info.getProperty("targetServerType", HostRequirement.any.name()));
} catch (IllegalArgumentException ex) {
throw new PSQLException(GT.tr("Invalid targetServerType value: {0}", info.getProperty("targetServerType")), PSQLState.CONNECTION_UNABLE_TO_CONNECT);
}
SocketFactory socketFactory = SocketFactoryFactory.getSocketFactory(info);
HostChooser hostChooser = HostChooserFactory.createHostChooser(hostSpecs, targetServerType, info);
Iterator<HostSpec> hostIter = hostChooser.iterator();
while (hostIter.hasNext()) {
HostSpec hostSpec = hostIter.next();
LOGGER.log(Level.FINE, "Trying to establish a protocol version 3 connection to {0}", hostSpec);
//
// Establish a connection.
//
PGStream newStream = null;
try {
newStream = new PGStream(socketFactory, hostSpec, connectTimeout);
// Construct and send an ssl startup packet if requested.
if (trySSL) {
newStream = enableSSL(newStream, requireSSL, info, connectTimeout);
}
// Set the socket timeout if the "socketTimeout" property has been set.
int socketTimeout = PGProperty.SOCKET_TIMEOUT.getInt(info);
if (socketTimeout > 0) {
newStream.getSocket().setSoTimeout(socketTimeout * 1000);
}
// Enable TCP keep-alive probe if required.
newStream.getSocket().setKeepAlive(requireTCPKeepAlive);
// Try to set SO_SNDBUF and SO_RECVBUF socket options, if requested.
// If receiveBufferSize and send_buffer_size are set to a value greater
// than 0, adjust. -1 means use the system default, 0 is ignored since not
// supported.
// Set SO_RECVBUF read buffer size
int receiveBufferSize = PGProperty.RECEIVE_BUFFER_SIZE.getInt(info);
if (receiveBufferSize > -1) {
// value of 0 not a valid buffer size value
if (receiveBufferSize > 0) {
newStream.getSocket().setReceiveBufferSize(receiveBufferSize);
} else {
LOGGER.log(Level.WARNING, "Ignore invalid value for receiveBufferSize: {0}", receiveBufferSize);
}
}
// Set SO_SNDBUF write buffer size
int sendBufferSize = PGProperty.SEND_BUFFER_SIZE.getInt(info);
if (sendBufferSize > -1) {
if (sendBufferSize > 0) {
newStream.getSocket().setSendBufferSize(sendBufferSize);
} else {
LOGGER.log(Level.WARNING, "Ignore invalid value for sendBufferSize: {0}", sendBufferSize);
}
}
LOGGER.log(Level.FINE, "Receive Buffer Size is {0}", newStream.getSocket().getReceiveBufferSize());
LOGGER.log(Level.FINE, "Send Buffer Size is {0}", newStream.getSocket().getSendBufferSize());
List<String[]> paramList = new ArrayList<String[]>();
paramList.add(new String[] { "user", user });
paramList.add(new String[] { "database", database });
paramList.add(new String[] { "client_encoding", "UTF8" });
paramList.add(new String[] { "DateStyle", "ISO" });
paramList.add(new String[] { "TimeZone", createPostgresTimeZone() });
Version assumeVersion = ServerVersion.from(PGProperty.ASSUME_MIN_SERVER_VERSION.get(info));
if (assumeVersion.getVersionNum() >= ServerVersion.v9_0.getVersionNum()) {
// User is explicitly telling us this is a 9.0+ server so set properties here:
paramList.add(new String[] { "extra_float_digits", "3" });
String appName = PGProperty.APPLICATION_NAME.get(info);
if (appName != null) {
paramList.add(new String[] { "application_name", appName });
}
} else {
// User has not explicitly told us that this is a 9.0+ server so stick to old default:
paramList.add(new String[] { "extra_float_digits", "2" });
}
String replication = PGProperty.REPLICATION.get(info);
if (replication != null && assumeVersion.getVersionNum() >= ServerVersion.v9_4.getVersionNum()) {
paramList.add(new String[] { "replication", replication });
}
String currentSchema = PGProperty.CURRENT_SCHEMA.get(info);
if (currentSchema != null) {
paramList.add(new String[] { "search_path", currentSchema });
}
sendStartupPacket(newStream, paramList);
// Do authentication (until AuthenticationOk).
doAuthentication(newStream, hostSpec.getHost(), user, info);
int cancelSignalTimeout = PGProperty.CANCEL_SIGNAL_TIMEOUT.getInt(info) * 1000;
// Do final startup.
QueryExecutor queryExecutor = new ExtendedQueryExecutorImpl(newStream, user, database, cancelSignalTimeout, info);
// Check Master or Slave
HostStatus hostStatus = HostStatus.ConnectOK;
if (targetServerType != HostRequirement.any) {
hostStatus = isMaster(queryExecutor) ? HostStatus.Master : HostStatus.Slave;
}
GlobalHostStatusTracker.reportHostStatus(hostSpec, hostStatus);
if (!targetServerType.allowConnectingTo(hostStatus)) {
queryExecutor.close();
if (hostIter.hasNext()) {
// still more addresses to try
continue;
}
throw new PSQLException(GT.tr("Could not find a server with specified targetServerType: {0}", targetServerType), PSQLState.CONNECTION_UNABLE_TO_CONNECT);
}
runInitialQueries(queryExecutor, info);
// And we're done.
return queryExecutor;
} catch (UnsupportedProtocolException upe) {
// Swallow this and return null so ConnectionFactory tries the next protocol.
LOGGER.log(Level.SEVERE, "Protocol not supported, abandoning connection.");
closeStream(newStream);
return null;
} catch (ConnectException cex) {
// Added by Peter Mount <peter@retep.org.uk>
// ConnectException is thrown when the connection cannot be made.
// we trap this an return a more meaningful message for the end user
GlobalHostStatusTracker.reportHostStatus(hostSpec, HostStatus.ConnectFail);
if (hostIter.hasNext()) {
// still more addresses to try
continue;
}
throw new PSQLException(GT.tr("Connection to {0} refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.", hostSpec), PSQLState.CONNECTION_UNABLE_TO_CONNECT, cex);
} catch (IOException ioe) {
closeStream(newStream);
GlobalHostStatusTracker.reportHostStatus(hostSpec, HostStatus.ConnectFail);
if (hostIter.hasNext()) {
// still more addresses to try
continue;
}
throw new PSQLException(GT.tr("The connection attempt failed."), PSQLState.CONNECTION_UNABLE_TO_CONNECT, ioe);
} catch (SQLException se) {
closeStream(newStream);
if (hostIter.hasNext()) {
// still more addresses to try
continue;
}
throw se;
}
}
throw new PSQLException(GT.tr("The connection url is invalid."), PSQLState.CONNECTION_UNABLE_TO_CONNECT);
}
use of org.postgresql.util.PSQLException in project debezium by debezium.
the class PostgresReplicationConnection method createReplicationStream.
private ReplicationStream createReplicationStream(final LogSequenceNumber lsn) throws SQLException {
PGReplicationStream s;
try {
s = startPgReplicationStream(lsn, plugin.forceRds() ? messageDecoder::optionsWithoutMetadata : messageDecoder::optionsWithMetadata);
messageDecoder.setContainsMetadata(plugin.forceRds() ? false : true);
} catch (PSQLException e) {
if (e.getMessage().matches("(?s)ERROR: option .* is unknown.*")) {
// It is possible we are connecting to an old wal2json plug-in
LOGGER.warn("Could not register for streaming with metadata in messages, falling back to messages without metadata");
s = startPgReplicationStream(lsn, messageDecoder::optionsWithoutMetadata);
messageDecoder.setContainsMetadata(false);
} else if (e.getMessage().matches("(?s)ERROR: requested WAL segment .* has already been removed.*")) {
LOGGER.error("Cannot rewind to last processed WAL position", e);
throw new ConnectException("The offset to start reading from has been removed from the database write-ahead log. Create a new snapshot and consider setting of PostgreSQL parameter wal_keep_segments = 0.");
} else {
throw e;
}
}
final PGReplicationStream stream = s;
final long lsnLong = lsn.asLong();
return new ReplicationStream() {
private static final int CHECK_WARNINGS_AFTER_COUNT = 100;
private int warningCheckCounter = CHECK_WARNINGS_AFTER_COUNT;
// make sure this is volatile since multiple threads may be interested in this value
private volatile LogSequenceNumber lastReceivedLSN;
@Override
public void read(ReplicationMessageProcessor processor) throws SQLException, InterruptedException {
ByteBuffer read = stream.read();
// the lsn we started from is inclusive, so we need to avoid sending back the same message twice
if (lsnLong >= stream.getLastReceiveLSN().asLong()) {
return;
}
deserializeMessages(read, processor);
}
@Override
public void readPending(ReplicationMessageProcessor processor) throws SQLException, InterruptedException {
ByteBuffer read = stream.readPending();
// the lsn we started from is inclusive, so we need to avoid sending back the same message twice
if (read == null || lsnLong >= stream.getLastReceiveLSN().asLong()) {
return;
}
deserializeMessages(read, processor);
}
private void deserializeMessages(ByteBuffer buffer, ReplicationMessageProcessor processor) throws SQLException, InterruptedException {
lastReceivedLSN = stream.getLastReceiveLSN();
messageDecoder.processMessage(buffer, processor, typeRegistry);
}
@Override
public void close() throws SQLException {
processWarnings(true);
stream.close();
}
@Override
public void flushLastReceivedLsn() throws SQLException {
if (lastReceivedLSN == null) {
// nothing to flush yet, since we haven't read anything...
return;
}
doFlushLsn(lastReceivedLSN);
}
@Override
public void flushLsn(long lsn) throws SQLException {
doFlushLsn(LogSequenceNumber.valueOf(lsn));
}
private void doFlushLsn(LogSequenceNumber lsn) throws SQLException {
stream.setFlushedLSN(lsn);
stream.setAppliedLSN(lsn);
stream.forceUpdateStatus();
}
@Override
public Long lastReceivedLsn() {
return lastReceivedLSN != null ? lastReceivedLSN.asLong() : null;
}
private void processWarnings(final boolean forced) throws SQLException {
if (--warningCheckCounter == 0 || forced) {
warningCheckCounter = CHECK_WARNINGS_AFTER_COUNT;
for (SQLWarning w = connection().getWarnings(); w != null; w = w.getNextWarning()) {
LOGGER.debug("Server-side message: '{}', state = {}, code = {}", w.getMessage(), w.getSQLState(), w.getErrorCode());
}
}
}
};
}
use of org.postgresql.util.PSQLException in project molgenis by molgenis.
the class PostgreSqlExceptionTranslator method doTranslate.
@Override
public MolgenisDataException doTranslate(TransactionException transactionException) {
Throwable cause = transactionException.getCause();
if (!(cause instanceof PSQLException)) {
return null;
}
PSQLException pSqlException = (PSQLException) cause;
return doTranslate(pSqlException);
}
use of org.postgresql.util.PSQLException in project molgenis by molgenis.
the class PostgreSqlExceptionTranslator method doTranslate.
private MolgenisDataException doTranslate(SQLException sqlException) {
if (sqlException instanceof BatchUpdateException) {
sqlException = sqlException.getNextException();
}
if (!(sqlException instanceof PSQLException)) {
throw new RuntimeException(format("Unexpected exception class [%s]", sqlException.getClass().getSimpleName()));
}
PSQLException pSqlException = (PSQLException) sqlException;
MolgenisDataException molgenisDataException = doTranslate(pSqlException);
if (molgenisDataException == null) {
molgenisDataException = new MolgenisDataException(sqlException);
}
return molgenisDataException;
}
Aggregations