Integrated Authentication

For your first case study, you’ll analyze an application that authenticates to Oracle’s Application Server. The Oracle Application Server installs a single sign-on (SSO) server to provide application- wide authentication for users. The Oracle SSO is flexible and supports standard authentication technologies such as SSL and the Java Authentication and Authorization Service (JAAS) specification.

By default, the Oracle SSO utilizes the Oracle Internet Directory (OiD) for its user repository. When a new user is created, several entries are automatically made into OiD. Authentication and authorization information for each user is stored in OiD.

Creating the Application User

The first step in this process will be to create a new user. For the database, you will be using Enterprise Users. All users will be mapped to the same database schema. Therefore, you don’t have to create a new database schema for the users; you only have to map them to a database schema. You will do this later in the “Database Account Setup” section.

The users will access the database via an application deployed to the Oracle Application Server, so an application account is needed. You’ll create the user utilizing Oracle’s OiD Delegated Administration Services (OiDDAS). OiDDAS is the web-based tool deployed with the Oracle Application Server that is used to manage web-based user accounts. The “delegated” part of OiDDAS refers to the ability to distribute responsibility for managing users to separate security administrators within an organization.

When OiDDAS creates the user, it creates a new entry in the LDAP server for the user. This account is the same account the database uses when referencing the Enterprise User. To create the user, you login to OiDDAS as the administrator for the realm (the security domain) in which you wish to create the user. Navigating to the Directory tab, you can create a user by clicking the Create button when the User subtab is selected. Figure 6-1 shows the resulting screen used to create the Knox user.

image from book
Figure 6-1: OiDDAS allows delegated administration of user accounts for different security realms within an organization.

As part of the user creation, appropriate privileges and roles are assigned to the users. This step is also supported through OiDDAS. These privileges and roles control access to the applications. As illustrated in Figure 6-2, you can use the Oracle Enterprise Manager to restrict access to your application to users who have the appropriate privileges. Application privileges, like database privileges, can be either directly granted to users or indirectly granted via roles. Privileges to access a J2EE application are managed by configuration settings, not by code.

image from book
Figure 6-2: Oracle Enterprise Manager allows you to control access to the application by adding users and groups to the application’s security domain.

Once the user is created, they can log in to the application by authenticating to the SSO server. After authentication, the user’s authorizations are automatically retrieved. If the user possesses the correct privileges or roles, the application server will allow them to execute the application.

The important point is that all of this happens transparently (and almost magically) to the application itself. The application doesn’t have to perform any authentication or authorization checks. This greatly simplifies your application code.

Connecting the Application User to the Database

Now that you have the application deployed and your users created, you need to link the application users to the database. You will utilize proxy authentication for this task.

From Chapter 4, you will recall that proxy authentication technology was developed to help solve the challenge of securely passing the user identity to the database, thus allowing the database to employ its security capabilities at a user level. Typically, applications establish a connection pool to the database. The connection pool, which is a pool of preestablished database connections, links the application and users to a database schema. Oracle connections involve two steps.

The first step is to establish the physical connection from the client to the database. A network circuit is established; this task can take several hundred milliseconds (not that fast for highly scalable applications). The second step is to create the user’s database session. This is when the user identification and authentication occurs. This step is “lightweight,” meaning that it doesn’t require as many computing resources. The first step is much slower than the second step because proxy authentication with connection pools involves the creation of database sessions (step two) over existing physical connections (step one). The result is high throughput for the applications. The security or the “proxy” part of proxy authentication allows the connections to occur without the application needing the end-user’s password.

Configuring the Data Source for Proxy Authentication

J2EE applications use a data source to define database connections. This section describes how to configure a data source to support proxy authentication. The following examples are specific to the Oracle Application Server 10g. This process differs from the code examples in Chapter 4 because this example assumes the application has now been deployed to the Oracle Application Server.

There are two necessary steps required here. First, you want to use proxy authentication for secure identity preservation, so you have to configure a data source to use the proper JDBC drivers. Only Oracle’s thick JDBC drivers support proxy authentication. Second, you have to configure the data source to connect to the appropriate database schema. This is the schema from which you will issue your proxy authentication.

As shown in Figure 6-3, the data source can be configured using Oracle Enterprise Manager. The data source record contains the necessary connection information required to connect your application, using proxy authentication, to the database.

image from book
Figure 6-3: Oracle Enterprise Manager can be used to configure the data sources required to connect J2EE applications to databases.

The JDBC driver field specifies the connection object that will be used. Note that the required JDBC driver is the OracleOCIConnectionPool class because it supports the proxy authentication capability. The database username and password are also set here. While it may appear that the password for the user is “APP_PUBLIC”, it isn’t. The password was originally set in the Cleartext field and then updated to use the Indirect Password feature. This ensures the password can’t be seen from the administration screen.

