Categories
ldap security

Connect to ActiveDirectory with ldapsearch on Unix

In ancient times, ldapsearch could query ActiveDirectory without issues. In this examples, I used openldap client 2.4. Other tools may have other parameters.

$ ldapsearch -H ldap://example.com:389 -b dc=example,dc=com cn="Laurent C. Schneider" mail
mail: laurent.c.schneider@example.com

In Active Directory (AD) it is no longer the default since Windows Server 2003, unless you change dSHeuristics to 0000002 to allow anonymous access. Not recommended.
Anonymous LDAP operations

In normal case you’ll get :

$ ldapsearch -H ldap://example.com:389 -b dc=example,dc=com cn="Laurent C. Schneider" mail
ldap_search: Operations error
ldap_search: additional info: 000004DC: LdapErr: DSID-0C0907C2, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v2580
0 matches

Another widely used, simple, not recommended method is to use simple bind over ldap:389.

$ ldapsearch -H ldap://example.com:389 -D user001@example.com -w secretpassword -b dc=example,dc=com cn="Laurent C. Schneider" mail
mail: laurent.c.schneider@example.com

It authenticates your user, but it send the password in clear text over the network. Therefore, if you use simple bind, use ldaps too. Microsoft announced an upcoming Windows update in early 2020 that will prevent simple bind in clear text
ADV190023

So for sure, you should prefer SSL. You probably need or already have your pki root-ca’s installed. If you use OpenLdap, the TLS_CACERT is defined in /etc/openldap/ldap.conf.

$ grep TLS_CACERT /etc/openldap/ldap.conf
TLS_CACERTDIR /etc/pki/tls/certs
$ ldapsearch -H ldaps://example.com:636 -D user001@example.com -w secretpassword -b dc=example,dc=com cn="Laurent C. Schneider" mail
mail: laurent.c.schneider@example.com

That should be good enough to survive early 2020…

But, maybe you don’t like to put your password in a script at all.

One could use Kerberos.

$ kinit
Password for user001@EXAMPLE.COM: 
$ klist
Ticket cache: FILE:/tmp/krb5cc_001
Default principal: user001@EXAMPLE.COM

Valid starting     Expires            Service principal
11/13/19 12:11:44  11/13/19 22:11:49  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 11/20/19 12:11:44
$ ldapsearch -Y GSSAPI  -H ldap://example.com:389 -b dc=example,dc=com cn="Laurent C. Schneider" mail
SASL/GSSAPI authentication started
SASL username: user001@EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
mail: laurent.c.schneider@example.com

A list of supported mechanism can be retrieved with the -s base option

$ ldapsearch -s base -H ldap://example.com:389  -D user001@example.com supportedSASLMechanism
supportedSASLMechanisms: GSSAPI
supportedSASLMechanisms: GSS-SPNEGO
supportedSASLMechanisms: EXTERNAL
supportedSASLMechanisms: DIGEST-MD5

If you prefer to use a SSL client certificate, it requires a few steps.

First you need to get one certificate. There are many way to this, like Oracle Wallet manager or Microsoft Certmgr, but you could well use openssl. Using a selfsigned certificate is not a good idea.
openssl.org

Before you submit your certificate for signature. You need to add a subject alternate name with the principal name.

cat /etc/openssl/openssl.cnf > server.cnf
echo "[client]" >> server.cnf
echo "extendedKeyUsage = clientAuth" >> server.cnf
echo "subjectAltName=otherName:msUPN;UTF8:user001@example.com" >> server.cnf

This is (at least in the openssl version I used) not possible in one step. You need to create a local config file (-config) and define a new request extension ([client]).

openssl req -new -subj '/DC=com/DC=example/OU=Users/CN=user001' -key private_key.pem -out server.csr -config server.cnf -reqexts client

Once you have your user-certificate and root-authority, you need to map your client certificate to your AD account
Map a certificate to a user account
In openldap, you then create your own $HOME/.ldaprc

