Wednesday, July 2, 2025

Entra ID Client Credential Authentication Flow For Oracle Database Service Accounts

Entra ID is one of the new cloud native Oracle database authentication, authorization and user life cycle management architectures introduced in 2022.  In addition to authentication, authorization, and user life cycle management, this architecture also adds multi-factor authentication and unified password policy complexity with on premises Active Directory (AD) because most customers sync their users and groups with their Entra ID tenancy.

The main three Oracle Database authentication flows for Oracle database Entra ID integration include:
  • Interactive authentication flow for the humans connecting from devices that support pop-up browser
  • Device code authentication flow for humans connecting through jump hosts that do not support pop-up browser
  • Client credential authentication flow for service accounts
This blog post focuses on the client credential authentication flow to provide a simplified recipe for setting up Oracle database client service accounts with Entra ID integration.

The configuration encompasses configuration in each of the following three areas:
  • Entra ID
    • New app role in the target database
    • Service account app registration
    • Service account pre-shared credential
    • Add service account to target database allow app ingress rules
  • Database Server
    • Add service account
    • Apply grants to service account
  • Database Client
    • Create wallet with pre-shared credential
    • Add TNS entry for service account with AZURE_CREDENTIALS
In this example, lets assume that we are adding a service account for the Human Resources (HR) application.  The Entra ID App Role will be named app_hr.role.  The HR service account configuration in Entra ID will be named dbclient_service_hr.  The Oracle database server representation of this service account will be named app_hr.

Wednesday, June 25, 2025

Upgrade OUD 12cPS4 to OUD 14c

Oracle Unified Directory (OUD) 14c is now available and upgrading has never been easier.  The documentation for upgrade and migration are found at the following links:
From my experience, there are at least four viable upgrade paths, but the most will use one of the following first two options.  These options include:

I. Swing Migration
II. Upgrade In Place
III. Upgrade To New Middleware Home
IV. Sync New Topology

Each option is outlined below.  Before getting into the details, it is important to make clear that it is critical to pre-qualify the migration steps and qualification testing in lower non-production environments before attempting in production.

I. Swing Migration

This migration strategy expands the existing OUD 12cPS4 topology by adding new OUD 14c instances on new or existing infrastructure. The basic workflow looks like the following:

1. Setup new or existing hosts for the new OUD 14c instances

2. Install JDK 21 (or 17) and the OUD 14c software interactively or automated with with response files

2.1 Extract software

cd /opt/ods/poc/sw
tar -zxf /opt/ods/poc/bits/14c/jdk-21_linux-x64_bin.tar.gz
unzip -qo /opt/ods/poc/bits/14c/V1048203-01.zip
unzip -qo /opt/ods/poc/bits/14c/p37376076_141200_Generic.zip


2.2 Make response files for automated OUD 14c installation

cat  /opt/ods/poc/cfg/oraInventory.loc
inventory_loc=/opt/ods/poc/cfg/oraInventory
inst_group=opc

cat  /opt/ods/poc/cfg/oud14c-standalone.rsp
[ENGINE] 
Response File Version=1.0.0.0.0
[GENERIC]
DECLINE_AUTO_UPDATES=true
MOS_USERNAME=
MOS_PASSWORD=<SECURE VALUE>
AUTO_UPDATES_LOCATION=
SOFTWARE_UPDATES_PROXY_SERVER=
SOFTWARE_UPDATES_PROXY_PORT=
SOFTWARE_UPDATES_PROXY_USER=
SOFTWARE_UPDATES_PROXY_PASSWORD=<SECURE VALUE>
ORACLE_HOME=/opt/ods/poc/mw_oud14c
INSTALL_TYPE=Standalone Oracle Unified Directory Server (Managed independently of WebLogic server)


2.3 Install OUD 14c

export JAVA_HOME=/opt/ods/poc/sw/jdk-21.0.6
$JAVA_HOME/bin/java -jar  /opt/ods/poc/sw/fmw_14.1.2.1.0_oud.jar -silent -ignoreSysPrereqs -responseFile  /opt/ods/poc/cfg/oud14c-standalone.rsp -invPtrLoc /opt/ods/poc/cfg/oraInventory.loc


3 Setup OUD instance

export JAVA_HOME=/opt/ods/poc/sw/jdk-21.0.6
export ORACLE_HOME=/opt/ods/poc/mw_oud14c
/opt/ods/poc/mw_oud14c/oud/oud-setup --cli --integration no-integration --instancePath /opt/ods/poc/mw_oud14c/oud3/OUD --adminConnectorPort 3444 --ldapPort 3389 --ldapsPort 3636 --httpAdminConnectorPort 3555 --httpPort disabled --httpsPort 3443 --baseDN dc=example,dc=com --rootUserDN 'cn=Directory Manager' --addBaseEntry --enableStartTLS --useJavaKeystore /opt/ods/poc/cfg/certs/oud1.example.com/oud1.example.com.jks --keyStorePasswordFile /opt/ods/poc/cfg/certs/oud1.example.com/oud1.example.com.pin --certNickname server-cert --hostName oud1.example.com --noPropertiesFile


4. Apply desired configuration to the OUD 14c instance including custom schema, indexing, password policy, ... etc.

