I have configured ADDC on windows server 2012 R2 and I have added two users into DC - one is windows 8 and another one is ubuntu.
Windows server 2012 username - DC
Windows 8.1 username - Win
Ubuntu username - Linux
I am trying to achieve this - I want to write java program in ubuntu, that will connect to ADDC and sends back, detailed user information on windows 8.1
My program is like -
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class LdapSearch {
public static void main(String[] args) throws Exception {
Hashtable env = new Hashtable();
String sp = "com.sun.jndi.ldap.LdapCtxFactory";
env.put(Context.INITIAL_CONTEXT_FACTORY, sp);
String ldapUrl = "ldap://server.com, dc=com";
env.put(Context.PROVIDER_URL, ldapUrl);
DirContext dctx = new InitialDirContext(env);
String base = "ou=name";
SearchControls sc = new SearchControls();
String[] attributeFilter = { "cn", "mail" };
sc.setReturningAttributes(attributeFilter);
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(sn=W*)(l=Criteria*))";
NamingEnumeration results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
Attribute attr = attrs.get("cn");
System.out.print(attr.get() + ": ");
attr = attrs.get("mail");
System.out.println(attr.get());
}
dctx.close();
}
I am referring to above program and trying to achieve connection to AD through LDAP java. I dont know how to get ou, cn, etc.. I am very much new to the concepts of LDAP, ADDC.
Any idea on this? Please let me know.
Thanks,
saurabh
I've done a similar scenario in C# so am not sure about the connection settings in Java but as for similarities you should create a directory entry for the LDAP and provide the path, user name and password of authorized user who can access the active directory, i didnt provide DC in the path just the LDAP path and then the query filter parameters that searched based upon user first name was
Filter = "(& (SAMAccountName=" + name + ") (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*))) ))";
then it would provide you with an result in an arraylist like object so you would query the rest of information you like by just providing the attribute name, you would find a list of LDAP attributes here
LDAP attributes
Related
we required to fetch all user of dynamic group from LDAP server in Our Java based application.
below is my dynamic group url:
ldap:///ou=testou,o=test.com??sub?(&(|(atype=*Abc Company*)(atype=*def Company*)(ctype=test))(enabled=1)(!(sgroup=*testgrp*))(!(|(op=ABC)(bdesc=*abcdef*))))
when i provided filter from above url in JXplore, i am able to get user group which is available in this dynamic group but when i provide same filter in below java code LDAP is not returning any result. If i provided simple filter like cn=a* then it is working and LDAP is returning results.
public static void main(String[] args) throws NamingException, IOException {
Properties env = new Properties();
env.put("java.naming.factory.initial",
"com.sun.jndi.ldap.LdapCtxFactory");
// LDAP url
env.put("java.naming.provider.url", "url");
env.put("com.sun.jndi.ldap.read.timeout", "1000");
// ldap login
env.put("java.naming.security.principal", "username");
env.put("java.naming.security.credentials", "password");
InitialLdapContext ctx = new InitialLdapContext(env, null);
String contextName = "ou=testou,o=test.com";
// Filter expression
String filterExpr = "(&(|(atype=*Abc Company*)(atype=*def Company*)(ctype=test))(enabled=1)(!(sgroup=*testgrp*))(!(|(op=ABC)(bdesc=*abcdef*))))"; // selects the groups a user belongs to.
SearchControls constraints = new javax.naming.directory.SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); // SUBTREE_SCOPE means recursive search
ctx.setRequestControls(new Control[]{new PagedResultsControl(1000,true)});
byte[] cookie = null;
int totalResults = 0;
NamingEnumeration<SearchResult> search = ctx.search(contextName,
filterExpr,constraints);
int count=0;
while (search.hasMoreElements()) {
count++;
System.out.println(search.next().getName());
}
System.out.println("Total user"+count);
}
Assuming you are talking about JNDI, sadly the JNDI Tutorial, p. 247, says:
Note: Version 1.2 of Sun's LDAP provider does not treat query components properly
and nothing appears to have changed in any release up to Java 8.
The Dynamic Groups feature relies on this.
i am writing an OpenLdap controller, where i have a lot of ldap functions. One function is to get a LdapUser and his different attributes.
For example:
NamingEnumeration<SearchResult> enumResult = null;
UserData ldapUser = new UserData();
private String[] user_attributes = new String[]{"uid","cn", "sn", "dn", "description", "mail", "displayName",
"userPassword","pwdChangedTime","pwdExpires", "lastLogonTime"};
try
{
SearchControls searchCtrls = new SearchControls();
searchCtrls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchCtrls.setReturningAttributes(user_attributes);
String filter = "(&(objectClass=inetOrgPerson)(uid="+userUid+"))";
enumResult = ctx.search(ou,filter,searchCtrls);
SearchResult result = (SearchResult) enumResult.next();
ldapUser.setUid(getAttribute(result,"uid"));
ldapUser.setCN(getAttribute(result, "cn"));
ldapUser.setSN(getAttribute(result, "sn"));
ldapUser.setGivenName(getAttribute(result, "givenName"));
ldapUser.setDescription(getAttribute(result, "description"));
ldapUser.setMail(getAttribute(result, "mail"));
}
That works fine. I have my ldapUser class fullfilled with the attributes. I did the same for a TDS Controller before, and there i could use even the following attributes:
ldapUser.setPassword(getAttribute(result, "userPassword"));
ldapUser.setpwdExpires(getAttribute(result,"pwdExpires"));
ldapUser.setpwdChangedTime(getAttribute(result, "pwdChangedTime"));
ldapUser.setlastLogonTime(getAttribute(result,"lastLogonTime"));
But it seems this doesn't work for OpenLdap anymore. Does anyone know or has a solution for getting these password attributes in java from OpenLdap?
Best regards
The "password" is most likely either a hash of the real password or an encrypted version.
Source: How to retrieve LDAP password via JNDI
See also http://bethecoder.com/applications/tutorials/java/ldap/how-to-query-password-attribute-of-ldap-entry.html
I'm attempting to update a password via a portlet in Quercus using java libraries. Here is some of the code that I'm using:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.SearchControls;
import javax.sql.DataSource;
import java.util.Hashtable;
$uname = isset($_POST['uname'])?$_POST['uname']:'';
$pass1 = isset($_POST['pass1'])?$_POST['pass1']:'';
//connecto to LDAP
$ldapADURL = "ldaps://poplar.example.edu:636";
$ldapEnv = new HashTable();
$ldapEnv->put("java.naming.factory.initial","com.sun.jndi.ldap.LdapCtxFactory");
$ldapEnv->put("java.naming.provider.url", $ldapADURL);
$ldapEnv->put("java.naming.security.protocal", "ssl");
$ldapEnv->put("java.naming.referral", "follow");
$ldapEnv->put("java.naming.security.authentication", "simple");
$ldapEnv->put("java.naming.security.principal", "ADUser");
$ldapEnv->put("java.naming.security.credentials", "P#ssw0rd");
$ADCtx = new InitialDirContext($ldapEnv);
//query the vault for our user
$ctlsAD = new SearchControls();
$attribsAD = array("sAMAccountName","DN","title","extensionAttribute14","extensionAttribute8","cn");
$ctlsAD->setReturningAttributes($attribsAD);
$ctlsAD->setSearchScope(2);
$filter="(sAMAccountName=" . $uname . ")";
$resultAD=$ADCtx->search("DC=conncoll,DC=edu",$filter,$ctlsAD);
if ($resultAD->hasMore()) {
$item = $resultAD->next();
$resultADAttribs = $item->getAttributes();
$rsTitle = str_replace("title: ","",$resultADAttribs->get("title"));
$rsAttrib14 = str_replace("extensionAttribute14: ","",$resultADAttribs->get("extensionAttribute14"));
$rsAttrib8 = str_replace("extensionAttribute8: ","",$resultADAttribs->get("extensionAttribute8"));
$rsUname = str_replace("sAMAccountName: ","",$resultADAttribs->get("sAMAccountName"));
$rsDN = str_replace("dn: ","",$resultADAttribs->get("DN"));
}
echo ( '<br />' . $rsTitle . '<br />' . $rsAttrib14 . '<br />' . $rsAttrib8 . '<br />' . $rsUname . '<br />' . $rsDN . '<br />');
if (isset($rsUname)/*ccLDAPCheckUser($uname)*/){
$ADCtx->addToEnvironment("java.naming.security.principal","OtherADUser");
$ADCtx->addToEnvironment("java.naming.security.credentials","0therP#ssw0rd");
//$resultAD2 = $ADCtx->search("DC=conncoll,DC=edu",$filter,$ctlsAD);
$pass2 = "\"" . $pass1 . "\"";
$newPass = mb_convert_encoding($pass2, "UTF-16LE");
$ADNewPass = new BasicAttribute("userpassword",$newPass);
$ADNewAttrib8 = new BasicAttribute("extensionAttribute8",$rsAttrib8);
$ADAttributes = new BasicAttributes();
$ADAttributes->put($ADNewPass);
$ADAttributes->put($ADNewAttrib8);
$ADCtx->modifyAttributes("sAMAccountName=" . $rsUname,2,$ADAttributes);
}
After running this code I get the following error from the LDAP server:
javax.naming.directory.InitialDirContext.modifyAttributes: [LDAP: error code 1 - 000020D6: SvcErr: DSID-031007DB, problem 5012 (DIR_ERROR), data 0 ]
So I'm wondering several things. The first is if I have the syntax of the modifyAttributes function call correct. I've tried it with dc=example,dc=edu tacked on to the query string to no success. The first query returns results correctly so I'm sure that I'm getting connected to the AD server and I've had someone verify that the JVM executing the code has a valid up-to-date certificate in its store.
The error makes me believe that I need the exact location specified for the object I'm attempting to update, which I don't have.
Thanks for your thoughts on the issue!
So I found part of my answer with getting the DN and using that instead of the sAMAccountName to issue a password reset.
I set $rsDN as follows:
$rsDN = $item->getNameInNamespace();
and issue the call to change the password as such:
$ADCtx->modifyAttributes($rsDN,2,$ADAttributes);
Now of course I'm getting SSL errors but I'm at least hitting the correct object with the update.
I would like to use JNDI to look up Kerberos SRV records in a local network. I try to guess the local domain in hopefully clever ways. If that fails I would like to look up the plain entry, e.g. _kerberos._tcp without any suffix and rely on the DNS domain search list to find the right entry. This works on Windows with nslookup -type=srv _kerberos._tcp and Linux with host -t srv _kerberos._tcp. The domain example.test is appended and the entry is found.
Here is an example program to do DNS lookups via JNDI:
import java.util.Hashtable;
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.DirContext;
import javax.naming.directory.InitialDirContext;
public class JndiDnsTest {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: " + JndiDnsTest.class.getName() +
" name record-types...");
return;
}
String name = args[0];
String[] recordTypes = new String[args.length - 1];
System.arraycopy(args, 1, recordTypes, 0, args.length - 1);
Hashtable<String, String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
try {
DirContext ctx = new InitialDirContext(env);
Attributes dnsQueryResult = ctx.getAttributes(name, recordTypes);
if (dnsQueryResult == null) {
System.out.println("Not found: '" + name + "'");
}
for (String rrType: recordTypes) {
Attribute rr = dnsQueryResult.get(rrType);
if (rr != null) {
for (NamingEnumeration<?> vals = rr.getAll(); vals.hasMoreElements();) {
System.out.print(rrType + "\t");
System.out.println(vals.nextElement());
}
}
}
} catch (NamingException e) {
e.printStackTrace(System.err);
}
System.out.println("\nThe DNS search list:");
for (Object entry: sun.net.dns.ResolverConfiguration.open().searchlist()) {
System.out.println(entry);
}
System.out.println("\nsun.net.spi.nameservice.domain = " +
System.getProperty("sun.net.spi.nameservice.domain"));
}
}
It appears to me that JNDI only does one lookup for the direct name. No entry is found where above commands succeed. It seems it does not use the DNS search list. Its contents are printed correctly at the bottom, though.
On the other hand the Networking properties documentation says that
If the sun.net.spi.nameservice.domain property is not defined then the provider will use any domain or domain search list configured in the platform DNS configuration.
(The property is not set.) The Java version is Sun Java 1.6.0_20.
Does JNDI use the DNS search list or not?
It's a known bug - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6427214
How can I list all the local users configured on a windows machine (Win2000+) using java.
I would prefer doing this with ought using any java 2 com bridges, or any other third party library if possible.
Preferable some native method to Java.
Using a Java-COM Bridge , like Jacob. You then select an appropriate COM library, e.g. COM API for WMI to list local users, or any other Windows management information.
The Win32_SystemUsers association WMI class relates a computer system and a user account on that system.
The Win32_Account abstract WMI class contains information about user accounts and group accounts known to the computer system running Windows. User or group names recognized by a Windows NT domain are descendants (or members) of this class.
Working Example (jacob 1.17-M2, javaSE-1.6):
import java.util.Enumeration;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.EnumVariant;
import com.jacob.com.Variant;
public class ComTst {
public static void main(String[] args) {
ComThread.InitMTA();
try {
ActiveXComponent wmi = new ActiveXComponent("winmgmts:\\\\.");
Variant instances = wmi.invoke("InstancesOf", "Win32_SystemUsers");
Enumeration<Variant> en = new EnumVariant(instances.getDispatch());
while (en.hasMoreElements())
{
ActiveXComponent bb = new ActiveXComponent(en.nextElement().getDispatch());
System.out.println(bb.getPropertyAsString("PartComponent"));
}
} finally {
ComThread.Release();
}
}
}
Using Java COM Object, i.e. Jacob:
public static void EnumerateUsers() {
String query = "SELECT * FROM Win32_UserAccount";
ActiveXComponent axWMI = new ActiveXComponent("winmgmts:\\");
Variant vCollection = axWMI.invoke("ExecQuery", new Variant(query));
EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());
Dispatch item = null;
StringBuilder sb = new StringBuilder();
while (enumVariant.hasMoreElements()) {
item = enumVariant.nextElement().toDispatch();
sb.append("User: " + Dispatch.call(item, "Name")).toString();
System.out.println(sb);
sb.setLength(0);
}
}
There is a simpler solution for what I needed.
This implementation will use the "net user" command to get the list of all users on a machine. This command has some formatting which in my case I don't care about, I only care if my user is in the list or not. If some one needs the actual user list, he can parse the output format of "net user" to extract the list without the junk headers and footers generated by "net use"
private boolean isUserPresent() {
//Load user list
ProcessBuilder processBuilder = new ProcessBuilder("net","user");
processBuilder.redirectErrorStream(true);
String output = runProcessAndReturnOutput(processBuilder);
//Check if user is in list
//We assume the output to be a list of users with the net user
//Remove long space sequences
output = output.replaceAll("\\s+", " ").toLowerCase();
//Locate user name in resulting list
String[] tokens = output.split(" ");
Arrays.sort(tokens);
if (Arrays.binarySearch(tokens, "SomeUserName".toLowerCase()) >= 0){
//We found the user name
return true;
}
return false;
}
The method runProcessAndReturnOutput runs the process, collects the stdout and stderr of the process and returns it to the caller.
import com.sun.jna.platform.win32.Netapi32Util;
Netapi32Util.User[] users = Netapi32Util.getUsers();
for(Netapi32Util.User user : users) {
System.out.println(user.name);
}