Showing posts with label Active Directory. Show all posts
Showing posts with label Active Directory. Show all posts

Thursday, November 13, 2008

Active Directory userAccountControl Values

Normal Day to Day Values:
===========================
512 - Enable Account
514 - Disable account
544 - Account Enabled - Require user to change password at first logon
4096 - Workstation/server
66048 - Enabled, password never expires
66050 - Disabled, password never expires
262656 - Smart Card Logon Required
532480 - Domain controller

All Other Values:
===========================
1 - script
2 - accountdisable
8 - homedir_required
16 - lockout
32 - passwd_notreqd
64 - passwd_cant_change
128 - encrypted_text_pwd_allowed
256 - temp_duplicate_account
512 - normal_account
2048 - interdomain_trust_account
4096 - workstation_trust_account
8192 - server_trust_account
65536 - dont_expire_password
131072 - mns_logon_account
262144 - smartcard_required
524288 - trusted_for_delegation
1048576 - not_delegated
2097152 - use_des_key_only
4194304 - dont_req_preauth
8388608 - password_expired
16777216 - trusted_to_auth_for_delegation


reference:
http://support.microsoft.com/kb/305144
http://www.computerperformance.co.uk/ezine/ezine23.htm

Thursday, August 28, 2008

Update Active Directory Password with Code

import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import java.util.*;
import java.security.*;

public class ADUpdatePwd

{

private DirContext ldapContext;

private String baseName = ",ou=People,dc=bhatiacorp,dc=com";

private String serverIP = "127.0.0.1";

public void updatePassword(String username, String password) {
try {
String quotedPassword = "\"" + password + "\"";
char unicodePwd[] = quotedPassword.toCharArray();
byte pwdArray[] = new byte[unicodePwd.length * 2];
for (int i = 0; i < unicodePwd.length; i++) {
pwdArray[i * 2 + 1] = (byte) (unicodePwd[i] >>> 8);
pwdArray[i * 2 + 0] = (byte) (unicodePwd[i] & 0xff);
}

ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("UnicodePwd", pwdArray));
ldapContext.modifyAttributes("cn=" + username + baseName, mods);
} catch (Exception e) {
System.out.println("ADUpdatePwd :: Update Password Error :: " + e);

}
}

private void setContext(String ldaphost, String ldapport, String adminID, String adminpassword, boolean useSSL) {
String providerurl = ldaphost + ":" + ldapport;
if (ldapport == "") {
ldapport = "636";
}
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, providerurl);
if (useSSL == true) {
// if SSL is used - use can use ssl enabled ldaphost
// eg. "ldaps://localhost:636"
// else
// eg. "ldap://localhost:636"
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, adminID);
env.put(Context.SECURITY_CREDENTIALS, adminpassword);
ldapContext = new InitialDirContext(env);
} catch (Exception ex) {
ex.printStackTrace();
}
}


public ADUpdatePwd() {
try {
setContext("ldaps://serverIP", "636", "CN=Administrator"+baseName, "p@ssw0rd1~", true);
} catch (Exception e) {
System.out.println("ADUpdatePwd :: Error :: " + e);
e.printStackTrace();

}
}

public static void main(String[] args) {
try {
/*
* Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); the keystore that holds trusted root certificates
* System.setProperty("javax.net.ssl.trustStore", "c:\\myCaCerts.jks");
* System.setProperty("javax.net.debug","all");
*/

ADUpdatePwd c = new ADUpdatePwd();
c.updatePassword("Bhatiar", "p@ssw0rd3");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Thursday, May 22, 2008

AD SSL Handshake / Certificate Expired Error

If you have a certificate in Active Directory that is manually generated and expired, your OIM connection might fail with SSL Handshake error or Certificate Expired Error. Even though you see the correct certificate in Active Directory, still you might recieve SSL Handshake Errors or Certificate Expired Errors. This happens mostly when its a manually generated certificate.

Here is the error that you might face:
java.security.cert.CertificateExpiredException: NotAfter: Thu Apr 17 13:56:25 EDT 2008
at sun.security.x509.CertificateValidity.valid(CertificateValidity.java:268)
at sun.security.x509.X509CertImpl.checkValidity(X509CertImpl.java:564)
at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:123)
at sun.security.validator.Validator.validate(Validator.java:202)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(DashoA12275)
at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_ax.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.j(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(DashoA12275)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:183)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:222)
at java.io.BufferedInputStream.read(BufferedInputStream.java:277)
at com.sun.jndi.ldap.Connection.run(Connection.java:784)

Alternatively, you might face the following issue:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found

Here is the solution for this:

WORKAROUND

To work around this issue, remove the expired (archived) certificate. To do this, follow these steps:1. Open the Microsoft Management Console (MMC) snap-in where you manage the certificate store on the IAS server. If you do not already have an MMC snap-in to view the certificate store from, create one. To do so:a. Click Start, click Run, type mmc in the Open box, and then click OK.
b. On the Console menu (the File menu in Windows Server 2003), click Add/Remove Snap-in, and then click Add.
c. In the Available Standalone Snap-ins list, click Certificates, click Add, click Computer account, click Next, and then click Finish.

Note You can also add the Certificates snap-in for the user account and for the service account to this MMC snap-in.
d. Click Close, and then click OK.

