X.509
certificates with Oracle Application Server
Starting from the first and second document I'm going to test the
connection via certificates from an oracle application server to an
oracle database.
The steps will be:
- application server security configuration (certificate generation),
- connection pool and datasource definition.
- test.
My architecture:
client: SLES9 with Oracle Application Server 10.1.3
client name: breoraasls02
server: SLES 9 SP2 with Oracle RDBMS 10.1.0.4
server name: breousdbls02
Instance name: UBANKP
APPLICATION SERVER SIDE:
Usually I generate the certificates and certificates requests with
orapki.
this time I wished to test the owm and the GUI so:
oracle@breoraasls02:~>
mkdir -p /opt/oracle/wallet/WALLETS/oracle
oracle@breoraasls02:~>
owm &
From the GUI I create the wallet and the certificate request. Then I
export this request.
When I have my certificate request I transport it on the server where
my CA wallet is located:
oracle@breoraasls02:~/wallet/WALLETS/oracle> scp test_conn.req
oracle@breousdbls02.ras:~/wallet/WALLETS/oracle
The authenticity of host 'breousdbls02.ras (192.168.24.145)' can't be
established.
RSA key fingerprint is 05:49:21:34:e6:77:8e:34:3a:89:12:98:4f:20:28:c7.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'breousdbls02.ras,192.168.24.145' (RSA) to
the list of known hosts.
Password:
test_conn.req
100% 642 0.6KB/s 00:00
And I sign it creating a certificate.
orapki cert create -wallet wallet-ca -request test_conn.req -cert
test_conn.cer -validity 3650
I transport the certificate back on the application server and with it
my ca certificate.
oracle@breoraasls02:~/wallet/WALLETS/oracle> scp
oracle@breousdbls02.ras:~/wallet/WALLETS/oracle/test_conn.cer .
Password:
test_conn.cer
100% 807 0.8KB/s 00:00
oracle@breoraasls02:~/wallet/WALLETS/oracle> scp
oracle@breousdbls02.ras:~/wallet/WALLETS/oracle/root-ca.cer .
Password:
root-ca.cer
100% 807 0.8KB/s 00:00
With the oracle wallet manager I import the user certificate and the
trusted certificate (the CA one).
Now on the database I create the user test_conn:
SQL> create user test_conn identified globally as
'CN=test_conn,OU=AS,O=RAS,L=Milan,ST=Milan,C=IT';
SQL> grant create session to test_conn;
and a dummy user pippo:
SQL> create user dummyuser identified by dummyuser;
SQL> grant create session to dummyuser;
This user is going to be authenticated without password.
The DN is checked instead and compared to the certificates' DNs stored
in the wallet.
From 10gR2 on you need to use:
create user Fabrizio identified
externally as 'CN=test_conn,OU=AS,O=RAS,L=Milan,ST=Milan,C=IT';
To solve the error:
ORA-01017: invalid
username/password; logon denied
instead of the global
authentication!!!!
Now the network configuration.
SERVER (same as document two of the
series):
In your listener.ora specify the port where to listen for the TPCS
protocol and the position of your wallet.
listener.ora
oracle@breousdbls02:/u01/app/oracle/product/10.1/db_1/network/admin>
cat listener.ora
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(ORACLE_HOME =
/u01/app/oracle/product/10.1/db_1)
(SID_NAME = UBANKP)
)
)
WALLET_LOCATION =
(SOURCE =
(METHOD = File)
(METHOD_DATA =
(DIRECTORY =
/opt/oracle/wallet/WALLETS/oracle/wallet-ubankp)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST =
breousdbls02.ras)(PORT = 1521))
)
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCPS)(HOST =
breousdbls02.ras)(PORT = 2484))
)
)
The sqlnet.ora also contains the wallet position and the crypto
parameters:
SQLNET.AUTHENTICATION_SERVICES= (TCPS, BEQ)
NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
SSL_CLIENT_AUTHENTICATION = TRUE
SSL_CIPHER_SUITES= (SSL_RSA_EXPORT_WITH_RC4_40_MD5)
SSL_VERSION = 0
wallet_location =
(SOURCE=
(METHOD=File)
(METHOD_DATA=
(DIRECTORY=/opt/oracle/wallet/WALLETS/oracle/wallet-ubankp)))
CLIENT:
The tnsnames.ora contains the entry for the SERVICE_NAME for the TPCS
protocol:
UBANKPSSL =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCPS)(HOST =
breousdbls02.ras)(PORT = 2484))
)
(CONNECT_DATA =
(SERVICE_NAME = UBANKP)
)
(SECURITY=
(SSL_SERVER_CERT_DN="CN=UBANKP,
OU=RAS, O=RAS, L=Milan, ST=Milan, C=IT")
)
)
SSL_SERVER_CERT_DN specify the DN used by the server
certificate.
The sqlnet.ora contains the wallet location and the crypto parameters
according to the server:
SQLNET.AUTHENTICATION_SERVICES= (BEQ, TCPS)
SSL_VERSION = 0
TRACE_LEVEL_CLIENT = SUPPORT
SSL_CLIENT_AUTHENTICATION = TRUE
SSL_SERVER_DN_MATCH = TRUE
SSL_CIPHER_SUITES= (SSL_RSA_EXPORT_WITH_RC4_40_MD5)
WALLET_LOCATION =
(SOURCE =
(METHOD = FILE)
(METHOD_DATA =
(DIRECTORY =
/home/oracle/wallet/WALLETS/oracle)
)
)
Now, from the client:
oracle@breoraasls02:/u01/app/oracle/product/10.1/ias_1/network/admin>
tnsping UBANKPSSL
TNS Ping Utility for Linux: Version 10.1.0.4.0 - Production on
23-DEC-2005 11:35:11
Copyright (c) 1997, 2003, Oracle. All rights reserved.
Used parameter files:
/u01/app/oracle/product/10.1/ias_1/network/admin/sqlnet.ora
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS =
(PROTOCOL = TCPS)(HOST = breousdbls02.ras)(PORT = 2484))) (CONNECT_DATA
= (SERVICE_NAME = UBANKP)) (SECURITY= (SSL_SERVER_CERT_DN=CN=UBANKP,
OU=RAS, O=RAS, L=Milan, ST=Milan, C=IT)))
OK (150 msec)
From here we need two configure the application server defining a data
source and a connection pool.
Import note: for the configuration
I'm using OCI (jdbc thick client) since I want to rely on my
configuration files in $ORACLE_HOME/network/admin.
A later document is going to issue
the configuration with thin client.
The configuration file is for the default OC4J called "home" is:
$ORACLE_HOME/j2ee/home/config/data-sources.xml
If your OC4J is called, for example MYOC4J, the file would be: $ORACLE_HOME/j2ee/MYOC4J/config/data-sources.xml
The list of the OC4J can be obtained from the AS web console or from
the command line:
$ORACLE_HOME/opmn/bin/opmnctl status
Where I define a new connection pool with:
</connection-pool>
<connection-pool name='Certificate connection pool'
max-connections='50' min-connections='5' >
<connection-factory
factory-class='oracle.jdbc.pool.OracleDataSource' user='' password=''
url='jdbc:oracle:oci:@UBANKPSSL'>
</connection-factory>
and the data source:
<managed-data-source user='' password=''
connection-pool-name='Certificate connection pool'
jndi-name='jdbc/OracleTESTSSL' name='test_conn' />
At the end my file will look like this:
<?xml version="1.0"?>
<data-sources xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:noNamespaceSchemaLocation='http://xmlns.oracle.com/oracleas/schema/data-sources-10_1.xsd'
schema-major-version='10' schema-minor-version='1'>
<managed-data-source connection-pool-name='Example
Connection Pool' jndi-name='jdbc/OracleDS' name='OracleDS' />
<managed-data-source user='' password=''
connection-pool-name='Certificate connection pool'
jndi-name='jdbc/OracleTESTSSL' name='test_conn' />
<connection-pool name='Example Connection Pool' >
<connection-factory
factory-class='oracle.jdbc.pool.OracleDataSource' user='scott'
password='tiger'
url='jdbc:oracle:thin:@//localhost:1521/oracle.regress.rdbms.dev.us.oracle.com'>
</connection-factory>
</connection-pool>
<connection-pool name='Certificate connection pool'
max-connections='50' min-connections='5' >
<connection-factory
factory-class='oracle.jdbc.pool.OracleDataSource' user='' password=''
url='jdbc:oracle:oci:@UBANKPSSL'>
</connection-factory>
</connection-pool>
</data-sources>
It can be done manually but because of my lazyness and the fear of
errors I relied on the Application server Administration
console for then editing the above file manually.
Start defining the connection pool.
I use the OCI driver so my URL is going to be jdbc:oracle:oci:@UBANKSSL
while my users will be the dummyuser.
This last user is used to configure the connection pool.
Then go into data-sources.xml and leave username and passwords blank.