cd /opt/ods/poc/mw_oud14c/oud1/OUD/bin
./ldapmodify -Z -X -p 1444 -h oud3.example.com -D "cn=Directory Manager" -j /opt/ods/poc/cfg/...pw -c -f /opt/ods/poc/cfg/custom_schema.ldif
./dsconfig --batchFilePath /opt/ods/poc/cfg/custom_config.batch --hostName oud3.example.com --port 1444 --bindDN "cn=Directory Manager" --bindPasswordFile /opt/ods/poc/cfg/...pw  --trustAll --no-prompt --noPropertiesFile
./stop-ds
./start-ds


5.  Add the OUD 14c instance to the OUD 12c replication topology

cd /opt/ods/poc/mw_oud14c/oud3/OUD/bin
./dsreplication enable --secureReplication1 --secureReplication2 --host1 oud1.example.com --port1 1444 --bindDN1 'cn=Directory Manager' --bindPasswordFile1 /opt/ods/poc/cfg/...pw --bindPasswordFile2 /opt/ods/poc/cfg/...pw --replicationPort1 1989 --host2 oud3.example.com --port2 1444 --bindDN2 'cn=Directory Manager' --replicationPort2 1989 --baseDN dc=example,dc=com --adminUID admin --adminPasswordFile /opt/ods/poc/cfg/...pw --trustAll --noPropertiesFile --no-prompt


6. Initialize the OUD 14c instance with data

Initialization options include initialization over protocol, via binary backup restore, and LDIF file import.

6.1 Initialize over protocol
Initialize the OUD 14c instance on oud3.example.com from the the data of OUD 12cPS4 instance on oud1.example.com

cd /opt/ods/poc/mw_oud14c/oud3/OUD/bin
./dsreplication initialize --hostSource oud1.example.com --portSource 1444 --portProtocolSource auto-detect --hostDestination oud3.example.com --portDestination 1444 --portProtocolDestination auto-detect --baseDN dc=example,dc=com --adminUID admin --adminPasswordFile /opt/ods/poc/cfg/...pw --trustAll --no-prompt


6.2 Initialize from recent binary backup

6.2.1 If you don't already have a backup from an OUD 12cPS4 instance, create one with the backup command.

cd /opt/ods/poc/mw_oud12c/oud1/OUD/bin
./stop-ds
./backup -c -n userRoot --backupDirectory /opt/ods/poc/tmp/backup/userRoot
./start-ds


6.2.2 Copy the backup from the OUD 12cPS4 instance to the new OUD 14c instance

6.2.3 Restore the binary backup to the OUD 14c instance

cd /opt/ods/poc/mw_oud12c/oud1/OUD/bin
./stop-ds
./restore --backupDirectory /opt/ods/poc/tmp/backup/userRoot
./start-ds


6.3 Initialize from recent LDIF export

6.3.1 Export to LDIF file from OUD 12cPS4 instance

cd /opt/ods/poc/mw_oud12c/oud1/OUD/bin
./stop-ds
./export-ldif -c -n userRoot -l /opt/ods/poc/tmp/export.ldif
./start-ds

6.3.2 Copy the exported LDIF file to the OUD 14c host

6.3.3 Initialize the OUD 14c instance from the LDIF file

cd /opt/ods/poc/mw_oud12c/oud1/OUD/bin
./stop-ds
./import-ldif --skipDNValidation --skipSchemaValidation -c -n userRoot -l /opt/ods/poc/tmp/export.ldif
./start-ds

7. Rinse and repeat steps 1-5 until the desired number of OUD 14c instances have been deployed

8. Satisfy functional and performance qualifiers applying client load

9. Introduce load to the OUD 14c instances by either adding the OUD 14c instances to an existing network load balancer virtual IP address (VIP) or setup a new VIP and iterative migrate applications to the new VIP until no more client load exists on the previous VIP.

Important Note: At this point that if you have any issues at all, your rollback strategy is revert the network load balancer VIPs to their previous state where all load goes to OUD 12cPS4 instances.

10. Once all applications are transitioned to OUD 14c, then remove the OUD 12cPS4 instances from the load balancing infrastructure if necessary.  If you had transitioned all instances to the new VIP, you could transition the old DNS name to the new VIP so that if any straggler apps try to use the old name, they will get routed to the proper VIP.

11. The last step is to deinstall the OUD 12cPS4 instances using the OUD deinstall script so that each OUD 12cPS4 instance is properly removed from the OUD replication topology.  Then, once all of the OUD 12cPS4 instances have been deinstalled and cleanly removed from the OUD topology, you can decommission the OUD 12cPS4 infrastructure. 

II. Upgrade In Place

With this migration strategy, you upgrade existing OUD 12c instances in place in the existing middleware home directory. The basic workflow looks like the following:

1. Stop and backup the existing OUD 12cPS4 instance(s)

Important Note: This backup strategy presumes that the backend data and logs reside within the OUD instance directory path.

/opt/ods/poc/mw_oud12c/oud1/OUD/bin/stop-ds
cd /opt/ods/poc/mw_oud12c
tar -czf /opt/ods/poc/oud1.tgz oud1


2. Backup the OUD 12cPS4 middleware home

cd /opt/ods/poc
tar -czf /opt/ods/poc/mw_oud12c.tgz --exclude oud1 mw_oud12c


3. Deinstall the OUD 12cPS4 middleware home

cd /opt/ods/poc/mw_oud12c
./oui/bin/deinstall.sh -silent -distributionName 'Oracle Unified Directory'
rm -fr 
/opt/ods/poc/mw_oud12c