2. Under Console Root, click Certificates (Local Computer).
3. On the View menu, click Options.
4. Click to select the Archived certificates check box, and then click OK.
5. Expand Personal, and then click Certificates.
6. Right-click the expired (archived) digital certificate, click Delete, and then click Yes to confirm the removal of the expired certificate.
7. Quit the MMC snap-in. You do not have to restart the computer or any services to complete this procedure.
8. FYI - In our case, we had to restart the AD server to take the changes in effect. This did not fix the issue without restarting.

This is an excerpt from Microsoft's Website. Here are the links to solve this:

http://support.microsoft.com/kb/822406/

http://support.microsoft.com/kb/839514/

The other problem could be your new / renewed certificate was not imported in Java cacerts keystore of OIM server. Use the following to connect OIM with SSL based Active Directory. This is an excerpt from OIM documentation:

Installing Certificate Services

The connector requires Certificate Services to be running on the host computer. To install Certificate Services:
1.Insert the operating system installation media into the CD-ROM or DVD drive.
2.Click Start, Settings, and Control Panel.
3.Double-click Add/Remove Programs.
4.Click Add/Remove Windows Components.
5.Select Certificate Services.
6.Follow the instructions to start Certificate Services.

Enabling LDAPS

The target Microsoft Active Directory server must have LDAP over SSL (LDAPS) enabled. To enable LDAPS, generate a certificate as follows:
1.On the Active Directory Users and Computers console, right-click the domain node, and select Properties.
2.Click the Group Policy tab.
3.Select Default Domain Policy.
4.Click Edit.
5.Click Computer Configuration, Windows Settings, Security Settings, and Public Key Policies.
6.Right-click Automatic Certificate Request Settings, and then select New and Automatic Certificate Request. A wizard is started.
7.Use the wizard to add a policy with the Domain Controller template.
At the end of this procedure, the certificate is created and LDAP is enabled using SSL on port 636.


Setting Up the Microsoft Active Directory Certificate As a Trusted Certificate

If the Microsoft Active Directory certificate is not issued or certified by a certification authority (CA), then set it up as a trusted certificate. To do this, you first export the certificate and then import it into the keystore of the Oracle Identity Manager server as a trusted CA certificate.
Exporting the Microsoft Active Directory Certificate
To export the Microsoft Active Directory certificate:
1.Click Start, Programs, Administrative Tools, and Certification Authority.
2.Right-click the Certification Authority that you create, and then select Properties.
3.On the General tab, click View Certificate.
4.On the Details tab, click Copy To File.
5.Use the wizard to create a certificate (.cer) file using base-64 encoding.
Importing the Microsoft Active Directory Certificate
To import the Microsoft Active Directory certificate into the certificate store of the Oracle Identity Manager server:

Note:
In a clustered environment, you must perform this procedure on all the nodes of the cluster.

Note:
The user password cannot be set unless 128-bit SSL is used. In addition, the computer on which Microsoft Active Directory is installed must have Microsoft Windows 2000 Service Pack 2 (or later) or Microsoft Windows 2003 running on it.

Wednesday, May 7, 2008

Converting AD long dates to Java Date format

Environment : OIM 9.0.3, OIM Connector Pack 9.0.4.1, AD 2000

When you reconcile data from AD, the AD dates fail to link up OIM dates because of different format. The dates are stored in AD in long format and OIM uses normal Java Dates. So, here is the code that you can use to make this conversion.

import java.util.Date;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
public class AD
{
public void converADdateToOIMdate(long ADdate){

long ADdate = Long.parseLong(String.valueOf(ADdate));
System.out.println("long value : "+ADdate);

// Filetime Epoch is 01 January, 1601
// java date Epoch is 01 January, 1970
// so take the number and subtract java Epoch:
long javaTime = ADdate - 0x19db1ded53e8000L;

// convert UNITS from (100 nano-seconds) to (milliseconds)
javaTime /= 10000;

// Date(long date)
// Allocates a Date object and initializes it to represent
// the specified number of milliseconds since the standard base
// time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
Date theDate = new Date(javaTime);


System.out.println("java DATE value : "+theDate);

SimpleDateFormat formatter = new SimpleDateFormat("MMMMM d, yyyy");
// change to GMT time:
//formatter .setTimeZone(TimeZone.getTimeZone("GMT"));

String newDateString = formatter.format(theDate);

System.out.println("Date changed format :" + newDateString);
}


public static void main(String[] args)
{
AD d=new AD();
d.converADdateToOIMdate(128568528000000000L);
// 9223372036854775807
// 127948319499226601

}
}

Friday, April 11, 2008

DistributionListUtils

package com.bhatiacorp.utils;

import java.security.Provider;
import java.security.Security;
import java.util.Hashtable;
import java.util.Vector;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import Thor.API.tcResultSet;
import Thor.API.tcUtilityFactory;
import Thor.API.Operations.tcLookupOperationsIntf;

import com.thortech.util.logging.Logger;
import com.thortech.xl.dataaccess.tcDataProvider;