The data sources are stored in an OS file called data-sources.xml. The file lists all the data sources used within the application. Here is a sample data source record:

<data-source        name="OracleDS"    location="jdbc/OracleCoreOCIDS"    xa-location="jdbc/xa/OracleXADS"    ejb-location ="jdbc/OracleDS"    connection-driver="oracle.jdbc.pool.OracleOCIConnectionPool"    username="APP_PUBLIC"    password="->APP_PUBLIC"    url="jdbc:oracle:oci:@dagger"    inactivity-timeout="30"    min-connections="3"    max-connections="10"/> 

Note that the account password is not stored in cleartext. By selecting Use Indirect Password from the Enterprise Manager Edit Data Source screen, the entry will only be a placeholder for the application server to look up the actual password. The “->” in the preceding data source file indicates that the password is stored indirectly.

Getting the User Identity

The application has been deployed and configured. Users have been given appropriate privileges to execute the application. You can now look at the code the application will use to obtain the user’s identity and pass it through to the database.

The most common way to retrieve the user’s name is by calling a standard J2EE method getUserPrincipal() available from the HTTPServletRequest object. This will return the authenticated user’s name, for example, “Knox”:

String currentUser = request.getUserPrincipal().getName();

There is an alternative method you can use. For applications configured to run with Oracle SSO, you can make a different call. The following code returns not the user’s name, but rather their distinguished name (DN). DNs are unique for each user. The DN will not only identify the user, but also allow you to easily make the proxy authentication call to the database.

String userDN = request.getHeader("Osso-User-Dn"); // for 10gAS SSO

These two examples are important because they show the two common ways to identify the user. More importantly, they provide the information you need for proxy authentication. Recall that proxy authentication can occur four ways. The two most common are proxy by username and proxy by distinguished name. If you have the user’s name, you can proxy by username. If you have the user’s DN, you can proxy by distinguished name. For this application, you will use the user’s DN.

Proxy Authenticating with Connection Pools

You next establish a connection pool that will be used for proxy authentication. The pool’s initial connections will be made based on the data source you just created. To obtain a data source connection, you have to use an InitialContext object. This object will return the appropriate data source (database connection) based on the string parameter passed in the lookup method:

  InitialContext initial = new InitialContext();   OracleOCIConnectionPool ds = (OracleOCIConnectionPool)                                   initial.lookup("jdbc/OracleCoreOCIDS");

The connection is made by matching the string parameter (bolded) with the location tag located in the data-sources.xml file. As seen in Figure 6-4, this field is also specified in the Enterprise Manager Configuration screen for the J2EE application. The boxed area shows the Location field, which is matched in the context’s lookup method.

image from book
Figure 6-4: The database connection is resolved by matching the location field for the data source defined for the application.

Proxy by Distinguished Name

At this point, you have the data source but you haven’t established the user’s proxy session. For the proxy authentication, you’ll use the distinguished name value of the user identity. To do this, you’ll first need a Properties object, and then you’ll seed it with your distinguished name.

To establish the proxy authentication connection, you do not use the standard getConnection method. You must use the getProxyConnection method of your DataSource object. You have to pass the properties to the connection to indicate the identity of the user you wish to become (or become proxy to). The following snippet of Java code shows what’s required for looking up the data source and establishing the proxy connection:

  // retrieve user's distinguished name   String userDN = request.getHeader("Osso-User-Dn");    // retrieve the connection pool for our data source   InitialContext initial = new InitialContext();   OracleOCIConnectionPool ds = (OracleOCIConnectionPool)                                   initial.lookup("jdbc/OracleCoreOCIDS");   // set the user's name to be used in the proxy connection call           Properties prop = new Properties();   prop.put(OracleOCIConnectionPool.PROXY_DISTINGUISHED_NAME ,userDN  );     // make the proxy connection   Connection conn = ds.getProxyConnection(                        OracleOCIConnectionPool.PROXYTYPE_DISTINGUISHED_NAME,                         prop);

Database Account Setup

For proxy authentication with EUS, the database will have at least two accounts for this single application. One account will be used for establishing the connection pools for the application’s initial connection. The other account(s) will be used as the shared schema account for the actual end users.

Connection Pool Database Account—Least Privileges

It’s important to understand that the proxy authentication design is fundamentally different than the design used by most applications today. Most applications will connect all end users to the same database schema. That is not necessarily bad. However, in doing so, the application schema is usually granted all privileges required by all users (otherwise the application will not be able to perform the operations required by all users). If this isn’t done in a controlled way, your architecture will be in violation of the least-privilege principle. Your goal with any architecture is to maintain the least-privilege principle.

