Child pages
  • Preparing OpenDJ As Repository
Skip to end of metadata
Go to start of metadata

Prepare OpenDJ to be a OpenIDM Repo

To Use OpenDJ as a repository in OpenIDM you need to prepare the repository properly. This includes setting up directories and creating an objectClass to support OpenIDM attributes not available in OpenDJ.

Configuring OpenDJ

OpenDJ doesn't contain all the attributes that OpenIDM needs to store a managed user, so these attributes must be created. Below is the content of the ldif file needed to create the OpenDJ attributes.

dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.145 NAME 'accountStatus' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.146 NAME 'passPhrase' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.147 NAME 'securityAnswer' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.148 NAME 'securityQuestion' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.149 NAME 'securityAnswerAttempts' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.150 NAME 'lastSecurityAnswerAttempt' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.151 NAME 'total' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.152 NAME 'roles' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.153 NAME 'passwordAttempts' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.154 NAME 'lastPasswordAttempt' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.155 NAME 'lastPasswordSet' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.156 NAME 'country' 
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenIDM OpenDJRepoService' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.22 NAME 'openidmManagedUser' SUP top AUXILIARY
  MAY ( accountStatus $ passPhrase $ securityAnswer $
  pwdCheckQuality $ pwdMinLength $ pwdExpireWarning $ securityQuestion $
  securityAnswerAttempts $ lastSecurityAnswerAttempt $ total $ roles $ 
  passwordAttempts $ lastPasswordAttempt $ lastPasswordSet $ country )
  X-ORIGIN 'OpenIDM OpenDJRepoService' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.22 NAME 'openidmInternalUser' SUP top AUXILIARY
  MAY roles X-ORIGIN 'OpenIDM OpenDJRepoService' )

That LDIF content should be put in a file and saved as something.ldif. That file then needs to be copied to the /location/to/opendj/config/schema folder.

Next, OpenDJ requires the directories that will store the managed users to be populated, and one admin user to be populated. This can be done using an ldif file with the following content.

dn: dc=forgerock,dc=com
changetype: add
objectClass: domain
objectClass: top
dc: forgerock

dn: dc=openidm,dc=forgerock,dc=com
changetype: add
objectClass: domain
objectClass: top
dc: openidm
aci: (targetattr="*")(version 3.0; acl "IDM Access"; allow (all)
  userdn="ldap:///uid=idm,ou=admin,dc=opendj,dc=forgerock,dc=com";)

dn: dc=managed,dc=openidm,dc=forgerock,dc=com
changetype: add
objectClass: domain
objectClass: top
dc: managed

dn: ou=user,dc=managed,dc=openidm,dc=forgerock,dc=com
changetype: add
ou: user
objectClass: top
objectClass: organizationalUnit

dn: dc=internal,dc=openidm,dc=forgerock,dc=com
changetype: add
objectClass: domain
objectClass: top
dc: internal

dn: ou=user,dc=internal,dc=openidm,dc=forgerock,dc=com
changetype: add
ou: user
objectClass: top
objectClass: organizationalUnit

dn: dc=opendj,dc=forgerock,dc=com
changetype: add
objectClass: domain
objectClass: top
dc: opendj

dn: ou=admin,dc=opendj,dc=forgerock,dc=com
changetype: add
ou: admin
objectClass: top
objectClass: organizationalUnit

dn: uid=idm,ou=admin,dc=opendj,dc=forgerock,dc=com
changetype: add
objectClass: top
objectClass: inetOrgPerson
uid: idm
ou: admin
cn: IDM Administrator
sn: IDM Administrator
description: Special LDAP acccount used by openIDM
userPassword: password
ds-privilege-name: bypass-acl
ds-privilege-name: changelog-read

Put the above content in an ldif file and use the following command to populate that data in OpenDJ.

opendj/bin/ldapmodify --bindDN "cn=Directory Manager" --bindPassword password --hostname localhost --port 1389 --filename /path/to/file.ldif

Now that OpenDJ has the necessary attributes and directories populated the final step is to enable the rest2ldap service and set the servlet mapping for managed user.

To enable the rest2ldap service use the following command.

opendj/bin/dsconfig set-connection-handler-prop --hostname localhost --port 4444 \
--bindDN "cn=Directory Manager" --bindPassword password --handler-name "HTTP Connection Handler" \
--set enabled:true --set listen-port:8090 --no-prompt --trustAll

Once the rest2ldap service is enabled create a file called http-config.json with the following content