4. Extract JDK 21 (or 17) and OUD 14c

cd /opt/ods/poc/sw
tar -zxf /opt/ods/poc/bits/14c/jdk-21_linux-x64_bin.tar.gz
unzip -qo /opt/ods/poc/bits/14c/V1048203-01.zip
unzip -qo /opt/ods/poc/bits/14c/p37376076_141200_Generic.zip


5.1 Make response files for automated OUD 14c installation

cat  /opt/ods/poc/cfg/oraInventory.loc
inventory_loc=/opt/ods/poc/cfg/oraInventory
inst_group=opc

cat  /opt/ods/poc/cfg/oud14c-standalone.rsp
[ENGINE] 
Response File Version=1.0.0.0.0
[GENERIC]
DECLINE_AUTO_UPDATES=true
MOS_USERNAME=
MOS_PASSWORD=<SECURE VALUE>
AUTO_UPDATES_LOCATION=
SOFTWARE_UPDATES_PROXY_SERVER=
SOFTWARE_UPDATES_PROXY_PORT=
SOFTWARE_UPDATES_PROXY_USER=
SOFTWARE_UPDATES_PROXY_PASSWORD=<SECURE VALUE>
ORACLE_HOME=/opt/ods/poc/mw_oud12c
INSTALL_TYPE=Standalone Oracle Unified Directory Server (Managed independently of WebLogic server)


5.2 Install OUD 14c

export JAVA_HOME=/opt/ods/poc/sw/jdk-21.0.6
$JAVA_HOME/bin/java -jar  /opt/ods/poc/sw/fmw_14.1.2.1.0_oud.jar -silent -ignoreSysPrereqs -responseFile  /opt/ods/poc/cfg/oud14c-standalone.rsp -invPtrLoc /opt/ods/poc/cfg/oraInventory.loc


5.3 Apply patch(es) to OUD 14c

Important Note: Patch 37376076 is not required.  It is just provided for illustrative purposes.

export JAVA_HOME=/opt/ods/poc/sw/jdk-21.0.6
export ORACLE_HOME=/opt/ods/poc/mw_oud12c
cd /opt/ods/poc/sw/37376076
$ORACLE_HOME/OPatch/opatch apply


6. Restore the OUD 12cPS4 instance(s)

cd /opt/ods/poc/mw_oud12c
tar -xzf /opt/ods/poc/oud1.tgz


7. Upgrade the OUD 14c instance scripts to reflect the new JDK path

cd /opt/ods/poc/mw_oud12c
./oud/bin/upgrade-oud-instances --instancePath /opt/ods/poc/mw_oud12c/oud1


8. Upgrade the OUD 14c instance(s)

/opt/ods/poc/mw_oud12c/oud1/OUD/bin/start-ds --upgrade


9. Start the OUD 14c instance(s)

/opt/ods/poc/mw_oud12c/oud1/OUD/bin/start-ds


That completes the demonstration of an in place migration of an OUD instance from OUD 12cPS4 to OUD 14c.

III. Upgrade To New Middleware Home

With this migration strategy, you transition existing OUD 12c instances to a new middleware home (e.g. mw_oud14c) from the existing middleware home directory (e.g. mw_oud12c).  The only benefit of this method is that it may streamline rollback if necessary.  Most customers will either migrate in place or swing to new OUD 14c instances on new infrastructure.  The workflow of this upgrade method is identical to the in place upgrade except using a new middleware home (e.g. mw_oud14c) instead of the existing middleware home (e.g. mw_oud12c).

IV. Sync New Topology

With this migration strategy, you setup a complete independent OUD 14c topology, setup and OUD 14c Directory Integration Platform (DIP) instance, configure bi-directional DIP sync profiles between the one of the OUD 12cPS4 instances and one of the OUD 14c instances to sync data between the OUD 12cPS4 and OUD 14c replication topologies. The work flow is similar to the swing migration with regards to load balancer configuration and rollback methodology.  Once the migration is complete, in addition to de-commissioning the OUD 12cPS4 infrastructure, you de-commission the DIP instance as well.  A detailed example of this migration flow is beyond the scope of this blog post because most customers will use one of the first two approaches. 

I hope that you found this helpful.

Brad

Wednesday, May 28, 2025

TLS for Oracle Real Application Cluster (RAC)

In recent months, I've helped many customers understand Oracle's two new cloud native architectures for centralizing authentication including multi-factor, authorization, and user life cycle management of Oracle database users.  These two new architectures enable integration with identity providers Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) and Microsoft's Entra ID.

The interactive SAML flow of this architecture outsources authentication to the identity provider by popping up a browser to the identity provider.  Once the authentication browser with the identity provider is complete, an authorization code is returned to the database client. The client then securely sends the access token to the database server over a TLS encrypted connection between the database client and database server.  Finally, the database confirms the validity of the access token from the public key that it retrieves from the identity provider.  The following diagram illustrates this interactive flow with Entra ID.


The configuration options for the TLS configuration for a standalone database is covered in the following previous blog posts:


Oracle Real Application Cluster (RAC) database system is quite a bit more sophisticated and has unique needs where TLS is concerned compared to a standalone database instance. The RAC cluster is composed of 2 or more hosts (nodes) configured for high availability including built in load distribution through the Single Client Access Name (SCAN) listener.  