The connection pool will connect to the database and then create a new database session for the end user(s). For the account to which your connection pool will first be established (APP_PUBLIC in the previous code), it’s important to ensure least privileges so that if, for some reason, the account is compromised, you have limited the actions that can be performed. Granting only the privilege needed to connect to the database complies with the least privilege principle.

To create a least-privilege account for your proxy-ready connection pool, simply create a database user and give them a single privilege: the privilege to connect to the database. Recall that this is not the CONNECT role. The only privilege needed will be the CREATE SESSION privilege. Here is sample code to create a public user and assign them the connection privilege:

sec_mgr@DAGGER> CREATE  USER app_public IDENTIFIED BY tiarhpw2r   2    DEFAULT TABLESPACE users   3    TEMPORARY TABLESPACE temp; User created. sec_mgr@DAGGER> GRANT CREATE SESSION TO app_public; Grant succeeded.

User Database Account(s)

With Oracle EUS, you can have dedicated schemas or shared schemas. This example is only being performed for a single shared schema but there is no reason why you couldn’t use more. Remember that the way to create a shared schema is to specify an empty distinguished name. The following code creates the user and also grants the necessary connection privilege:

sec_mgr@DAGGER> CREATE  USER user_public_global IDENTIFIED GLOBALLY AS ''; User created. sec_mgr@DAGGER> GRANT  CREATE SESSION TO user_public_global; Grant succeeded.

You can now grant any other necessary privileges required for your application. Keep in mind that this should be done in a least-privilege manner. Any privileges that are consistent for all application users can be directly granted to the USER_PUBLIC_GLOBAL schema. Any differences in privilege sets should be implemented with Enterprise Roles and database Global Roles (see Chapter 7). This will ensure that two users that require different privileges but are connected to the same shared schema will actually have different privileges.

You are not quite done. You have two accounts: one for the application’s connection pool and the other for the shared schema used for the Enterprise Users. You need to bridge these two accounts—you need to allow for proxy authentication.

The connection pool will connect to APP_PUBLIC, and the actual end users will be authenticated. In Chapter 4, you saw the privilege to perform a proxy authentication was given to the end user schema, for example, SCOTT. Because the users are Enterprise Users and have no schema, you have to grant the proxy authentication privileges to the Enterprise User shared schema:

sec_mgr@DAGGER> ALTER USER user_public_global   2      GRANT CONNECT THROUGH app_public   3      AUTHENTICATED USING DISTINGUISHED NAME; User altered.

The mapping for the end users, which is stored in OiD, places the users in the USER_PUBLIC_GLOBAL schema after database authentication. The preceding DDL allows the connection pool schema to perform its proxy authentication.

Authentication Blueprint

Let’s review a blueprint of your connection design. Figure 6-5 illustrates the results of your configuration.

image from book
Figure 6-5: User information can be centrally managed in the LDAP directory.

The figure can be described by following the sequential steps listed here parenthetically. The user (Knox, in this example) first attempts to access the application (1). The application server knows the user is unauthenticated and redirects the user to the single sign-on (SSO) server (2). SSO challenges the user for credentials (3) and authenticates the credentials with the LDAP server (4). The SSO server provides the user’s authenticated identity to the application (5).

The application server verifies the user’s privilege to execute the application by retrieving their authorizations from the LDAP server. The user’s identity is needed to perform this step. Note that the SSO server is not an authorization server; no authorization information about the user is initially provided. The applications have to implement their own authorization mechanism. The Oracle Application Server does this automatically for the J2EE applications by retrieving the user’s authorizations from the LDAP server (6).

The application now has an identified, authenticated, and privileged user. A connection is retrieved from the connection pool. The connection pool is connected to the APP_PUBLIC database schema. A proxy authentication is then made based on the user’s distinguished name, which was provided by the SSO (7).

The database, upon receiving the proxy authentication request, will first look for the user in its local table of users. Because no schema exists in the database for the end user, the database must refer to the LDAP server to determine in which schema the user should reside (8). If you were authenticating directly to the database using a password, the password would be authenticated in the LDAP server at this point. The LDAP server also provides a list of any database Global Roles the end user has for this specific database (9).

The users are mapped to the USER_PUBLIC_GLOBAL schema. The database verifies the privilege for a proxy connection to occur from the APP_PUBLIC schema to the USER_PUBLIC_GLOBAL schema and the privilege to create a database session. Once the privileges are verified, the user is logged on to the database. The database session is then automatically set up by the database; that is, logon triggers will fire, roles will be enabled, and so on.

Points of Interest

The preceding authentication architecture works easily because the user is created and managed in a central place. Both the SSO server and the database refer to the same place for user authentication (the same place doesn’t mean the same physical server but the same entry within the same server).

