Proxy Authentication

Your third alternative is proxy authentication. Proxy authentication uses the OCI connection pool and offers a new connection method called getProxyConnection. This connection call doesn’t require the user’s password. In spite of this fact, proxy authentication is still secure because the authentication requires special privileges.

Note 

Proxy authentication doesn’t require the user’s password.

Proxy Example

The proxy authentication process is simple. The application first establishes the connection pool to the database via the proxy account. The proxy account is the account configured simply to allow the physical database connections (the connection pool) to be established. Figure 4-1 depicts this happening for a connection pool to a database schema APP_USER.

image from book
Figure 4-1: A connection pool is established to the proxy account prior to any web requests

The following example illustrates how to use proxy authentication, and it’s derived from the connection pool examples used above. The first few lines are identical to the OCI Connection Pool code. The first change will be to connect your pool to a new database user called APP_USER. This is done to more accurately portray how you will use proxy authentication for your real applications. You’ll see how to set up and secure this database account in the upcoming “Proxy Authentication Database Setup” section. If you’re following along by executing this code, you’ll need to jump to the user creation steps in the database setup section.

package OSBD; import java.sql.*; import oracle.jdbc.*; import oracle.jdbc.pool.OracleOCIConnectionPool; import oracle.jdbc.oci.OracleOCIConnection; public class ProxyAuthenticationTest  {   public static void main(String[] args)  {     long connectTime=0, connectionStart=0, connectionStop=0;     long connectTime2=0, connectionStart2=0, connectionStop2=0;     long connectTime3=0, connectionStart3=0, connectionStop3=0;     String tnsAlias = "(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = " +                       "  (PROTOCOL = TCP)(HOST = DKNOX)(PORT = 1521)) )" +                       "  (CONNECT_DATA = (SERVICE_NAME = knox10g) ) )";     try {       OracleOCIConnectionPool ods = new OracleOCIConnectionPool();       ods.setURL("jdbc:oracle:oci:@" + tnsAlias);       ods.setUser("app_user");       ods.setPassword("qej4k9lD");       java.util.Properties prop = new java.util.Properties();       prop.setProperty(OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT, "3");       prop.setProperty(OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT, "20");       prop.setProperty(OracleOCIConnectionPool.CONNPOOL_INCREMENT, "1");       ods.setPoolConfig(prop);

The proxy authentication call uses a property value to determine which user to create a proxy database session for. You’ll first establish your connection to SCOTT:

      java.util.Properties userNameProp = new java.util.Properties();       userNameProp.setProperty(OracleOCIConnectionPool.PROXY_USER_NAME,                                 "scott");

To obtain a proxy connection, you have to invoke the getProxyConnection method. The first parameter indicates how you will be authenticating. The upcoming “Proxy Authentication Modes” section discusses the possibilities. This example will record the proxy connection time and uses the username for the proxy authentication mode:

      connectionStart = System.currentTimeMillis();       Connection conn = ods.getProxyConnection(                           OracleOCIConnectionPool.PROXYTYPE_USER_NAME,                            userNameProp);       connectionStop = System.currentTimeMillis();

For the remainder of the program, the only changes from the OCI connection pool examples are the replacements of getConnection with getProxyConnection and one extra call to change the user’s name in the property object to BLAKE:

      connectionStart2 = System.currentTimeMillis();       Connection conn2 = ods.getProxyConnection(                           OracleOCIConnectionPool.PROXYTYPE_USER_NAME,                            userNameProp);       connectionStop2 = System.currentTimeMillis();       connectionStart3 = System.currentTimeMillis();       userNameProp.setProperty(OracleOCIConnectionPool.PROXY_USER_NAME,                                "blake");       Connection conn3 = ods.getProxyConnection(                           OracleOCIConnectionPool.PROXYTYPE_USER_NAME,                            userNameProp);       connectionStop3 = System.currentTimeMillis();       conn.close();       conn2.close();       conn3.close();       ods.close();     } catch (Exception e)    { System.out.println(e.toString()); }     // print connection times           connectTime = (connectionStop - connectionStart);     System.out.println("Initial connection time for pool: " +                          connectTime + " ms.");     connectTime2 = (connectionStop2 - connectionStart2);     System.out.println("Connection 2 to Scott user: " +                          connectTime2 + " ms.");        connectTime3 = (connectionStop3 - connectionStart3);     System.out.println("Connection 3 to Blake user: " +                          connectTime3 + " ms.");      } }

Analyzing the Results

The results from this test are consistent with those in the OCI connection pool using the standard getConnection call:

Initial connection time for pool: 180 ms. Connection 2 to Scott user: 20 ms. Connection 3 to Blake user: 20 ms.

Viewing the Connections

Once again, you can insert a sleep call in your Java code and query the database prior to closing the connections:

sec_mgr@KNOX10g> SELECT   username, server, module   2      FROM v$session   3     WHERE TYPE != 'BACKGROUND'   4       AND username IS NOT NULL   5  ORDER BY username; USERNAME   SERVER    MODULE ---------- --------- ----------- APP_USER   DEDICATED javaw.exe APP_USER   DEDICATED javaw.exe APP_USER   DEDICATED javaw.exe BLAKE      PSEUDO    javaw.exe SCOTT      PSEUDO    javaw.exe SCOTT      PSEUDO    javaw.exe SYSTEM     DEDICATED SQL*Plus 7 rows selected.

The records where the server value is PSEUDO are the proxy sessions. To help you visualize an OCI connection pool, Figure 4-2 depicts a single physical connection with three sessions multiplexed. The top session is for the user BLAKE, and the bottom two are for the user SCOTT. The dedicated physical connection is to the APP_USER schema.

image from book
Figure 4-2: A dedicated physical connection to the APP_USER schema with three sessions multiplexed via the OCI connection pool

Proxy Authentication Database Setup

The APP_USER schema requires only one privilege: the CREATE SESSION privilege. No other privileges are needed nor should be given to this account. This is in contrast to the way most connection pool database accounts are configured today where that account generally has all privileges. The proxy account should only have the ability to connect to the database; it shouldn’t have the superset of all privileges of all users! This configuration conforms to the least-privilege principle.

Creating the Proxy User

Creating the proxy user is a simple task:

sec_mgr@KNOX10g> CREATE USER app_user IDENTIFIED BY qej4k9ld; User created. sec_mgr@KNOX10g> GRANT CREATE SESSION TO app_user; Grant succeeded. 

Next, you must allow APP_USER to connect as the end users that will be using your application. In the preceding example code, the APP_USER could proxy to SCOTT and BLAKE. Intuitively, you might think that you have to issue something like “Grant proxy authenticate to APP_USER for SCOTT”, but as you can see this syntax doesn’t flow well. Instead, the syntax isn’t granting a privilege to APP_USER, but rather altering the user to allow someone to proxy to him:

sec_mgr@KNOX10g> ALTER USER scott GRANT CONNECT THROUGH app_user; User altered. sec_mgr@KNOX10g> ALTER USER blake GRANT CONNECT THROUGH app_user; User altered.

This syntax shows the least restrictive way to issue this privilege. You can, and should, further restrict what roles the user can enable, and explore whether the proxy authentication request needs additional authenticating credentials.

Securing the Proxy Account

The proxy account, APP_USER in the previous example, should be protected either by strong password or some form of strong authentication. Even though APP_USER has the least amount of privileges possible (the CREATE SESSION privilege), you don’t want people to be able to easily guess the password. Another reason to avoid this is that if the user has privileges they could also issue proxy authentication calls to other user accounts.

Because the proxy authentication calls have to be done over Oracle’s OCI layer, which can use the Advanced Security features, the network encryption and integrity capabilities can and should be leveraged. When configured, all connections are secured from the application server to the database. If this isn’t done, there’s a risk of network eavesdropping, and this may prove to be the weakest link in the chain. It’s much easier to snoop packets than to hack the database authentication, access control, and auditing mechanisms. Refer to Chapter 2 or the Oracle Database Advanced Security Administrator’s Guide 10g for information on how to set up the secure network connection.

Restricting Access to Roles

You can restrict the authorizations that occur through your proxy connection by specifying the roles that can be enabled when you grant the privileges within the database. Assuming the application needs only the APP_A_ROLE, you can prevent the application from enabling other database roles. This is especially important for the DBA role and roles for other applications and most importantly supports the concept of least-privileges. For more detailed information on database roles, see Chapter 7.

sec_mgr@KNOX10g> -- create database role   sec_mgr@KNOX10g> CREATE ROLE app_a_role; Role created. sec_mgr@KNOX10g> -- grant role to user   sec_mgr@KNOX10g> GRANT  app_a_role TO scott; Grant succeeded. sec_mgr@KNOX10g> -- disable role by default   sec_mgr@KNOX10g> ALTER USER scott DEFAULT ROLE ALL EXCEPT app_a_role; User altered. sec_mgr@KNOX10g> -- grant proxy privileges along with   sec_mgr@KNOX10g> -- ability to enable the app_a_role   sec_mgr@KNOX10g> ALTER  USER scott GRANT CONNECT THROUGH app_user     2                WITH ROLE app_a_role; User altered.

The preceding configuration restricts SCOTT to the APP_A_ROLE when proxied from the APP_USER account. All other roles, including default enabled roles, can’t be enabled.

This is very practical because privileges for an application can be grouped into roles specific for that application.

Tip 

To enforce a good security design, the proxy authentication grants should be made to allow only the roles needed by the application.

The preceding syntax does just that for the APP_A_ROLE. Note also the following examples:

-- this disallows any roles to be set     ALTER USER scott GRANT CONNECT THROUGH app_user        WITH NO ROLES; --this allows all roles but DBA   ALTER USER scott GRANT CONNECT THROUGH app_user      WITH ROLE ALL EXCEPT DBA;

To illustrate the role restrictions, we’ll look at an example that restricts users to specific roles when proxy authenticating. The SCOTT user, by default, is granted the CONNECT and RESOURCE roles. Both are default roles that are automatically enabled upon logon. This is illustrated by the following query issued after logon as the SCOTT user:

scott@KNOX10g> SELECT ROLE FROM session_roles; ROLE   ------------------------------ CONNECT   RESOURCE

Assume you want to disable the RESOURCE role when the user connects via proxy authentication. The CONNECT role will remain enabled for proxy authentication because it contains the CREATE SESSION privilege needed to establish his database session. The RESOURCE role is disabled for proxy authentication because the user requires no privileges from this role when accessing the database via your application.

sec_mgr@KNOX10g> ALTER USER scott     2      GRANT CONNECT THROUGH app_user      3      WITH ROLE ALL EXCEPT RESOURCE; User altered.

The following program is used to illustrate the role restrictions. The program will proxy authenticate to SCOTT and check the currently enabled roles. This first section of code shows the connection pool creation and the proxy authentication call.

package OSBD; import java.sql.*; import oracle.jdbc.*; import oracle.jdbc.pool.OracleOCIConnectionPool; import oracle.jdbc.oci.OracleOCIConnection; public class ProxyRoles  {    public static void main(String[] args)  {     String tnsAlias = "(DESCRIPTION = (ADDRESS_LIST = (ADDRESS = " +                       "  (PROTOCOL = TCP)(HOST = DKNOX)(PORT = 1521)) )" +                       "  (CONNECT_DATA = (SERVICE_NAME = knox10g) ) )";     OracleOCIConnectionPool ods = null;     try {       ods = new OracleOCIConnectionPool();       ods.setURL("jdbc:oracle:oci:@" + tnsAlias);       ods.setUser("app_user");       ods.setPassword("qej4k9lD");       java.util.Properties userNameProp = new java.util.Properties();       userNameProp.setProperty(OracleOCIConnectionPool.PROXY_USER_NAME,                                 "scott");       Connection conn = ods.getProxyConnection(                           OracleOCIConnectionPool.PROXYTYPE_USER_NAME,                            userNameProp);

At this point, the program retrieves the user’s enabled roles:

      Statement stmt = conn.createStatement();       ResultSet rset = stmt.executeQuery("select role from session_roles");       while (rset.next()) {         System.out.println(rset.getString(1));       }      

Next, the program will attempt to enable the RESOURCE role. Afterward, the roles are printed to verify whether this succeeded.

      CallableStatement cstmt = conn.prepareCall(                                "{CALL DBMS_SESSION.SET_ROLE('RESOURCE')}");       cstmt.executeUpdate();       rset = stmt.executeQuery("select role from session_roles");       while (rset.next()) {         System.out.println(rset.getString(1));       }      

The remaining code closes the connections. There is also one very important thing to do now: catch any thrown exceptions and close your data source in the exception handler. This is a good practice. Exceptions are thrown all the time for many reasons. If you don’t close your connections in the exception handler, the connections may be left open to consume precious resources on the server:

      cstmt.close();       rset.close();       stmt.close();       conn.close();       ods.close();     } catch (Exception e) {        System.out.println(e.toString());        try {         ods.close();       } catch (Exception e2) {}     }   } }

The output from this program validates your security configuration:

CONNECT   java.sql.SQLException: ORA-28157: Proxy user 'APP_USER' forbidden to set role ' RESOURCE' for client 'SCOTT' ORA-06512: at "SYS.DBMS_SESSION", line 124   ORA-06512: at line 1

Note 

The RESOURCE role in the previous code, which is actually a default role when the user logs in directly, isn’t a default role for the proxy session.

Figure 4-3 illustrates the fact that the user is able to enable different roles and thus different privileges depending on how they are connected. The database supports a distinct set of privileges for the proxy authentication. This is important because the RESOURCE role might instead be the DBA role. You don’t want the user to have DBA privileges when accessing the database through your application. Oracle can enforce this security policy for you.

image from book
Figure 4-3: Users’ roles can be disabled when accessing the database via proxy authentication.

This feature allows you to support least privileges when you have a user accessing the same database through multiple applications. Each application may have its own security policy. When the user accesses the database via one application, they should have only the privileges required for that application. For example, application “A” would have a connection pool to the APP_USER_A schema and would be allowed to proxy authenticate SCOTT with APP_A_ROLE. Application “B” would have a connection pool to the APP_USER_B schema and would be allowed to proxy authenticate SCOTT with APP_B_ROLE. Restricting roles via proxy authentication ensures that you are running in a least-privilege environment.

While this prevents users who are proxy authenticated from enabling certain roles, it doesn’t prevent directly authenticated users from enabling roles. To prevent directly authenticated users from enabling roles, see Chapter 7.

Note 

Database global roles and secure application roles can’t be restricted in proxy authentication, and any roles granted to PUBLIC can’t be restricted either.

The database privileges can be verified by querying the PROXY_USERS view, as shown in the following example:

sec_mgr@KNOX10g> COL proxy format a10   sec_mgr@KNOX10g> COL client format a10   sec_mgr@KNOX10g> SELECT * FROM proxy_users; PROXY      CLIENT     AUT FLAGS   ---------- ---------- --- -----------------------------------   APP_USER   BLAKE      NO  PROXY MAY ACTIVATE ALL CLIENT ROLES   APP_USER   SCOTT      YES PROXY MAY ACTIVATE ROLE

Proxy Authentication Modes

The preceding example shows how privileges are granted and how roles can be restricted using proxy authentication. You have seen how the user can be proxy authenticated by username. There are four modes supported for proxy authentication requests:

  • Proxy by providing only the username

  • Proxy by providing the username and password

  • Proxy by providing the user’s distinguished name

  • Proxy by providing the user’s X.509 certificate

Simple Username Proxy

In the first mode, which you have already seen in the examples, the proxy call simply passes the name of the user to which you want to connect. No other credentials are required. The benefit of this mode is in its simplicity. The application merely needs to determine what user to proxy to, and the proxy connection will occur.

From the security perspective, the database privileges have to exist for this to succeed, meaning that there is no significant security risk in doing this even though no other credentials are being passed to the database.

Username and Password

In the second mode, the user is proxied by supplying both the username and the user’s (database) password. This is identical to obtaining a standard connection from the OCI connection pool except for one big difference: the proxy authentication allows you to restrict the roles the application can enable. Therefore, if there is a way to obtain the user’s database password in a secure manner, proxy authentication is a better method than using a standard OCI connection because it supports role restrictions.

For all modes of proxy authentication, you can specify which mode you plan to use when you grant the privileges in the database. This provides additional security because it ensures a proxy authentication call can’t occur unless you have the user’s database password. The following example illustrates how to enforce the password authentication to the SCOTT user when proxied from APP_USER.

 ALTER USER scott     GRANT CONNECT THROUGH app_user     AUTHENTICATED USING PASSWORD;

When you try to connect from your Java application used in the preceding example, which does not provide the user’s password, you get the following error:

java.sql.SQLException: ORA-28183: proper authentication not provided by proxy

Proxy by Distinguished Name

A third option is to proxy by distinguished name (DN). The DNs are the primary key equivalents to an LDAP directory and are used to uniquely identify objects located within the directory—users, in this case.

This proxy mode is attractive because many applications and application servers use LDAP for their authentication mechanisms. The Oracle Application Server in conjunction with Oracle Single Sign-on uses LDAP for authentication. Consequently, you have easy access to the user’s DN by simply making a request to the application container. An example of how to do this is given in Chapter 6.

Proxy by Certificate

The fourth mode is the ability to proxy via X.509 certificate. The X.509 certificate can be used in a secure, strongly authenticated http with SSL session from the client browser to the application server. The application server can take this public certificate and use it as the authentication mode to the database. A benefit to this is that it allows the database to interrogate the certificate for other access control measures it may wish to enforce.

Forcing Proxy Authentication

Applying what you’ve learned about proxy authentication, associated privileges, and Oracle passwords, you can create a design that allows a user to be authenticated only via proxy authentication.

The security requirement is to only allow user access to the database when access is done via the application(s). If you wish to restrict access to the database through a specific application, you can’t lock the account or revoke the CREATE SESSION privilege because these are needed for proxy authentication. You could potentially write a log-on trigger to do this, but there is a more effective way.

Set the database user’s password to be an impossible password (see Chapter 2 for more details). This ensures that the user can’t log on directly using a password (although SSL authentication would still be possible). The only way for a user to get a database session will be to use proxy authentication.



Effective Oracle Database 10g Security by Design
Effective Oracle Database 10g Security by Design
ISBN: 0072231300
EAN: 2147483647
Year: 2003
Pages: 111

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net