When a database client connects to the RAC cluster through SCAN listener, the SCAN listener re-directs the client to the local listener specified by LOCAL_LISTENER of the RAC node to which he database client is then connected.  The LOCAL_LISTENER is managed by RAC to take into consideration fail-overs and fall-backs which is most easily accomplished by using IP addresses rather than host names.

Given that the client connects via TLS to both the SCAN listener hostname and then to the IP address of the RAC node, the certificate(s) will need to either use a single host cert for all of the RAC nodes and SCAN listener, or a Subject Alternative Name (SAN) certificate that includes the SCAN listener name and all possible RAC node names and the RAC node IP addresses or use a wildcard certificate.

Most customers avoid wildcard certificates like the plague because it of the security risk that it represents by not having unique certificates per host.  Therefore, we will distill the RAC certificate options down to the following three options.

Option 1: Single Host Certificate
This option is possible because the database client can validate the certificate by the SSL_SERVER_CERT_DN alone rather than matching the host value to the CN value of the certificate subject or one of the certificate Subject Alternative Name (SAN) entries.  Let's consider the following TNS entry:

Let's start with looking up the certificate subject from database server with orapki:

$ orapki wallet display -complete  -wallet $WALLET_ROOT/tls  -pwd Oracle123|egrep "Certificates:|Subject:"
Requested Certificates: 
User Certificates:
Subject:        C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
Trusted Certificates: 
Subject:        CN=Certificate Authority,O=Company,L=Austin,ST=Texas,C=US


Alternatively, you can retrieve the certificate subject with openssl form a UNIX/Linux host:

echo | openssl s_client -connect scan.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com

The client TNS entry would look like the following where key TLS properties are highlighted in blue and the SSL_SERVER_CERT_DN is set to the exact subject DN of the certificate.

PDB1 = 
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=
TCPS)(HOST=scan.myco.com)(PORT=2484))
    )
    (SECURITY=
      (SSL_SERVER_DN_MATCH=TRUE)
      (SSL_SERVER_CERT_DN="C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com")
      (WALLET_LOCATION=SYSTEM)

      (TOKEN_AUTH=AZURE_INTERACTIVE)
      (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
      (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
      (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)
    )
    (CONNECT_DATA=
      (SERVICE_NAME=pdb1)
    )
  )



Option 2: Single SAN Certificate
The single Subject Alternative Name (SAN) certificate is slightly more secure because you incorporate all of the possible names and IP address of the RAC cluster into the SAN entries of a single certificate where the subject of the certificate includes the SCAN listener host name for it's canonical name (CN) value.

Let's start with looking up the certificate subject from database server with orapki:

$ orapki wallet display -complete  -wallet $WALLET_ROOT/tls  -pwd Oracle123|egrep "Certificates:|Subject:"
Requested Certificates: 
User Certificates:
Subject:        C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
Trusted Certificates: 
Subject:        CN=Certificate Authority,O=Company,L=Austin,ST=Texas,C=US


Alternatively, you can retrieve the certificate subject and SAN entries with openssl form a UNIX/Linux host:

echo | openssl s_client -connect scan.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Alternative|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
            X509v3 Subject Alternative Name: 
                DNS:node1.myco.com, DNS:node2.myco.com, DNS: node1, DNS: node2 IP: 10.0.0.10, IP 10.0.0.20

Note in the above openssl output, that the DNS and IP SAN entries are listed as well and that they include the fully qualified host names, unqualified host names and IP addresses of the RAC nodes.  This is important because clients can sometimes connect directly to a RAC node rather than through the SCAN listener. In this case, you wan the certificate to find a match in the SAN entries to complete the TLS connection.

The client TNS entry would look like the following where key TLS properties are highlighted in blue and the SSL_SERVER_CERT_DN is not present because the DN matching is just looking to find a match of ADDRESS HOST value with the CN value of the certificate subject name or any of the SAN entries.

PDB1 = 
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS=(PROTOCOL=
TCPS)(HOST=scan.myco.com)(PORT=2484))
    )
    (SECURITY=
      (SSL_SERVER_DN_MATCH=TRUE)
      (WALLET_LOCATION=SYSTEM)
      (TOKEN_AUTH=AZURE_INTERACTIVE)
      (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
      (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
      (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)
    )
    (CONNECT_DATA=
      (SERVICE_NAME=pdb1)
    )
  )




Option 3: Individual SAN Certificates Per RAC Node
The individual SAN certificate is again more secure because you specify a host-specific set of SAN entries for that host's names and IP address.

Let's start with looking up the certificate subject and SAN entries from the first RAC node with openssl from a UNIX/Linux host:

echo | openssl s_client -connect node1.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Alternative|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
            X509v3 Subject Alternative Name: 
                DNS:node1.myco.com, DNS: node1, IP: 10.0.0.10

Next, lets lookup the certificate subject and SAN entries from the second RAC node with openssl from a UNIX/Linux host:

echo | openssl s_client -connect node1.myco.com:2484 2>&1 | openssl x509 -noout -text | egrep "DNS:|IP:|Alternative|Subject:"
        Subject: C=US,ST=Texas,L=Austin,O=MyCo,CN=scan.myco.com
            X509v3 Subject Alternative Name: 
                DNS:node2.myco.com, DNS: node2, IP: 10.0.0.20

Note in the above openssl output, that the DNS and IP SAN entries are listed as well and that they include the fully qualified host names, unqualified host names and IP addresses of the just the local RAC node rather than all RAC nodes.

A similar RAC node specific certificate would be created and installed on each respective RAC node and respective listener.

The client TNS entry would be the same as the Option 2 because the difference in the two options is the contents of the certificate.

If you encounter issues with any of these configurations or EntraID integration, check out my blog posts on troubleshooting these areas:

Those are the three certificate options for RAC clusters.

I hope you found this information useful.

Blessings!

Brad

Oracle Net Service Name Resolution Options

Oracle database name resolution is provided by Oracle Net Services.  Oracle Net Services connect string (a.k.a. connect descriptor) resolution is to Oracle database clients what Domain Name Services (DNS) is to TCP/IP clients for host name to IP address resolution. For example, with DNS a TCP/IP client would resolve a hostname like hrdb.dbauthdemo.com to an IP address like 10.10.0.1.  In the same way, an Oracle database client would resolve through Oracle Net services a service name alias like pdb1 to a connect string like the following:

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hrdb.dbauthdemo.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1)))