A client-server application could authenticate the user directly to the database using the same password the user supplied to the web-based application. The user would be placed in the same database schema and would have the same privileges as they did when accessing the database through the web application. The authentication consistency is important for ensuring security consistency.

Performance

The initial application authentication process naturally requires some time. However, for the web applications, the authentication process only happens once. Steps one through four are not performed for the user’s subsequent requests. The SSO server and applications both establish a “web session” with the user’s browser. This is normally done automatically without requiring any application code. Once the web session has been established, subsequent requests happen without delay.

Connecting to the database is different. Proxy authentication to an Enterprise User is slower than proxy authentication for a user managed within the database. The database has to authenticate the user and look up the schema and roles for the user in the LDAP server. In my tests, this can add a couple hundred milliseconds to the connection time. Your performance goal is to drive the database connection time to zero. The way to do this is to cache the database session for the user.

There are two risks to caching the database session for each user. First, each user session requires memory. Both the application server and the database server will require enough memory to handle open connections to support all concurrent users. Proxy authentication only creates a new database session, so the memory requirements are minimal. Nevertheless, an evaluation has to be done to determine if this task can be accomplished given the expected (concurrent) user load.

The second risk involves the nature of web applications. In the web environment, there is no guarantee the user will make another web request. If the application has opened a database session for a user that will never return, then memory and processing resources are wasted on the application server and the database. The solution to the performance challenge is to use caching. The solution to the wasted resources problem is to ensure that sessions are closed after a period of inactivity.

You can do this by creating a Java helper program. The Java object will automatically close the database sessions at the appropriate time. The object will be invoked not by your application, but by the application server (actually the web container). Web applications can be configured to release resources after a period of inactivity. This session time-out period will be used as the time period to close the database session.

To use this capability, the object has to implement a specific Java interface. By doing so, the application server will automatically call this object’s valueUnbound method when the user’s web session expires. You simply need to close the database session within this method.

package OSBD; import javax.servlet.http.*; public class DBHolder implements HttpSessionBindingListener {   oracle.jdbc.OracleConnection conn = null;   public DBHolder() { }   public void valueBound(HttpSessionBindingEvent event){}   public void valueUnbound(HttpSessionBindingEvent event) {       if (conn != null) {         try {           conn.close();         } catch (java.sql.SQLException ex) {           System.out.println("can't close SQL conn..."+ex);         }       }   }   public void setConnection(oracle.jdbc.OracleConnection c) {     conn = c;   }   public oracle.jdbc.OracleConnection getConnection() {       return conn;   } } 

To use this design from a JSP or Servlet, use the web application server (container) ability to store values in memory. The following represents the complete code for doing this as a JSP:

<%@ page contentType="text/html;charset=windows-1252"%> <%@ page import="javax.naming.*,javax.sql.*,oracle.jdbc.*,java.sql.*"%> <%@ page import="java.util.*,oracle.jdbc.pool.OracleOCIConnectionPool"%> <%@ page import="oracle.jdbc.pool.OracleDataSource,OSBD.*"%> <%@ page import="oracle.jdbc.oci.OracleOCIConnection"%> <% OracleConnection conn = null;     // retrieve user's distinguished name String userDN = request.getHeader("Osso-User-Dn");      // Try to obtain database session (connection)     // from the Web session DBHolder hold = (DBHolder) session.getAttribute("conn");     // check to see if connection was cached if (hold == null) {       // no connection, create a new one   InitialContext initial = new InitialContext();   OracleOCIConnectionPool ds = (OracleOCIConnectionPool)                                initial.lookup("jdbc/OracleCoreOCIDS");       // set user's name for proxy connection call   Properties prop = new Properties();   prop.put(OracleOCIConnectionPool.PROXY_DISTINGUISHED_NAME,userDN);         // make the proxy connection   conn = ds.getProxyConnection(          OracleOCIConnectionPool.PROXYTYPE_DISTINGUISHED_NAME, prop);       // save connection in session   hold = new DBHolder();   hold.setConnection(conn);   session.setAttribute("conn", hold);    } else {     // Use the saved connection     conn = hold.getConnection();   }     // Can use connection to access database now   // Note: Do NOT close the connection! DBHolder will do that %>

The process is simple. You first try to get a cached connection from the user’s application session. If a connection doesn’t exist, create a new one and store it in the application server session cache. Any subsequent requests will use this cached database connection thus ensuring performance is maintained. Subsequent connections will have a zero cost connect time.

It’s important that you never issue a direct call to close your database connection. The helper object (DBHolder) will do this for you automatically when the user’s web session expires and the application server invokes the valueUnbound method. Using this technique, you can achieve both security and performance.



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