blob: bd217f53cb277ddd159dcdac0a1dddad752bed14 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// 05/28/2008-1.0M8 Andrei Ilitchev
// - New file introduced for bug 224964: Provide support for Proxy Authentication through JPA.
package org.eclipse.persistence.platform.database.oracle;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.exceptions.ConversionException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.databaseaccess.Accessor;
import org.eclipse.persistence.internal.databaseaccess.ConnectionCustomizer;
import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.sessions.Session;
/**
* PUBLIC:
* This class allows connection to open proxy session.
*/
public class OracleJDBC_10_1_0_2ProxyConnectionCustomizer extends ConnectionCustomizer {
protected OracleConnection oracleConnection;
protected int proxyType;
protected Properties proxyProperties;
/**
* INTERNAL:
* Should be instantiated only if session.getProperty(PersistenceUnitProperties.ORACLE_PROXY_TYPE) != null.
*/
public OracleJDBC_10_1_0_2ProxyConnectionCustomizer(Accessor accessor, Session session) {
super(accessor, session);
}
/**
* INTERNAL:
* Applies customization to connection.
* Called only if connection is not already customized (isActive()==false).
* The method may throw SQLException wrapped into DatabaseException.
* isActive method called after this method should return true only in case
* the connection was actually customized.
*/
@Override
public void customize() {
// Lazily initialize proxy properties - customize method may be never called
// in case of ClientSession using external connection pooling.
if(proxyProperties == null) {
buildProxyProperties();
}
Connection connection = accessor.getConnection();
if(connection instanceof OracleConnection) {
oracleConnection = (OracleConnection)connection;
} else {
connection = session.getServerPlatform().unwrapConnection(connection);
if(connection instanceof OracleConnection) {
oracleConnection = (OracleConnection)connection;
} else {
throw ValidationException.oracleJDBC10_1_0_2ProxyConnectorRequiresOracleConnection();
}
}
try {
clearConnectionCache();
Object[] args = null;
if (this.session.shouldLog(SessionLog.FINEST, SessionLog.CONNECTION)) {
Properties logProperties = proxyProperties;
if(proxyProperties.containsKey(OracleConnection.PROXY_USER_PASSWORD)) {
logProperties = (Properties)proxyProperties.clone();
logProperties.setProperty(OracleConnection.PROXY_USER_PASSWORD, "******");
}
args = new Object[]{ oracleConnection, logProperties };
}
if(oracleConnection.isProxySession()) {
// Unexpectedly oracleConnection already has a proxy session - probably it was not closed when connection was returned back to connection pool.
// That may happen on jta transaction rollback (especially triggered outside of user's thread - such as timeout)
// when beforeCompletion is never issued
// and application server neither closes proxySession nor allows access to connection in afterCompletion.
try {
if (args != null) {
((AbstractSession)this.session).log(SessionLog.FINEST, SessionLog.CONNECTION, "proxy_connection_customizer_already_proxy_session", args);
}
oracleConnection.close(OracleConnection.PROXY_SESSION);
} catch (SQLException exception) {
// Ignore
this.session.getSessionLog().logThrowable(SessionLog.WARNING, SessionLog.CONNECTION, exception);
}
}
oracleConnection.openProxySession(proxyType, proxyProperties);
// 12c driver will default to an autoCommit setting of true on calling openProxySession
oracleConnection.setAutoCommit(false);
if (args != null) {
((AbstractSession)this.session).log(SessionLog.FINEST, SessionLog.CONNECTION, "proxy_connection_customizer_opened_proxy_session", args);
}
} catch (SQLException exception) {
oracleConnection = null;
throw DatabaseException.sqlException(exception);
} catch (NoSuchMethodError noSuchMethodError) {
oracleConnection = null;
throw ValidationException.oracleJDBC10_1_0_2ProxyConnectorRequiresOracleConnectionVersion();
}
}
/**
* INTERNAL:
* Indicated whether the connection is currently customized.
*/
@Override
public boolean isActive() {
return oracleConnection != null;
}
/**
* INTERNAL:
* Clears customization from connection.
* Called only if connection is customized (isActive()==true).
* If the method fails due to SQLException it should "eat" it
* (just like DatasourceAccessor.closeConnection method).
* isActive method called after this method should always return false.
*/
@Override
public void clear() {
try {
clearConnectionCache();
if (this.session.shouldLog(SessionLog.FINEST, SessionLog.CONNECTION)) {
Properties logProperties = proxyProperties;
if(proxyProperties.containsKey(OracleConnection.PROXY_USER_PASSWORD)) {
logProperties = (Properties)proxyProperties.clone();
logProperties.setProperty(OracleConnection.PROXY_USER_PASSWORD, "******");
}
Object[] args = new Object[]{ oracleConnection, logProperties };
((AbstractSession)this.session).log(SessionLog.FINEST, SessionLog.CONNECTION, "proxy_connection_customizer_closing_proxy_session", args);
}
oracleConnection.close(OracleConnection.PROXY_SESSION);
} catch (SQLException exception) {
// Ignore
this.session.getSessionLog().logThrowable(SessionLog.WARNING, SessionLog.CONNECTION, exception);
} finally {
oracleConnection = null;
}
}
/**
* INTERNAL:
* Normally called only when customizer is in inactive state (isActive()==false)
* and followed by setAccessor call on the clone.
*/
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException exception) {
throw new InternalError("clone not supported");
}
}
/**
* INTERNAL:
* Two customizers considered equal if they produce the sane customization.
*/
@Override
public boolean equals(Object obj) {
if(obj instanceof OracleJDBC_10_1_0_2ProxyConnectionCustomizer) {
return equals((OracleJDBC_10_1_0_2ProxyConnectionCustomizer)obj);
} else {
return false;
}
}
/**
* INTERNAL:
* Two customizers considered equal if they produce the sane customization.
*/
public boolean equals(OracleJDBC_10_1_0_2ProxyConnectionCustomizer customizer) {
if(this == customizer) {
return true;
}
if(this.proxyProperties == null) {
buildProxyProperties();
}
if(customizer.proxyProperties == null) {
customizer.buildProxyProperties();
}
return this.proxyType == customizer.proxyType && this.proxyProperties.equals(customizer.proxyProperties);
}
/**
* INTERNAL:
* Precondition: session.getProperty(PersistenceUnitProperties.ORACLE_PROXY_TYPE) != null
*/
protected void buildProxyProperties() {
Object proxyTypeValue = session.getProperty(PersistenceUnitProperties.ORACLE_PROXY_TYPE);
try {
proxyType = (Integer) session.getPlatform().getConversionManager().convertObject(proxyTypeValue, Integer.class);
} catch (ConversionException conversionException) {
throw ValidationException.oracleJDBC10_1_0_2ProxyConnectorRequiresIntProxytype();
}
proxyProperties = new Properties();
if(proxyType == OracleConnection.PROXYTYPE_USER_NAME) {
String proxyUserName = (String)session.getProperty(OracleConnection.PROXY_USER_NAME);
if(proxyUserName != null) {
proxyProperties.setProperty(OracleConnection.PROXY_USER_NAME, proxyUserName);
} else {
ValidationException.expectedProxyPropertyNotFound("OracleConnection.PROXYTYPE_USER_NAME", OracleConnection.PROXY_USER_NAME);
}
} else if(proxyType == OracleConnection.PROXYTYPE_DISTINGUISHED_NAME) {
String distinguishedName = (String)session.getProperty(OracleConnection.PROXY_DISTINGUISHED_NAME);
if(distinguishedName != null) {
proxyProperties.setProperty(OracleConnection.PROXY_DISTINGUISHED_NAME, distinguishedName);
} else {
ValidationException.expectedProxyPropertyNotFound("OracleConnection.PROXYTYPE_DISTINGUISHED_NAME", OracleConnection.PROXY_DISTINGUISHED_NAME);
}
} else if(proxyType == OracleConnection.PROXYTYPE_CERTIFICATE) {
Object certificate = session.getProperty(OracleConnection.PROXY_CERTIFICATE);
if(certificate != null) {
proxyProperties.put(OracleConnection.PROXY_CERTIFICATE, certificate);
} else {
ValidationException.expectedProxyPropertyNotFound("OracleConnection.PROXYTYPE_CERTIFICATE", OracleConnection.PROXY_CERTIFICATE);
}
} else {
ValidationException.unknownProxyType(proxyType, "OracleConnection.PROXYTYPE_USER_NAME", "OracleConnection.PROXYTYPE_DISTINGUISHED_NAME", "OracleConnection.PROXYTYPE_CERTIFICATE");
}
String proxyUserPassword = (String)session.getProperty(OracleConnection.PROXY_USER_PASSWORD);
// set the value if it's not null and not an empty String
if(proxyUserPassword != null && proxyUserPassword.length() > 0) {
proxyProperties.setProperty(OracleConnection.PROXY_USER_PASSWORD, proxyUserPassword);
}
Object proxyRoles = session.getProperty(OracleConnection.PROXY_ROLES);
// set the value if it's not null and not an empty String
if(proxyRoles != null && !((proxyRoles instanceof String) && (((String)proxyRoles).length() == 0))) {
proxyProperties.put(OracleConnection.PROXY_ROLES, proxyRoles);
}
}
/**
* INTERNAL:
* Clears connection's both implicit and explicit caches.
*/
protected void clearConnectionCache() {
this.getSession().getServerPlatform().clearStatementCache(this.getAccessor().getConnection());
((DatabaseAccessor)this.getAccessor()).clearStatementCache((AbstractSession)this.getSession());
}
}