In the above sample connect string, the pdb1 service name resolves to a connect string for enabling a database client to connect to the pdb1 service name via TCP to host hrdb.dbauthdemo.com on port 1521.

As customers expand their Oracle database estate and transition Oracle databases from on premises to one or more  clouds and strengthen their security posture through enabling TLS encryption or enabling multi-factor authentication, the number and complexity of connect strings will increase dramatically over time.  Therefore, it is important to ensure accurate and up-to-date name resolution through centralizing Oracle database server name resolution.

Net Service Name Resolution Options

The most common net service naming resolution configuration approaches include the following.

1. Independent Client Configs

Every database client independently specifies a connect string or maintains name service entry it's own  local tnsnames.ora file.  Using previous example, here is a sample connect string for the service name alias pdb1:

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hrdb.dbauthdemo.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1))) 

Here is an equivalent net service connect descriptor entry from a tnsnames.ora file: 

PDB1 = 
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCP)(HOST=
hrdb.dbauthdemo.com)(PORT=1521))
    (CONNECT_DATA=
      (SERVICE_NAME=
 pdb1)
    )
  )



2. Unified tnsnames.ora File

With this option, the database administrative team creates and maintains a single tnsnames.ora file that is either published for internal reference or distributed to all database clients.  This method is better than independently managed connect strings and tnsnames.ora files but is also fraught with possible data inconsistency over time because the clients don't necessarily have to refresh their tnsnames.ora files with the most current version. There can also be security concerns with method used to propagate the tnsnames.ora file to database clients.



3. Centralized Directory Naming

This is one of the most common options employed by customers with a large number of database servers and clients that need to be kept up-to-date.  In this solution, you setup one or more LDAP-based directory service instances according to your high availability requirements and load the directory service with your TNS entries using either dbca tool that comes with the Oracle database or create your own custom TNS entries.

The main directory service products employed for this architecture include Oracle Unified Directory (OUD) and Oracle Internet Directory (OID) though others could be used as well.  One important note on directory server product selection is that Active Directory (AD) can technically be used for this purpose but Microsoft strongly discourages extending AD schema or loading non-Microsoft data in AD because it can put AD upgrades at risk.  I've worked with hundreds of customers on this use case and I've yet to meet a single large customer that allows this data to be loaded into their production AD service.

 Regarding high availability, the recommended maximum high availability architecture includes use local and geographic load balancers that support proper LDAP service tests.  From a security perspective, note that exclusive use of encrypted LDAPS connections is accomplished by not including non-encrypted port in the DIRECTORY_SERVERS ldap.ora.  Further, authenticated lookups is available as well using additional properties for basic authentication are supported for LDAP-based name resolution as well.

An example configuration using OUD 12cPS4 is covered at the following blog post:https://www.braddiggs.com/2023/10/oud-12cps4-use-case-oracle-database.html


The equivalent net service connect descriptor entry for the pdb1 alias from a directory services looks like the following: 

dn: cn=pdb1,cn=OracleContext,dc=hrdb.dbauthdemo,dc=com
objectclass: orclApplicationEntity
objectclass: orclDBServer_92
objectclass: orclService
objectclass: orclDBServer
objectclass: top
orclNetDescString: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hrdb.dbauthdemo.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=pdb1))

 

4. Centralized Configuration Provider [New with 23ai] 

This is a new option was introduced with Oracle database version 23ai that enables connect descriptors to be loaded into HTTPS based object storage in JSON format. 

 There are several restrictions namely that it only works with 23ai and newer version clients and that the WALLET_LOCATION only supports SYSTEM.  Only supporting SYSTEM for the WALLET_LOCATION means that all certificates must be signed by a public certificate authority or your private certificate authority chain must be loaded into the host trust store where the database client is run.  This new feature along with the full set of restrictions is covered at the following link: https://docs.oracle.com/en/database/oracle/oracle-database/23/netrf/centralized-configuration-provider-naming-parameters.html 


The equivalent net service connect descriptor entry of the pdb1 alias in JSON format for centralized configuration provider looks like the following: 

{
 "connect_descriptor": "(DESCRIPTION=
                           (ADDRESS=
                              (PROTOCOL=TCP)
                              (HOST=hrdb.dbauthdemo.com)
                              (PORT=1521))
                           (CONNECT_DATA=
                              (SERVICE_NAME=pdb1))
                        )"
}