{
    "servlet": {
        "mappings": { 
            "/managed/user": {
                "usePermissiveModify": true, 
                "baseDN": "ou=user,dc=managed,dc=openidm,dc=forgerock,dc=com", 
                "additionalLDAPAttributes": [
                    {
                        "values": [
                            "top", 
                            "inetOrgPerson", 
                            "openidmManagedUser"
                        ], 
                        "type": "objectClass"
                    }
                ], 
                "readOnUpdatePolicy": "controls", 
                "etagAttribute": "etag", 
                "useSubtreeDelete": false, 
                "attributes": {
                    "_id": {
                        "simple": {
                            "isRequired": true, 
                            "writability": "createOnly", 
                            "ldapAttribute": "uid", 
                            "isSingleValued": true
                        }
                    },
                    "_rev": {
                        "simple": {
                            "writability": "readOnly", 
                            "ldapAttribute": "etag", 
                            "isSingleValued": true
                        }
                    }, 
                    "userName": {
                        "simple": {
                            "ldapAttribute": "cn", 
                            "isSingleValued": true
                        }
                    },
                    "password": {
                        "simple": {
                            "ldapAttribute": "userPassword",
                            "isSingleValued": true
                        }
                    },
                    "accountStatus": {
                        "simple": {
                            "ldapAttribute": "accountStatus",
                            "isSingleValued": true
                        }
                    },
                    "roles": {
                        "simple": {
                            "ldapAttribute": "roles",
                            "isSingleValued": false
                        }
                    },
                    "lastPasswordSet": {
                        "simple": {
                            "ldapAttribute": "lastPasswordSet",
                            "isSingleValued": true
                        }
                    },
                    "postalCode": {
                        "simple": {
                            "ldapAttribute": "postalCode",
                            "isSingleValued": true
                        }
                    },
                    "stateProvince": {
                        "simple": {
                            "ldapAttribute": "st",
                            "isSingleValued": true
                        }
                    },
                    "passwordAttempts": {
                        "simple": {
                            "ldapAttribute": "passwordAttempts",
                            "isSingleValued": true
                        }
                    },
                    "lastPasswordAttempt": {
                        "simple": {
                            "ldapAttribute": "lastPasswordAttempt",
                            "isSingleValued": true
                        }
                    },
                    "postalAddress": {
                        "simple": {
                            "ldapAttribute": "postalAddress",
                            "isSingleValued": false
                        }
                    },
                    "country": {
                        "simple": {
                            "ldapAttribute": "country",
                            "isSingleValued": true
                        }
                    },
                    "city": {
                        "simple": {
                            "ldapAttribute": "l",
                            "isSingleValued": true
                        }
                    },
                    "givenName": {
                        "simple": {
                            "ldapAttribute": "givenName",
                            "isSingleValued": true
                        }
                    },
                    "sn": {
                        "simple": {
                            "ldapAttribute": "sn",
                            "isSingleValued": true
                        }
                    },
                    "telephoneNumber": {
                        "simple": {
                            "ldapAttribute": "telephoneNumber",
                            "isSingleValued": true
                        }
                    },
                    "mail": {
                        "simple": {
                            "ldapAttribute": "mail",
                            "isSingleValued": true
                        }
                    },
                    "siteImage": {
                        "simple": {
                            "ldapAttribute": "jpegPhoto",
                            "isSingleValued": true
                        }
                    },
                    "passPhrase": {
                        "simple": {
                            "ldapAttribute": "passPhrase",
                            "isSingleValued": true
                        }
                    },
                    "securityAnswer": {
                        "simple": {
                            "ldapAttribute": "securityAnswer",
                            "isSingleValued": true
                        }
                    },
                    "securityQuestion": {
                        "simple": {
                            "ldapAttribute": "securityQuestion",
                            "isSingleValued": true
                        }
                    },
                    "securityAnswerAttempts": {
                        "simple": {
                            "ldapAttribute": "securityAnswerAttempts",
                            "isSingleValued": true
                        }
                    },
                    "lastSecurityAnswerAttempt": {
                        "simple": {
                            "ldapAttribute": "lastSecurityAnswerAttempt",
                            "isSingleValued": true
                        }
                    },
                    "total": {
                        "simple": {
                            "ldapAttribute": "total",
                            "isSingleValued": true
                        }
                    }
                }, 
                "namingStrategy": {
                    "dnAttribute": "uid", 
                    "strategy": "clientDNNaming"
                }
            },
            "/internal/user": {
                "usePermissiveModify": true, 
                "baseDN": "ou=user,dc=internal,dc=openidm,dc=forgerock,dc=com", 
                "additionalLDAPAttributes": [
                    {
                        "values": [
                            "top",
                            "account", 
                            "openidmInternalUser"
                        ], 
                        "type": "objectClass"
                    }
                ], 
                "readOnUpdatePolicy": "controls", 
                "etagAttribute": "etag", 
                "useSubtreeDelete": false, 
                "attributes": {
                    "_id": {
                        "simple": {
                            "isRequired": true, 
                            "writability": "createOnly", 
                            "ldapAttribute": "uid", 
                            "isSingleValued": true
                        }
                    },
                    "_rev": {
                        "simple": {
                            "writability": "readOnly", 
                            "ldapAttribute": "etag", 
                            "isSingleValued": true
                        }
                    },
                    "pwd": {
                        "simple": {
                            "ldapAttribute": "userPassword",
                            "isSingleValued": true
                        }
                    },
                    "roles": {
                        "simple": {
                            "ldapAttribute": "roles",
                            "isSingleValued": false
                        }
                    }
                }, 
                "namingStrategy": {
                    "dnAttribute": "uid", 
                    "strategy": "clientDNNaming"
                }
            }
        }
    }, 
    "authenticationFilter": {
        "altAuthenticationPasswordHeader": "X-OpenIDM-Password", 
        "searchScope": "sub", 
        "altAuthenticationUsernameHeader": "X-OpenIDM-Username", 
        "supportHTTPBasicAuthentication": true, 
        "supportAltAuthentication": true, 
        "searchFilterTemplate": "(&(objectClass=inetOrgPerson)(uid=%s))", 
        "searchBaseDN": "ou=admin,dc=opendj,dc=forgerock,dc=com"
    }
}
        

