Tuesday, April 1, 2025

ldapsearch error: "scope is required for a null based search"

This command:


ldapsearch -D binduser@acme.com -w ? -h globalADcatalog -b DC=acme,DC=com cn=myuser

Will sometimes give the error:

scope is required for a null based search

But if you simply change directories (to /opt, for example), the command will run just fine.

This is due to filename expansion in the shell, where you happen to have a file (or directory) with a single-character name in your current working directory. The correct way to get around this is to change the command to:

ldapsearch -D binduser@acme.com -w \? -h globalADcatalog -b DC=acme,DC=com cn=myuser

FYI: The "-w ?" tells ldapsearch to prompt you for a password, and the backslash quotes the question mark so the shell doesn't try to interpret it. I like using this form of the command rather than typing the password on the command line for security purposes:

  1. While the command is running, ANY user on the system can see the entire command line with the 'ps -ef' command.
  2. If you're using a shared account (like a service account), any other people sharing that account can see all previous commands with the 'history' command.

Monday, March 31, 2025

Customizing IDI Linux Adapter - javax.naming.NameNotFoundException: isDollarAllowedInPwd

I was just looking at customizing the IDI Linux Adapter. I unzipped PosixLinuxProfile.jar and imported posixAdd.xml into my project in the IDI CE. When I clicked on the posixConn connector in the AssemblyLine, I got the error:

javax.naming.NameNotFoundException: isDollarAllowedInPwd 