public class DistributionListUtils {

private String loggerTag;
private Logger logger;
private String CLASS_NAME;
public static double DISTRIBUTION_GROUP_GLOBAL = 2D;
public static double SECURITY_GROUP_GLOBAL = -2147483646D;
private String mLdapHost;
private String mLdapPort;
private String mAdminID;
private String mAdminPassword;
private boolean mUseSSL;
private String mLdapDistributionListLocation;
private String mRootContext;
private tcLookupOperationsIntf lookIntf;
private static String lookupCodeKeyCol = "Lookup Definition.Lookup Code Information.Code Key";
private static String lookupDecodeKeyCol = "Lookup Definition.Lookup Code Information.Decode";

public DistributionListUtils(String pLdapHost, String pLdapPort,
String pAdminID, String pAdminPassword, String pUseSSL,
String pLdapDistributionLocation, String pRootContext) {
loggerTag = "XL_INTG.BHATIACORP_UTILS";
logger = Logger.getLogger(loggerTag);
CLASS_NAME = getClass().getName();

mLdapHost = pLdapHost;
mLdapPort = pLdapPort;
mAdminID = pAdminID;
mAdminPassword = pAdminPassword;
mUseSSL = (pUseSSL.equalsIgnoreCase("true")) ? true : false;
mLdapDistributionListLocation = pLdapDistributionLocation;
mRootContext = pRootContext;
if (mUseSSL) {
Provider provider = Security.getProvider("com.sun.net.ssl.internal.ssl.Provider");
try {
if (provider == null) {
Class class1 = Class.forName("com.sun.net.ssl.internal.ssl.Provider");
Provider provider1 = (Provider) class1.newInstance();
Security.addProvider(provider1);
}
} catch (ClassNotFoundException classnotfoundexception) {
logger.error("DistributionListUtils -> Exception while setting provide for ssl. Could not find class com.sun.net.ssl.internal.ssl.Provider.\n"
+ classnotfoundexception.getMessage());
} catch (IllegalAccessException illegalaccessexception) {
logger.error("DistributionListUtils -> Exception while setting provide for ssl. IllegalAccessException: "
+ illegalaccessexception.getMessage());
} catch (InstantiationException instantiationexception) {
logger.error("DistributionListUtils -> Exception while setting provide for ssl. InstantiationException: "
+ instantiationexception.getMessage());
}
}

}

private DirContext getDirContext(String pLdapHost, String pLdapPort,
String pAdminID, String pAdminPassword,
boolean pUseSSL) {
DirContext ctx = null;
String providerurl = pLdapHost + ":" + pLdapPort;
if (pLdapPort == "") {
pLdapPort = "636";
}
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, providerurl);
if (pUseSSL == true) {
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, pAdminID);
env.put(Context.SECURITY_CREDENTIALS, pAdminPassword);

ctx = new InitialDirContext(env);
} catch (Exception ex) {
ex.printStackTrace();
}
return ctx;
}

