Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

EclipseLink/Development/Oracle/ProxyAuthentication

Oracle DB Proxy Authentication

Bugs

Bug Assignee Summary
216554 - Provide access to additional property/hints within session and query property maps
224964 - Provide support for Proxy Authentication through JPA
219435 dclarke EXAMPLE: JPA Proxy Authentication
232137 - Can't have exclusive client session without isolated descriptors

Usage Examples

The following usage examples are intended to be the focus of the design as the customer usability is paramount.

Map properties= new HashMap();
 
// This property indicates that proxy-authentication is being used and the provides the
// Integer value used as the first argument to OracleConnection.openProxySession
properties.put("eclipselink.oracle.proxy-type", OracleConnection.PROXYTYPE_USER_NAME);
 
// This map is used as-is in the OracleConnection.openProxySession
Map proxyProps = new HashMap();
proxyProps.put(OracleConnection.PROXY_USER_NAME, "sarah");
 
properties.put("eclipselink.oracle.proxy-properties", proxyProps);


JPA: Application Managed

EntityManager em = getEMF().createEntityManager(properties);

JPA: Container Managed

In container managed an EntityManager is typically injected or accessed through a JNDI lookup. In order to use proxy authentication a mechanism needs to be provided to allow the developer to populate the EntityManager's properties in an equivalent fashion to application managed.

Injected EntityManager

We could allow a developer to provide the values in a SessionEventListener.postAcquireClientSession. In here the developer would lookup any credential information from their container's context and populate it in the client session's property map, which is equivalent to the EntityManager's properties. This approach would require EclipseLink to ensure this event is fired prior to the acquisition of any JDBC connection (lazy or non-lazy).

EntityManagerFactory Injection

Alternative we could instruct developers to inject the EMF into their application components and then create the EntityManager directly passing through the properties.

Native Server/Client Session

Ideally we should have a consistent solution where users in either JPA or native would see the proxy properties in the same locations. Currently the solution provided involves cloning the connection policy and configuration of the additional properties on this policy. This can be somewhat problematic anyways as the user/password information is often contained in this map and can be challenging to separate correctly in all situations from the proxy properties.

server.acquireClientSession(properties);
 
 
server.acquireClientSession("pool-name", properties);
 
 
server.acquireClientSession(login, properties);
 
 
server.acquireClientSession(connectionPolicy, properties);

In each of these cases the properties passed in will be those used initially on the newly created client session.

Implementation/Design

Q: How does EclipseLink know when a customer wants to use database/JDBC specific connection configuration such as proxy authentication?

A:Customer specifies "eclipselink.oracle.proxy-type" property with non-empty value for proxy authentication: if the database platform is Oracle9Platform or higher it will know what to do, otherwise the property is ignored.

Q: Where is the JDBC specific code encapsulated to avoid requiring a particular JDBC driver when the functionality is not being used.

A:In core DatabasePlatform defines a method creating connection customizer that returns null; in oracle extension this method on Oracle9Platform returns proxy connection customizer.

Q: In the Oracle DB proxy authentication case how are the values identified and passed through to OracleConnection.openProxySession(int, Map)?

A: The method accessed through connection customizer that takes a Session as a parameter.

The first argument is an integer value of "eclipselink.oracle.proxy-type" property.

The proxy properties are extracted from session's properties' map and saved in the customizer. Those properties passed as a second parameter to openProxySession method.

Alternatively define "eclipselink.connection.oracle.proxy-properties" property with Property value.

Q: In the container managed injection scenario how can a developer lookup and provide these values to the EM's properties.

A: Call Eclipselink-specific

   ((EntityManagerImpl)em.getDelegate()).setProperties(map);

Proposed Design

Design Motivation

  • The current implementation of PA is based on subclassing JNDIConnector, proxy session being opened before connect method returns. That causes the following problems:
    • Impossible to use on the server other than oc4j - Connector.connect method takes only properties, has no access to ServerPlatform, which required for unwrapping OracleConnection.
    • No natural place to close proxy session: Connector doesn't have clear method.
    • Impossible to use with internal connection pool because its accessors are connected during start up.
    • Awkward to use: currently proxy properties should appear on the login, but ClientSession usually uses connection from a pool (which has its login). It would be much easier to pass ClientSession properties instead.

Main core use cases

  • DatabaseSession. The user sets proxy properties set on DatabaseSession.
  • ServerSession:
    • The same proxy properties used for all connections. The user sets proxy properties set on ServerSession;
    • ClientSession has individual proxy properties. The user sets proxy properties set on ClientSession;
      • ClientSession's properties override ServerSession's properties.