I unzipped the PosixConnector.jar file and found the idi.inf file (that's not documented anywhere - this function is now performed with a tdi.xml file, but this older adapter still has this old file). In there, everything mainly looks good EXCEPT I noticed in the parameter section that isDollarAllowedInPwd didn't have a space before the following open curly brace, while every other parameter did. So I changed it from:

isDollarAllowedInPwd{

to

isDollarAllowedInPwd {

Then saved the idi.inf file, re-created the jar file, copied PosixConnector.jar to jars/connectors, and restarted IDI. Once I did that, I no longer got the error. I'm certain this doesn't affect the operation of the adapter, since this is simply for the Connector form in the CE, but I just didn't like seeing the error.

Additionally, another error you might see is a complaint about "_Default" and " Default". These are two properties files that are defined in all of the Linux Adapter assemblylines. The way to eliminate these errors (again, which only affect the CE; they don't affect the operation of the adapter) is to create two new tdiproperties files, one named "_Default" and one named " Default" (that is <space>Default). The GUI will let you create that weird name - just put a space in front of "Default". Then the CE won't complain about these two properties files any more.

There you go. Just wanted to share in case someone is encountering the problem.

Sunday, February 16, 2025

Using IDI to convert ISIM audit XML data into HTML

 Related to my last post, I made a video covering the IDI assemblyline I wrote to convert ISIM audit XML data to HTML. Here's the video:


And here's the link to the Github repo with the project containing the assemblyline: https://github.com/franktate/IBM-Directory-Integrator


XSLT for ISIM Audit XML Data

 I made a video on using XSLT to convert ISIM's XML reconciliation audit data into more readable XML. Specifically, it takes XML that looks like this:

<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="frankaudit.xslt"?>
<Object name="Person">
  <Attribute name="title" type="String">
    <Scalar>Senior BA</Scalar>
  </Attribute>
  <Attribute name="acmegroups" type="String">
    <Scalar>group1</Scalar>
  </Attribute>
  <Attribute name="AttributeChangeOperation" type="Object">
    <Object name="AttributeChangeOperation.operation.replace">
      <Attribute name="acmegroups" type="String">
        <Scalar>group2</Scalar>
        <Scalar>group3</Scalar>
        <Scalar>group4</Scalar> 
      </Attribute>
    </Object> 
  </Attribute>
  <Attribute name="AttributeChangeOperation" type="Object">
    <Object name="AttributeChangeOperation.operation.remove">
      <Attribute name="title" type="String"></Attribute>
    </Object>
  </Attribute>
  <Attribute name="AttributeChangeOperation" type="Object">
    <Object name="AttributeChangeOperation.operation.add">
      <Attribute name="acmepositionnumber" type="String">
        <Scalar>99999999</Scalar>
      </Attribute>
    </Object>
  </Attribute>
</Object>

And turn it into HTML that renders like this:


The video is here: https://youtu.be/7yEkGZGN1Lg and the files used are available in my github repo here: https://github.com/franktate/ISIM-Audit-XML-XSLT

Tuesday, January 21, 2025

Decrypting the idisrv.sth file from IBM Directory Integrator

Background

The idisrv.sth file that's included in IBM Directory Integrator isn't a normal stash file. A normal stash file can be decrypted with a simple Perl script (see my previous post). However, this one is different. Happily, IBM does include a method to read this file, though it's hidden in a Jar file and requires some Java know-how.

Java Code

Here's the Java code required to read the file (in a file named ftStashFile.java - the name of the file must match the name of the class):

import com.ibm.di.server.StashFile;
import java.util.Vector;

public class ftStashFile extends StashFile {
  public static void main(String[] args) throws Exception {
    try {
      Vector thePassword = readPasswords();
      System.out.println(thePassword.firstElement());
    } catch (Exception e) {
      System.out.println("Exception encountered: " + e.toString());
    }
  }
}

The command to compile it is:

javac -cp .:/opt/IBM/TDI/V7.1.1/jars/common/miserver.jar ftStashFile.java

Then the command to run it is:

java -cp .:/opt/IBM/TDI/V7.1.1/jars/common/miserver.jar:/opt/IBM/TDI/V7.1.1/jars/common/tdiresource.jar:/opt/IBM/TDI/V7.1.1/jars/3rdparty/IBM/icu4j-4_4_2.jar ftStashFile

NOTE: You need to have the idisrv.sth file in the same directory as ftStashFile.class when you run it.

NOTE2: You will have problems if the JDK you're using is older than the JDK that was used to compile the IDI jar files. You'll get an error similar to this if that's the case:

  bad class file: ../jars/common/miserver.jar(com/ibm/di/server/StashFile.class)
    class file has wrong version 55.0, should be 52.0
    Please remove or make sure it appears in the correct subdirectory of the classpath.



JD-GUI Download: 


Perl script for decrypting a GSKit-created stash file:


Keystore Explorer (open-source tool similar to iKeyMan):

Monday, January 20, 2025

Decrypting properties in IBM Directory Integrator

If you look at the usage from the IDI encryption utility (cryptoutils.sh), you'll see this:

[root@jazzsm9 serverapi]# ./cryptoutils.sh 
CTGDKD446I Usage:
-input <input file>
-output <output file>
-mode <encrypt|decrypt|encrypt_config|decrypt_config>
-keystore <keystore file>
-storepass <keystore password>
-alias <encryption key alias>
[ -keypass <key password> ]
[ -transformation <encryption transformation> ]
[ -storetype <keystore type> ]
[ -cryptoproviderclass <security provider used for encryption> ]


Unfortunately, none of those "-mode" options will let you decrypt values in any of the *.properties files (e.g. global.properties, solution.propterties, etc.) So how do you do it?

To get the answer, you need to find the online documentation here to find that there are two additional options that aren't listed above. They are:

encrypt_props
decrypt_props

Once you know that, you're over the largest obstacle. But now you have several additional flags with values to provide, and the documentation doesn't give you an example of doing exactly this. So here's the example:

/opt/IBM/TDI/cev10/serverapi/cryptoutils.sh \
-input /opt/IBM/TDI/ftsoldir/solution.properties \
-output /tmp/foo \
-mode decrypt_props \
-keystore /opt/IBM/TDI/ftsoldir/testserver.jks \
-storepass server \
-alias server


In the above case, I wanted to decrypt the encrypted values in my solution.properties file. My solution directory is /opt/IBM/TDI/ftsoldir. Notice also that you MUST provide the certificate alias that points to the server certificate in the solution directory. By DEFAULT (meaning: all of this can be changed), the alias of that certificate is "server", it is stored in the $SOLDIR/testserver.jks keystore, and the password of the keystore is "server". The name of the keystore and the alias are specified in these two properties in solution.properties:

com.ibm.di.server.encryption.keystore = testserver.jks
com.ibm.di.server.encryption.key.alias = server


If, however, you forget the password, that's not a good thing. Normally you can decrypt an IBM stash file with a perl script like this:

#!/usr/bin/perl
use strict;
die "Usage: $0 <stash file>n" if $#ARGV != 0;
my $file=$ARGV[0];
open(F,$file) || die "Can't open $file: $!";
my $stash;
read F,$stash,1024;
my @unstash=map { $_^0xf5 } unpack("C*",$stash);
foreach my $c (@unstash) {
last if $c eq 0;
printf "%c",$c;
}
printf " ";


However, that doesn't work on the IDI stash file (idisrv.sth) because this isn't a GSKit stash file. From the docs:

The stash file contains the Server keystore password values encrypted with AES128 with a fixed key.

Check back later to find out later how to read this stash file - I think I've figured out how to decrypt it.

I did figure it out, and here's the video.

And NOTE: This only matters if you want to CHANGE the password of the keystore and keep the keystore. If all you need to do is add a server certificate to the keystore for a new web connection, you can simply use the "Get Certificate" button in the HTTP Server Connector to get the server's certificate and add it to the keystore.

Friday, January 10, 2025

IBM Identity Manger: Adding a new attribute

Background

The documentation on this is lacking on this topic, and the example LDIF file provided is in a format that will cause idsldapmodify to fail with a painfully obtuse error message. So I'm documenting this here to help the next person avoid some headache.

Details

Here's the documentation on how to add an attribute. In there, it provides this LDIF file as an example:

dn: cn=schema changetype: modify add: attributetypes attributetypes: ( myAttribute-oid NAME ( 'myAttribute' ) DESC 'An attribute I defined for my LDAP application' EQUALITY 2.5.13.2 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 {200} USAGE userApplications ) - add: ibmattributetypes ibmattributetypes: ( myAttribute-oidDBNAME ( 'myAttrTable' 'myAttrColumn' ) ACCESS-CLASS normal LENGTH 200 )

However, if you try to import that LDIF file with the idsldapmodify command given, you'll get the following error:

ldapmodify: invalid format (line 5 of entry: cn=schema)
After a bit of pain, I figured out that the whitespace in the lines are the problem. You need to either concatenate the continued lines together OR have some white space at the front of the continued lines. Additionally, there should be a space in betwee "oid" and "DBNAME". So if you change the file to the following, you will no longer get the error:
dn: cn=schema
changetype: modify
add: attributetypes
attributetypes: ( myAttribute-oid NAME ( 'myAttribute' ) DESC 'An attribute I defined for my LDAP application'    EQUALITY 2.5.13.2 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15    {200} USAGE userApplications )
-
add: ibmattributetypes
ibmattributetypes: ( myAttribute-oid DBNAME ( 'myAttrTable' 'myAttrColumn' ) ACCESS-CLASS normal LENGTH 200 )

What about updating the objectclass?

That's what I was wondering! Simply adding an attribute doesn't really help you much until you add it as a MUST or a MAY attribute to an objectclass. IBM has an almost complete guide to doing that here, But it is incomplete. For one thing, the format of the data is wrong again. The long attribute values should all be on a single line, like this:
dn: cn=schema
changetype: modify
replace: objectclasses
objectclasses: ( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'Defines entries representing people in an organizations enterprise network.' SUP 'organizationalPerson' Structural MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ pager $ photo $ preferredLanguage $ roomNumber $ secretary $ uid $ userCertificate $ userSMIMECertificate $ x500UniqueIdentifier $ mytest ) )
Additionally, where did that value for "objectclasses" come from?? Well, that came from this command:
ldapsearch -b cn=schema -s base objectclass=* objectclasses | grep \'inetOrgPerson\'
Running that, you will get a result similar to:
objectclasses=( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'Defines entries representing people in an organizations enterprise network.' SUP organizationalPerson STRUCTURAL MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayName $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ pager $ photo $ preferredLanguage $ roomNumber $ secretary $ uid $ userCertificate $ userPKCS12 $ userSMIMECertificate $ x500UniqueIdentifier ) )
Modify that to include your new attribute, then put that into the LDIF file. Then run idsldapmodify to import that LDIF file into your server. After that, you'll have your new attribute added to the inetOrgPerson objectclass.