private DirContext getDirContext() {
DirContext ctx = null;
try {
if (mUseSSL = true) {
ctx = getDirContext("ldaps://" + mLdapHost, mLdapPort,
mAdminID, mAdminPassword, true);
} else {
ctx = getDirContext("ldap://" + mLdapHost, mLdapPort, mAdminID,
mAdminPassword, false);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return ctx;
}

/**
* Close the directory context of the LDAP server.
*
*/
protected void closeContext(DirContext ctx) {
try {
if (ctx != null) {
ctx.close();
}
} catch (NamingException e) {
logger.warn("DirContext.close failed", e);
}
}

public String assignDistributionList(String pDepartmentID, String pUserId,
String pCompany) throws Exception {

String rtnval = "EXECUTION_SUCCESS";
String tempDepartmentID = new String(pDepartmentID);
if (this.isEmptyString(pDepartmentID)) {
tempDepartmentID = (pCompany.equalsIgnoreCase("BHATIACORP"))
? new String("0000")
: new String("0000-CON");
}

String groupName = "CN="+ tempDepartmentID;
String groupDN = groupName + "," + this.mLdapDistributionListLocation;

//check if group Exists.
Vector groupSearchResult = this.search("(&(objectclass=group)("+groupName+"))");
if(groupSearchResult.isEmpty()){
createGroup(groupDN, pCompany);
}

Vector memberList = getSepcifiedGroupAttributeValue(groupName, "member");
if(memberList == null)
memberList = new Vector();
for(int i = 0; i < memberList.size(); i++){
String member = (String)memberList.elementAt(i);
member = member.toUpperCase();
memberList.setElementAt(member, i);
}

String userDN = getUserDN(pUserId);
if(!memberList.contains(userDN)){
addUserToGroup(userDN, groupDN);
}

return rtnval;
}


public boolean addUserToGroup(String userDN, String groupDN) throws Exception{
DirContext dirCtx = null;
try{
BasicAttributes basicattributes = new BasicAttributes(true);
basicattributes.put(new BasicAttribute("member", userDN));
dirCtx = getDirContext();
dirCtx.modifyAttributes(groupDN,dirCtx.ADD_ATTRIBUTE, basicattributes);
return true;
}catch(Exception exp){
throw exp;
}finally{
this.closeContext(dirCtx);
}
}



public boolean removeUserToGroup(String userDN, String groupDN) throws Exception{
DirContext dirCtx = null;
try{
BasicAttributes basicattributes = new BasicAttributes(true);
basicattributes.put(new BasicAttribute("member", userDN));
dirCtx = getDirContext();
dirCtx.modifyAttributes(groupDN,dirCtx.REMOVE_ATTRIBUTE, basicattributes);
return true;
}catch(Exception exp){
throw exp;
}finally{
this.closeContext(dirCtx);
}
}

public boolean createGroup(String pGroupName, String companyName) throws Exception{
try{
String defaultGroupMemberShip = null;
double groupType = 0D;
String groupName = new String(pGroupName);
if(companyName.equalsIgnoreCase("BHATIACORP")){
defaultGroupMemberShip = "CN=ALL-BCORP-STAFF" +"," + this.mLdapDistributionListLocation;
groupType = DistributionListUtils.SECURITY_GROUP_GLOBAL;
}else{
defaultGroupMemberShip = "CN=ALL-NON-BCORP-STAFF" +"," + this.mLdapDistributionListLocation;
groupName = groupName.concat("-CON");
groupType = DistributionListUtils.DISTRIBUTION_GROUP_GLOBAL;
}
Double groupTypeDouble = new Double(groupType);
String groupTypeDoubleStr = Integer.toString(groupTypeDouble.intValue());
return createGroup(pGroupName, groupTypeDoubleStr, defaultGroupMemberShip );
}catch(Exception exp){
throw exp;
}
}

public boolean createGroup(String groupName, String groupType, String defaultGroupMembership) throws Exception{
DirContext dirCtx = null;
try{
dirCtx = getDirContext();
BasicAttributes basicattributes = new BasicAttributes(true);
basicattributes.put(new BasicAttribute("objectclass", "group"));
basicattributes.put(new BasicAttribute("cn", groupName));
basicattributes.put(new BasicAttribute("sAMAccountName", groupName));
basicattributes.put(new BasicAttribute("groupType", groupType));
basicattributes.put(new BasicAttribute("memberOf", defaultGroupMembership));
dirCtx.createSubcontext(groupName, basicattributes);
return true;
}catch(Exception exp){
throw exp;
}finally{
this.closeContext(dirCtx);
}
}

private String getUserDN(String pUserId) throws Exception{
DirContext dirCtx = null;
try{
String userId = "CN="+ pUserId;
dirCtx = getDirContext();
Vector searchResults = search("("+userId+ ")");
if(searchResults.isEmpty())return null;
String userDNValue = (String)searchResults.get(0);
String userDN = userDNValue + "," + this.mRootContext;
return new String(userDN.toUpperCase());
}catch(Exception exp){
throw exp;
}finally{
this.closeContext(dirCtx);
}
}


public Vector getSepcifiedGroupAttributeValue(String groupName, String lookfor) throws Exception{
DirContext dirCtx = getDirContext();
try{
String[] attributes = {lookfor};
Vector searchResults = search("("+groupName+ ")", attributes);
SearchResult searchResult = (SearchResult)searchResults.get(0);
Attributes searchResultAttributes = searchResult.getAttributes();
Attribute attr = searchResultAttributes.get(lookfor);
Vector attrVector = new Vector(attr.size());
for(int i=0; i< attr.size(); i++){
String value = new String(attr.get(i).toString());
attrVector.add(value.toUpperCase());
}
closeContext(dirCtx);
return attrVector;
}catch(Exception exp){
throw exp;
}finally{
this.closeContext(dirCtx);
}
}

public Vector search(String filter) throws Exception{
DirContext ctx = null;
try{
ctx = getDirContext();
SearchControls searchcontrols = new SearchControls();
searchcontrols.setSearchScope(2);
SearchResult searchresult;
NamingEnumeration namingenumeration = ctx.search(this.mRootContext, filter, searchcontrols);
Vector vector = new Vector();
for(;namingenumeration.hasMoreElements();vector.addElement(searchresult.getName())){
searchresult = (SearchResult)namingenumeration.nextElement();
searchresult.setRelative(false);
}
return vector;
}catch(Exception exception){
logger.error("Error during search : " + exception);
}finally{
closeContext(ctx);
}
return null;
}

public Vector search(String filter, String[] retAttr) throws Exception{
DirContext ctx = null;
try{
ctx = getDirContext();
SearchControls searchcontrols = new SearchControls();
searchcontrols.setSearchScope(2);
if(retAttr != null)
searchcontrols.setReturningAttributes(retAttr);
SearchResult searchresult;
NamingEnumeration namingenumeration = ctx.search(this.mRootContext, filter, searchcontrols);
Vector vector = new Vector();
for(;namingenumeration.hasMoreElements();vector.addElement(searchresult)){
searchresult = (SearchResult)namingenumeration.nextElement();
searchresult.setRelative(false);
}
return vector;
}catch(Exception exception){
logger.error("Error during search : " + exception);
}finally{
closeContext(ctx);
}
return null;
}

public String getLookupCodeValue(String lookupName, String valueToLookFor, tcDataProvider tcdataprovider)
throws Exception{
lookIntf = (tcLookupOperationsIntf)tcUtilityFactory.getUtility(tcdataprovider, "Thor.API.Operations.tcLookupOperationsIntf");
tcResultSet tcresultset = lookIntf.getLookupValues(lookupName);
int i = tcresultset.getRowCount();
for(int j = 0; j < i; j++){
tcresultset.goToRow(j);
if(valueToLookFor.equalsIgnoreCase(tcresultset.getStringValue(lookupDecodeKeyCol)))
return tcresultset.getStringValue(lookupCodeKeyCol);
}
return "";
}

/**
* Return true if the given string is empty.
*/
public final boolean isEmptyString(String toCheck) {
if ((toCheck != null) && (toCheck.trim().length() > 0)) {
return false;
}
return true;
}

/**
* Return true if the given object is null.
*/
public final boolean isNull(Object toCheck) {
return (toCheck == null);
}

}//end of class DistributionListUtils


courtesy:Rajesh Mittal

LdapOperations

You may use the following code to create quick ldap assisting functions:
==========================================
LdapOperations.java
==========================================

package com.bhatiacorp.operations;

import java.util.Hashtable;

import javax.naming.*;
import javax.naming.directory.*;

import com.thortech.util.logging.Logger;

public class LdapOperations {

private String loggerTag;
private Logger logger;
private String CLASS_NAME;
private String ldapHost;
private String ldapPort;
private String adminID;
private String adminPassword;
boolean useSSL;

public LdapOperations(String ldapHost, String ldapPort, String adminID, String adminPassword, boolean useSSL){
this.ldapHost = ldapHost;
this.ldapPort = ldapPort;
this.adminID = adminID;
this.adminPassword = adminPassword;
this.useSSL = useSSL;
loggerTag = "XL_INTG.BHATIACORP_LDAPOPERATIONS";
logger = Logger.getLogger(loggerTag);
CLASS_NAME = getClass().getName();

logger.info(" server name = " + ldapHost );
logger.info(" server port = " + ldapPort );
logger.info("adminId = " + adminID);
logger.info(" useSSL = " + useSSL );
}


private DirContext getContext(String ldaphost, String ldapport, String adminID, String adminpassword, boolean useSSL)
{
DirContext ctx=null;
String providerurl=ldaphost+":"+ldapport;
if(ldapport=="")
{
ldapport="636";
}
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY ,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL ,providerurl);
if(useSSL==true)
{
// if SSL is used - use can use ssl enabled ldaphost
// eg. "ldaps://localhost:636"
// else
// eg. "ldap://localhost:636"
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
env.put(Context.SECURITY_AUTHENTICATION ,"simple");
env.put(Context.SECURITY_PRINCIPAL ,adminID);
env.put(Context.SECURITY_CREDENTIALS ,adminpassword);
ctx = new InitialDirContext(env);

}
catch(Exception ex)
{
ex.printStackTrace();
}
return ctx;
}

private DirContext getContext()
{
DirContext ctx=null;
try {
ctx=getContext("ldap://"+ldapHost,ldapPort,adminID,adminPassword,useSSL);
}
catch(Exception ex)
{
ex.printStackTrace();
}

return ctx;
}


/**
* @param cn
* @param attribute
* @param value
* @return
*/
public String addAttribute(String cn,String attribute, String newvalue) throws NamingException{
String rtnval="EXECUTION_SUCCESS";
DirContext ctx= null;
try{
ctx=getContext();
ModificationItem[] mods = new ModificationItem[1];
mods[0]=new ModificationItem(DirContext.ADD_ATTRIBUTE,new BasicAttribute(attribute,newvalue));
ctx.modifyAttributes(cn, mods);

}catch(Exception ex){
rtnval="ERROR: "+ex.getMessage();
ex.printStackTrace();
}finally{
ctx.close();
}
return rtnval;
}

/**
* @param cn
* @param attribute
* @param value
* @return
*/
public String modifyAttribute(String userId,String attribute, String newvalue) throws NamingException{
String rtnval="EXECUTION_SUCCESS";
DirContext ctx= null;
try{
System.out.println();
ModificationItem[] mods = new ModificationItem[1];
ctx=getContext();
mods[0]=new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(attribute,newvalue));
ctx.modifyAttributes("cn="+userId, mods);
}catch(Exception ex){
rtnval="ERROR: "+ex.getMessage();
ex.printStackTrace();
}finally{
ctx.close();
}
return rtnval;
}