Now define the datasource starting from the connection pool.
The username is just "/". No password is defined.

This is the result:

Now test the connection from the data source. Click on Test Connection.

The connection was a success.
No password has been submitted by the data source.

Now the real connection by certificates:
oracle@breoraasls02:/u01/app/oracle/product/10.1/ias_1/j2ee/home/config>
vi data-sources.xml
<?xml version="1.0"?>
<data-sources xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:noNamespaceSchemaLocation='http://xmlns.oracle.com/oracleas/schema/data-sources-10_1.xsd'
schema-major-version='10' schema-minor-version='1'>
<managed-data-source connection-pool-name='Example
Connection Pool' jndi-name='jdbc/OracleDS' name='OracleDS' />
<managed-data-source user='' password=''
connection-pool-name='Certificate connection pool'
jndi-name='jdbc/OracleTESTSSL' name='test_conn' />
<connection-pool name='Example Connection Pool' >
<connection-factory
factory-class='oracle.jdbc.pool.OracleDataSource' user='scott'
password='tiger'
url='jdbc:oracle:thin:@//localhost:1521/oracle.regress.rdbms.dev.us.oracle.com'>
</connection-factory>
</connection-pool>
<connection-pool name='Certificate connection pool' >
<connection-factory
factory-class='oracle.jdbc.pool.OracleDataSource' user='' password=''
url='jdbc:oracle:oci:@UBANKPSSL'>
</connection-factory>
</connection-pool>
</data-sources>
As you can see I deleted the username and passwords leaving them blank.
I test the connection and look into the database:
SQL> select username from V$session where username is not NULL;
USERNAME
------------------------------
TEST_CONN
DBSNMP
DBSNMP
SYS
My connection pool is authenticating with the certificate and the user
is the one associated with the certificate DN: TEST_CONN.
Another test:
SQL> alter user test_conn quota unlimited on users;
User altered.
SQL> create table test_conn .dummytable
(dummycol1 varchar2(20));
Table created.
SQL> insert into test_conn .dummytable
(dummycol1) values ('This is a
test');
1 row created.
SQL> commit;
Commit complete.
Now change the test performed by the data source from
select * from dual
to
select * from dummytable

Contact information:
fabrizio.magni _at_ gmail.com