| /* |
| * 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 = 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()); |
| } |
| } |