/**
* @param cn
* @param attribute
* @param value
* @return
*/
public String modifyAttributeWithOutFullDN(String userId,String directoryRootNode, String attribute, String newvalue) throws NamingException{
String rtnval="EXECUTION_SUCCESS";

DirContext ctx= null;
try
{
ctx=getContext();
logger.info(" userId = " + userId );
ModificationItem[] mods = new ModificationItem[1];
String userDN=searchFullDn(directoryRootNode, "cn=" + userId);
logger.info(" user full dn = " + userDN );
logger.info(" attr name = " + attribute + " value = " + newvalue);
mods[0]=new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(attribute,newvalue));
ctx.modifyAttributes(userDN, mods);

logger.info(" update was done successfully ");
}catch(Exception ex){
rtnval="ERROR: "+ex.getMessage();
ex.printStackTrace();
}finally{
ctx.close();
}
return rtnval;
}

/*
public void printAttributes(Attributes attrs)
{
try
{
for (NamingEnumeration ae = attrs.getAll(); ae.hasMore();) {
Attribute attr = (Attribute)ae.next();
System.out.println("attribute: " + attr.getID());
for (NamingEnumeration e = attr.getAll(); e.hasMore();
System.out.println("value: " + e.next()));
}}catch(Exception ex)
{
ex.printStackTrace();
}

}
*/

/**
* @param cn
* @param attribute
* @param value
* @return
*/
public String deleteAttribute(String cn,String attribute, String newvalue) throws NamingException{
String rtnval="EXECUTION_SUCCESS";
ModificationItem[] mods = new ModificationItem[1];
try
{
DirContext ctx=getContext();
mods[0]=new ModificationItem(DirContext.REMOVE_ATTRIBUTE,new BasicAttribute(attribute,newvalue));
ctx.modifyAttributes(cn, mods);
}
catch(Exception ex)
{
rtnval="ERROR: "+ex.getMessage();
ex.printStackTrace();
}
return rtnval;
}