Design overview

  • A new abstract class ConnectionCustomizer introduced: it's responsible for customizing connection (opening proxy session) and clearing customization (closing proxy session).
  • An instance of ConnectionCustomizer is assigned to DatasourceAccessor (only in case it's required) by either DatabaseSession, ConnectionPool or ClientSession.
  • Customization apllied when the accessor connects, also when ClientSession creates customizer (internal connection pool case).
  • Customization cleared when connection closes, also when ConnectionCustomizer is released.
  • Customization released by the object that has created it.

Main core use cases realizations

Let's say "Session has proxy peoperties" if it has not empty "eclipselink.oracle.proxy-type" property that defines a valid proxy type as well as the proxy properties required by the specified type. Example: "eclipselink.oracle.proxy-type" -> OracleConnection.PROXYTYPE_USERNAME; OracleConnection.PROXY_USER_NAME -> "Sarah"

  • DatabaseSession has proxy properties.
    • databaseSession.connect creates ConnectionCustomizer and sets it into the accessor;
    • accessor.connect causes customization;
    • accessor.disconnect causes clear customization;;
    • databaseSession.disconnect releases ConnectionCustomizer
  • ServerSession has proxy properties.
    • Connection pool creates ConnectionCustomizer and sets it into all the accessors it creates.
    • accessor.connect causes customization; (happens before acquireConnection in internal pool)
    • accessor.disconnect causes clear customization;
    • Connection pool releases ConnectionCustomizer when the accessor is no longer used (releaseConnection for external, shutdown for internal).
  • ClientSession has proxy properties.
    • ClientSession.setWriteConnection called with a non-null accessor causes
      • In case ServerSession doesn't have proxy properties - creation and setting of ConnectionCustomizer;
      • In case ServerSession has proxy properties customizer already exists. The new customizer is created using ClientSession and compared to the existing one:
        • If the two customizers are equivalent (which means they produce exactly the same customization) the old (created by ServerSession) customizer is kept;
        • If they are different, then the new customizer is set:
          • The old customization is cleared (internal connection pool case);
          • The new customization is applied (internal connection pool case);
          • The old customizer cahed by the new one - it will be restored when the new one is released.
    • accessor.connect causes customization (external connection pool case);
    • accessor.disconnect causes clear customization (external connection pool case);
    • ClientSession.setWriteConnection called with null accessor causes:
      • If the customizer was created by ServerSession then nothing happens, the customizer is kept;
      • If the customizer was created by the ClientSession then its customization is cleared and
        • If the customized has the cached "previous" customizer (created by ServerSession) that one is set a a new customizer
          • In case connection is connected (internal pool case) the new customization is applied.
    • Connection customization is exactly the same as it was before the ClientSession had acquired the connection.

That means: If ServerSession has proxy properties then these proxy properties used on all connections. If ClientSession has proxy properties then these proxy properties used on its writeConnection.

JPA support

  • To support container managed injection scenario a new setProperties method will be defined in EntityManagerImpl - it allows to set properties, but only when the unit of work either gone or dead (the conflict with another proxy user may arise otherwise).
  • The properies of EntityManagerImpl will be owned by ClientSession (as opposed to current UnitOfWork).
  • Proxy properties passed to createEntityManagerFactory method are set on the ServerSession.
  • Proxy properties passed to createEntityManager method are set on the ClientSession.

Examples

Map factoryProperties = new HashMap();
factoryProperties.put("eclipselink.oracle.proxy-type", OracleConnection.PROXYTYPE_USER_NAME);
factoryProperties.put(OracleConnection.PROXY_USER_NAME, "sarah");
 
Map emProperties = new HashMap();
emProperties.put("eclipselink.oracle.proxy-type", OracleConnection.PROXYTYPE_USER_NAME);
emProperties.put(OracleConnection.PROXY_USER_NAME, "john");
 
Map cancelProperties = new HashMap();
cancelProperties.put("eclipselink.oracle.proxy-type", "");
 
// EntityManagerFactory uses proxy properties that will be used by all connections (unless overridden).
EntityManagerFactory emf = Persistence.createEntityManagerFactory(factoryProperties);
 
// em1 doesn't specify its own proxy properties - uses proxy user "sarah" specified by the factory.
EntityManager em1 = emf.createEntityManager();
 
// em2 uses its own proxy properties - proxy user "john", doesn't matter whether factory has proxy properties or not.
EntityManager em2 = emf.createEntityManager(emProperties);
// or in case of injected EntityManager
((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em2.getDelegate()).setProperties(emProperties);
 
// em3 doesn't use any proxy connection - cancels proxy properties defined in the factory
EntityManager em3 = emf.createEntityManager(cancelProperties);
// or in case of injected EntityManager
((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em3.getDelegate()).setProperties(cancelProperties);

Code

The working implementation with core (not jpa yet) tests is in the latest patch in https://bugs.eclipse.org/bugs/show_bug.cgi?id=224964

More

I'd like to remove OracleJDBC10_1_0_2ProxyConnector and add JPA property for ExclusiveIsolatedClientSession: "eclipselink.connection.exclusive" ?

Back to the top