A JDBC reference to the above entry might look like:

jdbc:oracle:thin:@config-https://objectstorage.us-phoenix-1.oraclecloud.com/n/orasenatdpltintegration03/b/azure/o/pdb1.json


A more robust list of examples of the available configuration providers are available at the following blog post: https://blogs.oracle.com/developers/post/jdbc-config-providers

I hope you find this information helpful.

Blessings!

Braed

Wednesday, May 7, 2025

Entra ID Integration for TOAD

Shout out to Jason Gay for figuring out and sharing the TOAD configuration for adding an Entra ID enabled Oracle database.

The Tools for Oracle Database Administration and Development (TOAD) application is a frequently used SQL tool used by developers and database administrators for browsing and managing Oracle database data.  TOAD appears to leverage the Oracle Call Interface (OCI) libraries included with the Oracle full and instant database clients.  These are the same libraries leveraged by the very popular SQL*Plus command line tool that is includes with the Oracle database client.

To add an Entra ID integration enabled Oracle database to TOAD, us the following configuration parameters:

User: EXTERNAL
TNS: Select database alias from pull-down
Connect as: Normal
Connect using Oracle Client: <ODB 23.5+ full or instant client>
Check: Use this client by default

Here is a screen shot of what it looks like filled out except the selection of the database alias from the tnsnames.ora file.



I hope you found this post helpful and informative.

Blessings!

Brad

Wednesday, April 23, 2025

ODB Entra ID Integration Troubleshooting Guide

I've spent several weeks working through a wide variety of Oracle database integration use cases with Entra ID for the express purpose of methodically deriving all possible error codes that that a customer might encounter during an evaluation.  I will list each error followed by the one or more potential causes.

Before getting started with the errors, know that you can enable client and server side tracing to reveal underlying root causes of errors.

Client-side Trace for SQL*Plus
Either add the following to sqlnet.ora or set as environment variables the following before attempting to connect to the database server:
EVENT_25701=15
EVENT_25703=15
Note that 15 is for high level tracing and 14 for low level tracing.

Database Server Side Trace for non-autonomous databases
Set the following in the CDB:
SQL> ALTER SYSTEM SET EVENTS 'TRACE[TOKEN] DISK=HIGHEST'; 

Database Server Side Trace for autonomous databases
Review the alert log.  For example:
SQL> SELECT FROM V$DIAG_ALERT_EXT ORDER BY originating_timestamp desc;
SQL> SELECT * FROM UNIFIED audit_trail ORDER BY event_timestamp desc fetch first 100 rows only;
SQL> CREATE AUDIT POLICY ORA LOGON_SUCCESSES ACTIONS LOGON;
SQL> AUDIT POLICY ORA_LOGON_SUCCESSES WHENEVER SUCCESSFUL;

Error Number Documentation
Note that most errors provide additional help at the documentation page for the respective error code.
For example : https://docs.oracle.com/error-help/db/ora-<number>

Database Name Resolution
Database name resolution is typically provided by the explicit connect string, exclusively tnsnames.ora for JDBC-thin driver clients, a combination of sqlnet.ora and tnsnames.ora for JDBC-thick and OCI (C-based) client drivers, or LDAP-based name services.  Information on LDAP-based database name services are available at the following blog post: https://www.braddiggs.com/2023/10/oud-12cps4-use-case-oracle-database.html

Best Practice: Regardless of the name resolution repository, the best practice is to include all elements of connection in either the explicit connect string or TNS entry.

Here is a human friendly formatted TNS entry for database PDB1. The blue font items are required for the encrypted TCPS TLS connection. TLS connections between client and server are required for Entra ID integration.  The red font items are unique to Entra ID connections.

PDB1 = 
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCPS)(HOST=hrdb.dbauthdemo.com)(PORT=2484))
    (SECURITY=
      (SSL_SERVER_DN_MATCH=TRUE)
      (WALLET_LOCATION=SYSTEM)
      (TOKEN_AUTH=AZURE_INTERACTIVE)
      (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
      (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
      (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)
    )
    (CONNECT_DATA=
      (SERVER=DEDICATED)
      (SERVICE_NAME=pdb1)
    )
  )

Here is the equivalent explicit connect string being called with the connect SQL command:

SQL> connect (DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=hrdb.dbauthdemo.com)(PORT=2484))(SECURITY=(SSL_SERVER_DN_MATCH=TRUE)(WALLET_LOCATION=SYSTEM)(TOKEN_AUTH=AZURE_INTERACTIVE)(TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)(CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)(AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb1)))


Error Messages:

Here are the list of errors that I've encountered while troubleshooting Entra ID integration issues.

Error: ORA-01017: invalid username/password; logon denied
Potential reasons for this error:
  • Invalid username or password provided
  • The server side configuration of the target database of the client connection (CDB or PDB) may not yet be configured for Entra Integration including setting IDENTITY_PROVIDER_TYPE to AZURE_ID and applying Entra ID integration to IDENTITY_PROVIDER_CONFIG
  • The connection string or TNS entry of the client may not include all requisites for Entra ID integrated database
  • Use the following to determine if IDENTITY_PROVIDER_TYPE is set to AZURE_ID:

SQL> SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME='identity_provider_type';

  • Use the following to determine if IDENTITY_PROVIDER_CONFIG has the correct values for tenant_id, application_id_uri (e.g. database app URI), and app_id (e.g. database app registration's application ID).

SQL> SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME='identity_provider_config';

Error: ORA-12154: Cannot connect to database. Cannot find alias <db> in
<dir>\tnsnames.ora.
Potential reasons for this error:
  • The tnsnames.ora file does not exist in <odb_client_base>\network\admin or that the specified database does. Note that you can specify TNS_ADMIN=\<path> to specify the folder path to the tnsnames.ora file
  • The requested database does not exist in the tnsnames.ora file.

Error: ORA-12170: Cannot connect. - timeout of -s for host <ip_address> port <secure_port>.
(CONNECTION_ID=<connection_id>)
Potential reasons for this error:
  • The SQL*Plus command cannot connect to the host specified in the TNS or connect string entry
  • Check network firewall or host-based firewall ingress rules allow the host of the database client to connect to the host of the database server
  • Check the network firewall or host-based firewall egress rules do not allow the database client or server to connect to the database server's host


ORA-12541: Cannot connect. No listener at host <ip> port <port>
Potential reasons for this error:
  • Oracle database listener is not running or ingress firewall rules (network or host-based) are blocking access to the database port.

Error: ORA-12545: Connect failed because target host or object does not exist
Potential reasons for this error:
  • Can’t lookup specified connect string. Check name service resolution in tnsnames.ora or directory service
  • Make sure TNS_ADMIN is set to the directory where tnsnames.ora exists
  • You get the following Microsoft Entra ID error when you specify an invalid client ID.

    Error: ORA-12547: TNS:lost contact
    Potential reasons for this error:
    • Occurs if you specify PROTOCOL of TCP instead of TCPS in connect string or TNS entry

    Error: ORA-12514: Cannot connect to database. Service <service_name> is not registered with the
    listener at host <hostname_or_ip_address> port <tcps_tls_port>
    (CONNECTION_ID=Kittn+/2RPGXnZPxZAV9Hw==)
    Potential reasons for this error:
    • Occurs when incorrect SERVICE_NAME value is specified in connect string or TNS entry

      Error: ORA-18726: Failed to get a value from an OracleResourceProvider: No implementation of oracle.jdbc.spi.AccessTokenProvider with name: "ojdbc-provider-azure-token" can be located. Implementations of oracle.jdbc.spi.AccessTokenProvider that can be located have the following names : []
      Potential reasons for this error:
      • In the case of SQLDeveloper, this can occur if the SQLDeveloper product.conf configuration file does not have all of the requisite OJDBC extension libraries required for Entra ID integration. See this blog post (https://www.braddiggs.com/2025/04/entra-id-integration-for-sqldeveloper.html) for details on how to configure SQLDeveloper for EntraID integration
      • This can result from using a version of the SQL*Plus client earlier than 23.7.
      • Note that if the connect string or TNS entry specifies TOKEN_AUTH=AZURE_DEVICE_CODE , this may indicate that AZURE_DEVICE_CODE is not yet supported
      Here is the equivalent Entra ID error when logging in with SQLcl 25.1:
      To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code ARSX62NBJ to authenticate.
      2025-04-16 09:20:46.198 SEVERE com.azure.core.util.logging.ClientLogger performDeferredLogging Azure Identity => ERROR in getToken() call for scopes [https://dbauthdemo.com/89746215-ea34-4a83-ac0e-46a68de97935/.default]: Failed to acquire token with device code.
      Connection failed
        USER          =
        URL           = jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=hrdb.dbauthdemo.com)(PORT=2484))(SECURITY=(SSL_SERVER_DN_MATCH=TRUE)(WALLET_LOCATION=SYSTEM)(TOKEN_AUTH=AZURE_INTERACTIVE)(TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)(CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)(AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb1)))


      Error: ORA-18951: NL exception was generated: TNS-04610: No literals left, reached end of NV pair
      Potential reasons for this error:
      • Occurs when attempting to connect via thin client with TOKEN_AUTH=AZURE_DEVICE_CODE and the previous authentication was successful but failed to get token (Error: ORA-18726)

      Error: ORA-25704: Token-based authentication requires client parameter SSL_SERVER_DN_MATCH=TRUE.
      Potential reasons for this error:
      • All Entra ID integration connections between Oracle database client require encrypted TLS connection with SSL_SERVER_DN_MATCH=TRUE

      Error: ORA-25707: The token is invalid
      Potential reasons for this error:
      • If using file-based access token acquisition and refreshing, the token is not present, invalid or expired
      • If using memory-based access token acquisition and refreshing, the token may not have been passed because of an issue with TLS configuration setup between the database client and database server.
      • Use client and server side tracing to ascertain root cause. 

          Error: ORA-25714: invalid value of PASSWORD_AUTH or TOKEN_AUTH in the client configuration
          Potential reasons for this error:
          • OCI driver (e.g. sqlplus) or JDBC-thick driver version used is not supported. SQL*Plus 19.18 or newer is required
          • JDBC-thin driver appears to only work with 23.7 or newer

          Error: ORA-25718: Invalid value of CLIENT_ID in the client configuration
          Potential reasons for this error:
          • Occurs when CLIENT_ID is invalid format or bad value in connect string or TNS entry
          You may also see Entra ID Error message AADSTS90016:





          Error: ORA-25719: Invalid value of TENANT_ID in the client configuration
          Potential reasons for this error:
          • Occurs if the TENANT_ID is incomplete or invalid format in the connect string or TNS entry

          Error: ORA-25726: Invalid value of AZURE_CREDENTIALS in the client configuration
          Potential reasons for this error:
          • Occurs when no client credentials have been entered for TOKEN_AUTH=AZURE_SERVICE_PRINCIPAL

          Error: ORA-25724: Azure AD authentication timeout and Vendor Code: 25724
          Potential reasons for this error:
          • Occurs when pop-up browser connection to https://login.microsoftonline.com times out after 60 seconds
          • Test connection multiple times from your computer to Microsoft login with:
            • Linux: curl -ksL https://login.microsoftonline.com/
            • Windows Powershell: Invoke-WebRequest -Uri https://login.microsoftonline.com
          • Note that web connection test may require going through a web proxy if direct outbound connections are not permitted
          • If connection is successful some of the time, there may be a routing or firewall issue between your computer and Microsoft's login page
          • If connection fails every time, there is likely either a firewall constraint, routing issue or Microsoft login may be temporarily down
          • In Microsoft Terminal Services environments like Microsoft RDP or Citrix, the ODB client redirect to localhost (127.0.0.1) may not be connecting to the user's session real localhost (127.0.0.2-n).  The respective terminal services solution will need to be configured to connect the two for the requesting client application.  In this case determine what port that the web browser used to connect to localhost after successful EntraID authentication (typically localhost:8400 but can be other number) and then use (netstat -ano | findstr "<port>") to find the process that is trying to connect to that port. Note that both the web browser (Edge or Internet Explorer by default in Windows Server depending on version) and the identified process will need to be added to the Windows or Citrix policy for connecting the virtual localhost (127.0.0.1) and real user session localhost (127.0.0.n).  Here is a screenshot from the Citrix policy:



            Error: ORA-28547: connection to server failed, probable Oracle Net admin error
            Potential reasons for this error:
            • Combination ORA and Entra ID Error message AADSTS90002:

            or Entra ID Error message AADSTS700016:



              • This error occurs if you have not specified the correct TENANT_ID in the connect string or TNS entry
              • Entra ID authentication attempt either timed out or failed to authenticate properly
              • Occurs when incorrect CLIENT_ID value is specified in connect string or TNS entry

              Error: ORA-28759: failure to open file
              Potential reasons for this error:
              • WALLET_LOCATION of the connect string or TNS entry has specified a wallet path for which no wallet exists

                Error: ORA-28864: SSL connection closed gracefully
                Potential reasons for this error:
                • If you’ve specified the non-secure port number (Default: 1521) instead of the secure port number (Default: 2484) in the connect string or TNS entry
                • Note that the default autonomous database uses port 1521 for secure port

                Error: ORA-28865: SSL connection closed
                Potential reasons for this error:
                • The database server may have not yet set the wallet_root directory
                • Check to make sure that the wallet has been copied to the PDB GUID directory ($WALLET_ROOT/$pdbguid/tls) on the database server
                Set the database server wallet with:

                sqlplus / as sysdba
                SQL> alter system set wallet_root='/u01/app/oracle/19c/wallet_root' scope=spfile;
                SQL> shutdown immediate;
                SQL> quit;
                lsnrctl stop
                lsnrctl stop
                sqlplus / as sysdba
                SQL> startup;
                SQL> alter pluggable database all open;
                SQL> alter system register;
                SQL> quit;




                Error: ORA-29003: SSL transport detected mismatched server certificate.
                Potential reasons for this error:
                • Occurs the SSL_SERVER_CERT_DN value of the connect string or TNS entry does not match the certificate subject or subject alternative name (SAN) entries of the certificate
                • You can use the openssl command of a Linux host to ascertain the certificate and SAN entries of the database server with:

                $ echo | openssl s_client -connect hrdb.dbauthdemo.com:2484 2>&1 | openssl x509 -noout -text | egrep -i "DNS|subject"
                        Subject: CN=hrdb.dbauthdemo.com
                        Subject Public Key Info:
                            X509v3 Subject Alternative Name: 
                                DNS:hrdb.dbauthdemo.com, DNS:www.hrdb.dbauthdemo.com
                            X509v3 Subject Key Identifier:



                Error: ORA-29024: Certificate validation failure
                Potential reasons for this error:
                • This error can be caused by the signing certificate authority not being present in the client host certificate authority trust store
                • Use orapki on the database host to display the trusted certificate subject and confirm that this trusted certificate is in the client host
                  • orapki wallet display -complete  -wallet $WALLET_ROOT/tls  -pwd <wallet_password>
                • In Windows client, run mmc, add “Certificates” snap-in, look up “Trusted Root Certification Authorities” to see if the DN o the certificate authority matches the subject of the same certificate authority from orapki display
                • In Linux, return all of the CA certificate subjects with: openssl crl2pkcs7 -nocrl -certfile /etc/pki/tls/certs/ca-bundle.trust.crt | openssl pkcs7 -print_certs -noout

                  Error: AADSTS90009: Application '...'(...) is requesting a token for itself. This scenario is supported only if resource is specified using the GUID based App Identifier.
                  Potential reasons for this error:
                  • This error is caused by specifying the database server's web Application (client) ID for the value of the CLIENT_ID of the connect string or TNS entry. Here is a sample screenshot of this error.