public String setADManagerInfo(String userId,String directoryRootNode, String mgrEmployeeId) throws NamingException{
String rtnval="EXECUTION_SUCCESS";

DirContext ctx= null;
try
{
ctx=getContext();
logger.info(" userId = " + userId );
logger.info(" manager employee id = " + mgrEmployeeId);
ModificationItem[] mods = new ModificationItem[1];
String userDN=searchFullDn(directoryRootNode, "cn=" + userId);
logger.info(" Manager DN to be searched is = " + "(|(extensionAttribute1=" + mgrEmployeeId+ ")(cn="+ mgrEmployeeId+ "))");
String managerDN = searchFullDn(directoryRootNode, "(|(extensionAttribute1=" + mgrEmployeeId+ ")(cn="+ mgrEmployeeId+ "))" );
if(this.isEmptyString(managerDN)){
return "EXECUTION_FAILURE_MANAGER_DOESN'T_EXISTS";
}
logger.info(" user full dn = " + userDN );
logger.info(" attr name is manager value = " + managerDN);
mods[0]=new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("manager", managerDN));
ctx.modifyAttributes(userDN, mods);

logger.info(" update was done successfully ");
}catch(Exception ex){
rtnval="ERROR: "+ex.getMessage();
}finally{
ctx.close();
}
return rtnval;
}


/**
* @param directoryRootNode
* @param nameToSearch
* @return
*/
public String searchFullDn(String directoryRootNode,String nameToSearch){
try
{
SearchControls searchControls = new SearchControls (SearchControls.SUBTREE_SCOPE, 1, 0, new String[0], true, false);
NamingEnumeration srchResults = getContext().search(directoryRootNode, "(&("+nameToSearch+")(objectclass=*))",searchControls);
if (srchResults.hasMore())
{
SearchResult sr = (SearchResult)srchResults.next();
return sr.getName().toString()+","+directoryRootNode;
}
} catch (NamingException e){
e.printStackTrace();
}
return "";
}

/**
*
* @param cnvalue
* @param fname
* @param lname
* @param treevalue
* @return
*/
public String createUser(String cnvalue, String fname, String lname, String treevalue){
String rtnval="EXECUTION_SUCCESS";
String treenodevalue="ou=People,dc=bhatiacorp,dc=com";
if(treevalue!="")
treenodevalue=treevalue;
try {
BasicAttributes attrs = new BasicAttributes();
BasicAttribute ocs = new BasicAttribute("objectClass");
ocs.add("top");
ocs.add("person");
ocs.add("organizationalPerson");
//Add whichever classes apply in your case
attrs.put(ocs);
attrs.put(new BasicAttribute("cn" , cnvalue));
attrs.put(new BasicAttribute("sn" , lname));
attrs.put(new BasicAttribute("displayName" , fname+" "+ lname));
String fulldn="cn="+cnvalue+","+treenodevalue;
getContext().createSubcontext(fulldn, attrs);
}
catch (Exception ex) {
rtnval="ERROR: "+ex.getMessage();
ex.printStackTrace();
}

return rtnval;
}

/**
*
* @param cnvalue
* @return
*/
public String deleteUser(String cnvalue)
{
String rtnval="EXECUTION_SUCCESS";
String dn=searchFullDn("dc=bhatiacorp,dc=com", cnvalue);
try {
getContext().destroySubcontext(dn);
}
catch (Exception ex) {
rtnval="ERROR: "+ex.getMessage();
ex.printStackTrace();
}

return rtnval;

}


/**
* Return true if the given string is empty.
*/
public final boolean isEmptyString(String toCheck) {
if ((toCheck != null) && (toCheck.trim().length() > 0)) {
return false;
}
return true;
}

/**
* Return true if the given object is null.
*/
public final boolean isNull(Object toCheck) {
return (toCheck == null);
}

/**
*
* @param cn
* @param domain
* @param NewOU
* @return
*/
public String moveUser2NewOU(String cn, String domain,String NewOU){
String rtnval="EXECUTION_SUCCESS";
try {
DirContext ctx=getContext();
String OldCN="CN="+cn+",CN=Users,"+domain;
System.out.println("Old CN:"+OldCN);
String NewCN="CN="+cn+",OU="+NewOU+","+domain;
System.out.println("New CN:"+NewCN);
System.out.println("Starting Modify DN ");
ctx.rename(OldCN, NewCN);
System.out.println("Ended Modify DN with Success..."+rtnval);
//ctx.rename("CN=Rajnish Bhatia,OU=HR,dc=bhatiacorp,dc=com", "CN=Rajnish Bhatia,OU=IT,dc=bhatiacorp,dc=com");
//System.out.println(ctx.lookup("CN=Rajnish Bhatia,OU=IT,dc=bhatiacorp,dc=com"));
ctx.close();
} catch (Exception e) {
System.out.println("Ended Modify DN with Error...");
rtnval="ERROR : "+e.getMessage();
e.printStackTrace();
}
return rtnval;
}