$ cat $HOME/.ldaprc  
TLS_CERT /home/user001/cert_user001.pem
TLS_KEY /home/user001/private_key.pem
$ ldapsearch -Y EXTERNAL -ZZ -H ldap://example.lab:389  -D user001@example.com -vvv  -b "DC=example,DC=lab" cn="Laurent C. Schneider" mail
ldap_initialize( ldap://example.lab:389/??base )
SASL/EXTERNAL authentication started
SASL username: cn=user001,ou=Users,dc=example,dc=lab
SASL SSF: 0
mail: laurent.c.schneider@example.com

The option -Z means starttls. I connect plain to 389, then start TLS for ldap.

With this command, you connect to AD with an SSL client certificate

Categories
windows

Dump TNSNAMES.ORA from ActiveDirectory

Having all connections string in ActiveDirectory is nice, but maybe you need sometimes to push it to an external system (e.g. DMZ or Linux).

echo "# AD" > tnsnames.ora
$o = New-Object DirectoryServices.DirectorySearcher
$o.Filter = 'objectclass=orclNetService'
foreach ($p in $o.FindAll().Properties) {
[String]($p.name+"="+$p.orclnetdescstring) >> tnsnames.ora
}

goodies :mrgreen:

Categories
sqlnet

OracleContext as top object in Active Directory

When you do expand your Active Directory schema, it is not reversible; how to decide to use the OracleContext as a top object or not?

On the one hand, for tnsnames resolution, you could hide your context down in your AD structure and change the path in ldap.ora


DIRECTORY_SERVER_TYPE=AD
DEFAULT_ADMIN_CONTEXT="OU=Oracle,OU=Misc,DC=example,DC=com"

For debugging, I set TNSPING.TRACE_LEVEL=ADMIN and TNSPING.TRACE_DIRECTORY=C:\TEMP


PS> TNSPING DB01
Used LDAP adapter to resolve the alias
Attempting to contact (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(
PROTOCOL=TCP)(HOST=SRV01)(PORT=1521)))(CONNECT_DATA=(SID=DB01)))
OK (20 msec)

PS> Select-String "DB01" C:\temp\tnsping.trc

nnflrne1: Quering the directory for dn: cn=DB01,cn=OracleContext,
OU=Oracle,OU=Misc,DC=example,DC=com
nnflqbf: Search: Base: cn=DB01,cn=OracleContext,OU=Oracle,OU=Misc,
DC=example,DC=com; Scope: 0; filter: (objectclass=*) returns 0x0
nnflgne: DN : cn=DB01,cn=OracleContext,OU=Oracle,OU=Misc,
DC=example,DC=com
nsc2addr: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.2)
(PORT=1521))(CONNECT_DATA=(SID=DB01)))

So far so good; but on the other hand, it prevents you from using connection identifier like DB01.EXAMPLE.COM


PS> TNSPING DB01.EXAMPLE.COM
TNS-03505: Failed to resolve name

PS> Select-String "DB01" C:\temp\tnsping.trc

nnflfdn: Turning simplified name DB01.EXAMPLE.COM into a dn.
nnflfdn: The resulting dn is cn=DB01,cn=OracleContext,
dc=EXAMPLE,dc=COM
nnflrne1: Quering the directory for dn: cn=DB01,cn=OracleContext,
dc=EXAMPLE,dc=COM
nnflqbf: Search: Base: cn=DB01,cn=OracleContext,dc=EXAMPLE,
dc=COM; Scope: 0; filter: (objectclass=*) returns 0x20
nnfun2a: address for name "DB01.EXAMPLE.COM" not found

This no longer works. Your database domain name must match your Active Directory domain name and your object must be a top object domain

Platform guide for Windows : Oracle Context is the top-level Oracle entry in the Active Directory tree

It is probably wiser to follow this recommendation.

Also new in 11gR2 is NAMES.LDAP_AUTHENTICATE_BIND=TRUE, which removes the need of allowing anonymous ldap bind in AD