Copy the http-config.json file to /location/to/opendj/config/.

Finally restart OpenDJ with the following command.

opendj/bin/stop-ds --restart

Using OpenDJ Rest2Ldap

Creating Managed Users

$ curl -X PUT -H 'Content-Type:application/json' -u 'idm:password' -H 'If-None-Match:*' --data '{
  "_id": "value",
  "userName": "userName",
  "password": "password",
  "accountStatus": "accountStatus",
  "roles": ["role1", "role2"],
  "lastPasswordSet": "lastPasswordSet",
  "postalCode": "postalCode",
  "stateProvince" : "stateProvince",
  "passwordAttempts": "passwordAttempts",
  "lastPasswordAttempt": "lastPasswordAttempt",
  "postalAddress": ["postalAddress","postalAddress2"],
  "country": "country",
  "city": "city",
  "givenName": "givenName",
  "sn": "sn",
  "telephoneNumber": "5555555555",
  "mail": "mail",
  "siteImage": "image",
  "passPhrase": "passPhrase",
  "securityAnswer": "securityAnswer",
  "securityQuestion": "securityQuestion",
  "securityAnswerAttempts": "securityAnswerAttempts",
  "lastSecurityAnswerAttempt": "lastSecurityAnswerAttempt",
  "total": "total"
}' http://localhost:8090/managed/users/jason
 
{"total":"total","passwordAttempts":"passwordAttempts","givenName":"givenName","securityAnswerAttempts":"securityAnswerAttempts","password":"{SSHA}2sD59HpgufmmS2rU5eWJuakC3tqyVYw81S4SYA==","securityQuestion":"securityQuestion","city":"city","lastPasswordSet":"lastPasswordSet","postalCode":"postalCode","_id":"value","passPhrase":"passPhrase","accountStatus":"accountStatus","stateProvince":"stateProvince","userName":"userName","securityAnswer":"securityAnswer","lastSecurityAnswerAttempt":"lastSecurityAnswerAttempt","mail":"mail","sn":"sn","lastPasswordAttempt":"lastPasswordAttempt","country":"country","_rev":"00000000e5973c27","siteImage":"image","roles":["role1","role2"],"telephoneNumber":"5555555555","postalAddress":["postalAddress","postalAddress2"]}

Creating Internal Users

$ curl -X PUT -H "Content-Type: application/json" -H "If-None-Match: *" -u 'idm:password' --data '{
    "_id" : "admin",
    "roles" : ["role1", "role2"]
}' http://localhost:8090/internal/user/admin
 
{
	"_rev": "00000000d65545f5",
	"_id": "admin",
	"roles": ["role1", "role2"]
}
  • No labels

3 Comments

  1. Great progress. Well done.

    Also, another option is to not configure the HTTP listener in OpenDJ, but instead embed Rest2LDAP directly in OpenIDM as an internal CREST endpoint. You can see some basic use of the embedded version in the unit tests: http://sources.forgerock.org/browse/opendj/trunk/opendj/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/BasicRequestsTest.java?hb=true#to620

     

    import static org.forgerock.json.resource.Resources.*;
    import org.forgerock.opendj.rest2ldap.Rest2LDAP;
    ...
    
    // Create the Rest2LDAP resoure collection
    CollectionResourceProvider rest2ldap = Rest2LDAP.builder()
        .ldapConnectionFactory(new LDAPConnectionFactory("localhost", 1389))
        .baseDN("dc=test")
        .useEtagAttribute()
        .useClientDNNaming("uid")
        ...
        .build();
    
    // Create internal CREST connection to Rest2LDAP
    Connection crest = newInternalConnection(newCollection(rest2ldap));
    
    // Do a query.
    List<Resource> resources = new LinkedList<>();
    QueryResult result = crest.query(new RootContext(),
                                     Requests.newQueryRequest("").setQueryFilter(QueryFilter.alwaysTrue()),
                                     resources);

    Embedding Rest2LDAP in OpenIDM may be simpler in the long run because it requires less effort to configure and deploy OpenDJ.

    1. Matt, that is essentially how it has been implemented in IDM. I have created a generic CREST repository that wraps a CollectionResourceProvider. Jason was only using the resource servlet to test requests while my repo implementation was not in a working state.

      1. Great. Thanks for letting me know Jim.