/**
* @param args
*/
public static void main(String[] args) {
try
{
LdapOperations c=new LdapOperations();
//System.out.println(c.createUser("AB","ABtest","test","ou=People,dc=bhatiacorp,dc=com"));
System.out.println(c.modifyAttribute("cn=AB,ou=People,dc=bhatiacorp,dc=com", "extensionAttribute12", "12-12-1999"));
//System.out.println(c.searchFullDn("dc=bhatiacorp,dc=com","cn=AB"));
//System.out.println(c.deleteUser("cn=AB"));
}catch(Exception ex)
{
ex.printStackTrace();
}
}
}

Monday, March 31, 2008

Problem with AD Connector updating City, State with literal text

The Problem:
When a user is created in AD (using out of the box OIM connector 9041), all values for city, state etc change in AD to be literally "city", "state" etc. instead of correct values supplied via AD User Provisioning form (even with prepop).

The Resolution:
There is a task in AD called Set Exchange Related Properties in Exchange Provisioning Definition. This task has a literal value for all the AD fields like "city", "state". Either make this task conditional or map these values from Xellerate User City / State UDFs.

Wednesday, March 19, 2008

AD Child Domain Referral Searches

If your ldp tool fails to find users / groups from other child / brother domains due to referral issues, use the following method to override the search criteria.

First create an account with Enterprise Admin rights over the full root domain. Once the rights are properly given, in ldp tool, set connection options to add LDAP_OPT_REFERRALS to 1 (after binding with this enterprise admin user) and then retry your search.

Add cross reference of trusted domain. You may use the following Microsoft support link as a reference:
http://support.microsoft.com/kb/241737

If you are coding, add this statement to make it work:
env.put( Context.REFERRAL, "follow" );

Here is the sample code:

import javax.naming.ldap.*;
import javax.naming.directory.*;
import javax.naming.*;
import javax.naming.directory.BasicAttributes;
import java.util.Properties;

public class test {
public static void main(String[] args) {

Properties env = new Properties();

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389");
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.REFERRAL, "follow" );
env.put(Context.SECURITY_PRINCIPAL, "Rajnish");
env.put(Context.SECURITY_CREDENTIALS, "Bhatia01");

try {
LdapContext context = new InitialLdapContext(env, null);
String base = "DC=nj,DC=bhatiacorp,DC=com";
String filter = "(&(objectClass=group)(CN=rajadmin))";

SearchControls controls = new SearchControls();

String []strReturningAttr = {"member"};

controls.setReturningAttributes(strReturningAttr);
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

NamingEnumeration answer = context.search(base, filter, controls);
int totalResults = 0;
String strMember ;
BasicAttributes userattrs;

// ... process attributes ...
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult)answer.next();

System.out.println(">>>" + sr.getName());

//Print out the groups

Attributes attrs = sr.getAttributes();

if (attrs != null) {

try {
for (NamingEnumeration ae = attrs.getAll();ae.hasMore();) {
Attribute attr = (Attribute)ae.next();
System.out.println("Attribute: " + attr.getID());
for (NamingEnumeration e = attr.getAll();e.hasMore();totalResults++) {

strMember = (String) e.next();
System.out.println(" " + totalResults + ". " + strMember);
userattrs = (BasicAttributes)context.getAttributes(strMember);


}

}

}
catch (NamingException e) {
System.err.println("Problem listing membership: " + e);
}

}
}
System.out.println("TotalResults " + totalResults );
}
catch (NamingException e) {
System.out.println("Problem retrieving RootDSE: " + e);
}
}
}

Monday, March 17, 2008

AD Move User to New OU

The Active Directory Connector by default creates users in CN=Users. Oftentimes, you need to move user to another ou based on some logic, for example based of location. So, here I present you with a code snippet that you can use to move user to another ou and attach it to create user "Success" response code in AD Provisioining process.

import javax.naming.*;
import javax.naming.directory.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import Thor.API.Exceptions.tcAPIException;
import Thor.API.tcResultSet;
import Thor.API.tcUtilityFactory;
import Thor.API.Base.tcUtilityOperationsIntf;
import Thor.API.Operations.tcUserOperationsIntf;

import com.thortech.util.logging.Logger;
import java.util.Hashtable;
public class MoveUserToOU {
public Logger logger;

public String MoveUser2NewOU(String cn, String ADServer, String domain,String Location, String AdminID, String Password){
String rtnval="EXECUTION_SUCCESS";
if (Location.equalsIgnoreCase(""))
{
return rtnval;
}
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.PROVIDER_URL, "ldaps://"+ADServer+":636/");
//AdminID="Administrator@bhatia.com"
env.put(Context.SECURITY_PRINCIPAL, AdminID);
//Password="Password1";
env.put(Context.SECURITY_CREDENTIALS, Password);
try {
DirContext ctx = new InitialDirContext(env);
String OldCN="CN="+cn+",OU=Users,OU=OTHR,"+domain;
logger.debug("Old CN:"+OldCN);
String NewCN="CN="+cn+",OU=Users,OU="+getNewOU(Location)+","+domain;
logger.debug("New CN:"+NewCN);
logger.debug("Starting Modify DN ");
ctx.rename(OldCN, NewCN);
logger.debug("Ended Modify DN with Success..."+rtnval);
//ctx.rename("CN=Rajnish Bhatia,OU=HR,dc=bhatia,dc=com", "CN=Rajnish Bhatia,OU=IT,dc=bhatia,dc=com");
//System.out.println(ctx.lookup("CN=Rajnish Bhatia,OU=IT,dc=bhatia,dc=com"));
ctx.close();
} catch (Exception e) {
logger.debug("Ended Modify DN with Error...");
rtnval="ERROR : "+e.getMessage();
e.printStackTrace();
}
return rtnval;
}

public String getNewOU(String Location) {
String NewOU="";
if(Location.equalsIgnoreCase("CA"))
NewOU="CA";
else
if(Location.equalsIgnoreCase("TN"))
NewOU="TN";
else
if(Location.equalsIgnoreCase("NJ"))
NewOU="NJ";
else
if(Location.equalsIgnoreCase("TX"))
NewOU="TX";
return NewOU;
}
}

Active Directory SSL Test

You may use this code to test the SSL connection with your AD server.

=====================================================
ADSSLConnectionTest.java
=====================================================

import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
public class ADSSLConnectionTest
{

private DirContext getContext(String ldaphost, String ldapport, String adminID, String adminpassword, boolean useSSL)
{
DirContext ctx=null;
String providerurl=ldaphost+":"+ldapport;
if(ldapport=="")
{
ldapport="636";
}
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY ,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL ,providerurl);
if(useSSL==true)
{
// if SSL is used - use can use ssl enabled ldaphost
// eg. "ldaps://localhost:636"
// else
// eg. "ldap://localhost:636"
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
env.put(Context.SECURITY_AUTHENTICATION ,"simple");
env.put(Context.SECURITY_PRINCIPAL ,adminID);
env.put(Context.SECURITY_CREDENTIALS ,adminpassword);
ctx = new InitialDirContext(env);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return ctx;
}

public DirContext getContext()
{
DirContext ctx=null;
try {
ctx=getContext("ldaps://localhost","636","CN=Rajnish Bhatia,DC=bhatia,DC=com","Password1",true);
System.out.println("Connected with SSL");
}
catch(Exception ex)
{
System.out.println("NOT Connected with SSL");
ex.printStackTrace();
}
return ctx;
}

public static void main(String[] args) {
try
{
ADSSLConnectionTest c = new ADSSLConnectionTest();
c.getContext();
}catch(Exception ex)
{
ex.printStackTrace();
}
}
}

Compile and run with your credentials as following:

C:\>javac ADSSLConnectionTest.java

C:\>java ADSSLConnectionTest

=============================
Notes
=============================

1. If you have issues, make sure your SSL Certificate is in proper java store such as C:\j2sdk1.4.2_13\jre\lib\security. Make sure you are adding the certificate to the correct (& in path) java cacerts keystore.

2. You may also test by telnet to the server - telnet localhost 636

3. You may list the keystore values as follows:
C:\j2sdk1.4.2_13\jre\lib\security>keytool -list -v -storepass changeit -keystore cacerts

This is how it looks:


*******************************************
*******************************************


Alias name: someclass3g3ca
Creation date: Jun 15, 2004
Entry type: trustedCertEntry

Owner: CN=Some Authority, OU="(c)
1999 Bhatia, Inc. - For authorized use only", OU=Bhatia Trust Network, O="Bhatia, Inc.", C=US
Issuer: CN=Some Authority, OU="(c)
1999 Bhatia, Inc. - For authorized use only", OU=Bhatia Trust Network, O="Bhatia, Inc.", C=US
Serial number: 9b7e0649a33e62b9d5ee90487129ef53
Valid from: Thu Sep 30 20:00:00 EDT 1999 until: Wed Jul 16 19:59:59 EDT 2036
Certificate fingerprints:
MD5: CD:68:B6:A7:C7:C4:CE:75:E0:1D:2F:57:44:61:92:09
SHA1: 13:2D:0D:45:53:4B:69:97:CD:B2:D6:C3:39:E2:55:76:60:9B:5C:C6


*******************************************
*******************************************

Alias name: corp9
Creation date: Mar 17, 2008
Entry type: trustedCertEntry

Owner: CN=srvr-corp9.nj.bhatia.com
Issuer: CN=SRVR-RAS-DC, DC=bhatia, DC=com
Serial number: 2714a16c000000000013
Valid from: Mon Jan 28 12:14:58 CST 2008 until: Tue Jan 27 12:14:58 CST 2009
Certificate fingerprints:
MD5: CD:48:B6:A7:C7:C4:CE:75:E0:1D:2F:57:44:61:92:09
SHA1: 12:1D:0D:45:52:4B:64:97:CD:B2:D6:C3:39:E2:55:76:60:9B:5C:C6


*******************************************
*******************************************

4. Then, make sure your ADITResource in OIM - The server is srvr-corp9.nj.bhatia.com (as per your keystore).

5. For specific ldap error codes, look at the following url:
http://www.directory-info.com/LDAP/LDAPErrorCodes.html

Wednesday, February 6, 2008

Propagating Changes to target sources

If you ever need to Propagate the changes to the target systems by change from the source system in OIM, do the following steps. In the following example, I am transmitting the first name change to Active Directory whenever a change occurs in Xellerate User profile.

1. Create an process task adapter that will copy & return the same string back as an adapter return value.
2. Go to Active Directory Provisioning Process definition.
3. Create / Modify Change First Name process task. Map the adapter created in Step 1 with Xellerate User First Name as the source string and adapter return variable to Process Form First Name.
4. Create / re-verify that First Name Updated task is present on AD Provisioning Process definition that propogates the attribute update on AD. That should be it !!