I am using one java program to retrieve user information from active directory. The program is working but it is passing data from one group only (search filter is defined as a string
String searchFilter ="CN=CostCentre_1041";)
How I can pass multiple groups in a program.
I have tried using array but not able to define it properly.
package Test.ad;
import java.util.Hashtable;
import java.util.Properties;
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;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class GetUsersFrormLDAPGroup {
static String ldapSearchBase = "DC=test,DC=edu,DC=com";
private static DirContext ctx = null;
private static DirContext getActiveDirectoryContext() throws Exception {
final Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
properties.put(Context.PROVIDER_URL, "ldap://testad:3268");
properties.put(Context.SECURITY_AUTHENTICATION, "simple");
properties.put(Context.SECURITY_PRINCIPAL, "admin");
properties.put(Context.SECURITY_CREDENTIALS, "test");
return new InitialDirContext(properties);
}
public void getGroupUsers(String searchBase, String searchFilter, String returnedAttrs[], int maxResults) {
Hashtable userEntries = null;
String member = "";
try {
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
searchCtls.setReturningAttributes(returnedAttrs);
ctx = getActiveDirectoryContext();
try {
System.out.println("Search Base: " + searchBase);
System.out.println("Search Filter: " + searchFilter);
NamingEnumeration users = ctx.search(searchBase, searchFilter, searchCtls);
if (users.hasMoreElements() == false) {
System.out.println("Not find any object with this filter " + searchFilter + " and searchBase " + searchBase);
}
int k = 0;
String attValue = "";
userEntries = new Hashtable();
while (users.hasMoreElements()) {
if (k >= maxResults)
break;
SearchResult sr = (SearchResult) users.next();
Attributes attrs = sr.getAttributes();
if (attrs.size() == 0) {
System.out.println("Could not find attribute " + returnedAttrs[0] + " for this object.");
} else {
try {
for (NamingEnumeration ae = attrs.getAll(); ae.hasMore(); ) {
Attribute attr = (Attribute) ae.next();
String id = attr.getID();
for (NamingEnumeration e = attr.getAll(); e.hasMore(); ) {
attValue = (String) e.next();
if (id.equalsIgnoreCase("member"))
member = attValue;
{
System.out.println("member :" + member);
}
//{
//System.out.println("empty");
// }
}
}
} catch (NamingException e) {
System.out.println("Problem listing membership:" + e);
}
}
k++;
}
} catch (NamingException e) {
System.out.println("Problem searching directory: " + e);
}
ctx.close();
ctx = null;
} catch (Exception namEx) {
System.out.println("Exception while fetching the users from LDAP::" + namEx);
}
}
public static void main(String args[]) throws Exception {
GetUsersFrormLDAPGroup gug = new GetUsersFrormLDAPGroup();
String returnedAttrs[] = {"cn", "member", "name"};
String searchFilter = "CN=CostCentre_1041";
gug.getGroupUsers(ldapSearchBase, searchFilter, returnedAttrs, Integer.parseInt("2000"));
}
}
You can either:
Call getGroupUsers() a second time with a different searchFilter to get the results for a different group:
String searchFilter = "CN=CostCentre_1041";
gug.getGroupUsers(ldapSearchBase, searchFilter, returnedAttrs, Integer.parseInt("2000"));
searchFilter = "CN=SNOW - EA DEV INTG";
gug.getGroupUsers(ldapSearchBase, searchFilter, returnedAttrs, Integer.parseInt("2000"));
Change your searchFilter to return both groups.
String searchFilter = "(|(CN=CostCentre_1041)(CN=SNOW - EA DEV INTG))";
gug.getGroupUsers(ldapSearchBase, searchFilter, returnedAttrs, Integer.parseInt("2000"));
I have developed java code using pl/sql for weblogic user creation.
The code is:
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "NewUserCreation31" AS
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBeanInfo;
import java.util.Locale;
import java.util.Hashtable;
import javax.naming.Context;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
public class NewUserCreation31
{
private static ObjectName defaultAuthenticator;
private static String authenticatorName="DefaultAuthenticator";
public static String username=null;
public static String password=null;
public static String user_role=null;
public static String retVal="exception";
public static String createWeblogicUser()
{
try {
Hashtable<String, String> env = new Hashtable<String, String>();
// Connection conn = null;
String url1 = "jdbc:oracle:thin:#191.169.151.13:1521:SER140";
String driver = "oracle.jdbc.driver.OracleDriver";
String userNm = "user1";
String psword = "password1";
Statement stmt=null;
String query=" select user_id,enc_dec.decrypt(passwd) pwd,user_priv from user_data";
try
{
retVal= "return 1";
username="uname1";
password="pwd123";
user_role="A";
retVal= "return all";
String user_grp =
(user_role.equals("A")) ? "A" :
(user_role.equals("P")) ? "P" :
(user_role.equals("PA")) ? "PA" :
(user_role.equals("R")) ? "R" :
(user_role.equals("RA")) ? "RA" :
(user_role.equals("RP")) ? "RP" : (user_role.equals("RPA")) ? "RPA" : "U";
retVal= "return user_role";
env.put(Context.SECURITY_PRINCIPAL, "weblogic");
env.put(Context.SECURITY_CREDENTIALS, "weblogic123");
retVal= "return env";
String hostname ="192.168.161.17";
retVal= hostname;
int port = Integer.parseInt("8001");
retVal= "port";
String protocol = "rmi";
retVal= protocol;
String url = new String("/jndi/weblogic.management.mbeanservers.runtime");
retVal= url;
JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port, url);
retVal= serviceURL.toString();
JMXConnector connector = JMXConnectorFactory.connect(serviceURL, env);
retVal="connector";
MBeanServerConnection connection = connector.getMBeanServerConnection();
retVal="MBeanServerConnection";
ObjectName userEditor = null;
ObjectName mBeanTypeService =
new ObjectName("com.bea:Name=MBeanTypeService,Type=weblogic.management.mbeanservers.MBeanTypeService");
retVal="mBeanTypeService";
ObjectName rs1 =
new ObjectName("com.bea:Name=RuntimeService,Type=weblogic.management.mbeanservers.runtime.RuntimeServiceMBean");
retVal="rs1";
ObjectName domainMBean = (ObjectName) connection.getAttribute(rs1, "DomainConfiguration");
retVal="domainMBean";
ObjectName securityConfig = (ObjectName) connection.getAttribute(domainMBean, "SecurityConfiguration");
retVal="securityConfig";
ObjectName defaultRealm = (ObjectName) connection.getAttribute(securityConfig, "DefaultRealm");
retVal="defaultRealm";
ObjectName[] authProviders =
(ObjectName[]) connection.getAttribute(defaultRealm, "AuthenticationProviders");
retVal="authProviders";
for (ObjectName providerName : authProviders) {
if (userEditor == null) {
ModelMBeanInfo info = (ModelMBeanInfo) connection.getMBeanInfo(providerName);
String className = (String) info.getMBeanDescriptor().getFieldValue("interfaceClassName");
System.out.println("className is: " + className);
if (className != null) {
String[] mba = (String[]) connection.invoke(mBeanTypeService, "getSubtypes", new Object[] {
"weblogic.management.security.authentication.UserEditorMBean" }, new String[] {
"java.lang.String" });
for (String mb : mba) {
System.out.println("Model Bean is: " + mb);
if (className.equals(mb)) {
System.out.println("Found a match for the model bean and class name!");
userEditor = providerName;
}
}
}
}
}
if (userEditor == null)
throw new RuntimeException("Could not retrieve user editor");
try {
for (int i = 0; i < authProviders.length; i++) {
String name =
(String)connection.getAttribute(authProviders[i],
"Name");
System.out.println("name " + name);
if (name.equals(authenticatorName))
defaultAuthenticator = authProviders[i];
}
boolean userExists =
((Boolean)connection.invoke(defaultAuthenticator, "userExists",
new Object[] { username },
new String[] { "java.lang.String" })).booleanValue();
System.out.println("userExists" + userExists);
if(userExists)
{
return "User Already exists";
}
else if(!(userExists))
{
connection.invoke(userEditor, "createUser", new Object[] {
username, password, "User created by LPM admin." }, new String[] {
"java.lang.String", "java.lang.String", "java.lang.String"
});
connection.invoke(userEditor, "addMemberToGroup", new Object[] { user_grp, username }, new String[] {
"java.lang.String", "java.lang.String"
});
connection.invoke(userEditor, "addMemberToGroup", new Object[] { "Administrators", username }, new String[] {
"java.lang.String", "java.lang.String"
});
System.out.println("User created successfully");
}
connector.close();
}
catch (Exception ex) {
ex.printStackTrace();
return "Error";
}
// }
// conn.close();
System.out.println("Disconnected from database");
}
catch (Exception e)
{
e.printStackTrace();
}
}
catch(Exception e3)
{
e3.printStackTrace();
return "Error";
}
return retVal;
}
};
/
Here I will get exception at line
JMXConnectorFactory.connect() as Unsupported protocol : rmi.
If I will change the protocol to t3, then It will through
Unsupported protocol : t3
I have ran the code through java directly. It is working. But whenever I will try to call it through pl/sql I will get the mentioned exception.
Please suggest me on this. Is there any other way to create a weblogic users.
I need to create weblogic users from one of the table resided in my database : user_data.
Is it possible to create weblogic users through PL/SQL?. Can I make my java class to be invoked from weblogic server on some interval? Please suggest on this.
I'm trying to get an LDAP Login Page working with Wicket.
I have an working LDAP Class which responds with a true / false statement if the given user credentials were confirmed by the LDAP Server.
package Tools;
import javax.naming.*;
import javax.naming.directory.*;
import java.io.FileNotFoundException;
import java.util.Hashtable;
public class LDAP {
boolean LDAP_ENABLED;
String LDAPBaseDirectory;
String LDAP_SERVER_ADDRESS;
String LDAP_SERVER_PORT;
String LDAP_USER_DOMAIN;
String LDAP_DN;
String LDAP_StandardUserName;
String LDAP_StandardUserPassword;
public LDAP(){ //depends on Config Class
//Import settings from Config
try{
Config config = new Config();
if(config.getProperty_seLDAP_ENABLED()){
this.LDAP_ENABLED = true;
}else{
this.LDAP_ENABLED = false;
}
if(this.LDAP_ENABLED){
this.LDAPBaseDirectory = config.getProperty_seLDAP_BASE_DIRECTORY();
this.LDAP_SERVER_ADDRESS = config.getProperty_seLDAP_SERVER_ADDRESS();
this.LDAP_SERVER_PORT = config.getProperty_seLDAP_SERVER_PORT();
this.LDAP_USER_DOMAIN = config.getProperty_seLDAP_USER_DOMAIN();
this.LDAP_DN = config.getProperty_seLDAP_DN();
this.LDAP_StandardUserName = config.getProperty_seLDAP_StandardUserName();
this.LDAP_StandardUserPassword = config.getProperty_seLDAP_StandardUserPassword();
}
} catch (FileNotFoundException e){
//todo
}
}
public boolean authentify(String userName, String userPassword){
System.out.println(userPassword);
//LDAP responses with "true" if password == null
if(userPassword.equals("")){
return false;
}
/**
* TODO
* Add availability check for LDAP Server
*
*/
try
{
System.out.println("Trying LDAP");
// Set up the environment for creating the initial context
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
String ldapURL = "ldap://" + this.LDAP_SERVER_ADDRESS + ":" +this.LDAP_SERVER_PORT;
System.out.println("URL: "+ ldapURL);
env.put(Context.PROVIDER_URL, ldapURL);
//
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, this.LDAP_DN +"\\"+ userName ); //"domain\\user");
System.out.println("Principal: "+ this.LDAP_DN +"\\"+ userName ); //DEBUG
env.put(Context.SECURITY_CREDENTIALS, userPassword);
System.out.println("Password: "+ userPassword ); //DEBUG
// Create the initial context
DirContext ctx = new InitialDirContext(env);
boolean result = (ctx != null);
// if(ctx != null)
ctx.close();
System.out.println("Result: " + result);
// return result;
if(result){
return true;
}else{
return false;
}
}
catch (Exception e)
{
System.out.println(e.getStackTrace());
e.printStackTrace();
return false;
}
}
}
The above class works pretty fine when used f.e. via console.
Next step was creating a pretty simple login page with wicket:
package haw.Ausleihe;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.Model;
import org.hibernate.Session;
import Tools.LDAP;
import Database.HibernateHelper;
import Database.Entities.User;
public class Login extends WebPage {
private static final long serialVersionUID = 1L;
public Login(final PageParameters parameters) {
super(parameters);
final TextField<String> hawKennung = new TextField<String>("hawKennung",
Model.of(""));
hawKennung.setRequired(true);
hawKennung.add(new UserValidator());
final PasswordTextField passwort = new PasswordTextField("passwort", Model.of(""));
passwort.setRequired(true);
Form<?> login = new Form<Void> ("login")
{
#Override
protected void onSubmit() {
//HibernateHelper hibernate = new HibernateHelper();
final String usernameValue = hawKennung.getModelObject();
final String passwordValue = passwort.getModelObject();
//hibernate.addUser(usernameValue, passwordValue, "", "", "");
// User tmpUser = hibernate.getUser("abb123");
// System.out.println("Database Entry: " + tmpUser.getKennung() + " ; " + tmpUser.getPassword());
System.out.println(usernameValue);
System.out.println(passwordValue);
System.out.println("NOW TESTING LDAP");
LDAP ldap = new LDAP();
if(ldap.authentify(usernameValue, passwordValue)){
System.out.println("Success");
}else{
System.out.println("Fail");
}
setResponsePage(HomePage.class);
}
};
add(login);
login.add(hawKennung);
login.add(passwort);
}
}
Now to my problem...
So this should be pretty simple ... enter username/password click the submit button and ... litterally nothing happens. No System.out.println is shown and i seems as if the code just freezes (debug informations from the LDAP class aren't shown as well)
Do you guys have an idea what i have done wrong?
Greetings,
Dwarfex
Try overriding the onError() function of your form an see if you get there, I suspect that your validator returns an error and you do not get into the onSubmit() because of that.
Than I would suggest to use a proper Model for your input fields. Try adding 2 String properties to your Page (hawKennung and password) and getter/setters for them.
Create the input fields like this:
TextField<String> hawKennung =
new TextField<>("hawKennung", new PropertyModel(Login.this, "hawKennung");
and just use the property hawKennung in the onSubmit(). Wicket will take care of assigning the value.
I have a method:
private List<String> userCns = Collections.synchronizedList(new ArrayList<String>());
private List<String> recipients = Collections.synchronizedList(new ArrayList<String>());
public void sendEmailToLegalUsers() {
try {
synchronized (lock) {
searchGroup();
if(userCns.size() > 0) {
for(String userCn : userCns) {
String mail = getUserMail(userCn);
if(mail != null) {
recipients.add(mail);
}
}
}
String docName = m_binder.getLocal("docname");
String docId = m_binder.getLocal("docid");
String url = m_binder.getLocal("serverURL");
if(recipients.size() > 0) {
m_binder.addResultSet("LOI_EVIN_MAIL", getLoiEvinMailResultSet(docName, docId, url));
for(String recipient : recipients) {
Log.info("Sending mail to: " + recipient);
InternetFunctions.sendMailToEx(recipient, "MH_LOI_EVIN_SEND_EMAIL", "Update Evin Law Compliance for the item: " + docName, m_service, true);
}
}
}
} catch (Exception e) {
Log.info("Error occurred in LDAPSendMail: "+ e.getMessage());
}
}
Now this sendEmailToLegalUsers method can be called from different threads. I am wondering is it the right way to lock the code block so that there is no chances of data mixup in the list?
Edit: whole class:
package com.edifixio.ldapsendmail.handlers;
import intradoc.common.Log;
import intradoc.data.DataResultSet;
import intradoc.server.InternetFunctions;
import intradoc.server.ServiceHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
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.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class LDAPSendMail extends ServiceHandler {
private final Object lock = new Object();
private String ldapURL;
private String baseDN;
private String groupDN;
private String username;
private String password;
private DirContext context;
private List<String> userCns = Collections.synchronizedList(new ArrayList<String>());
private List<String> recipients = Collections.synchronizedList(new ArrayList<String>());
public void sendEmailToLegalUsers() {
try {
synchronized (lock) {
searchGroup();
if(userCns.size() > 0) {
for(String userCn : userCns) {
String mail = getUserMail(userCn);
if(mail != null) {
recipients.add(mail);
}
}
}
String docName = m_binder.getLocal("docname");
String docId = m_binder.getLocal("docid");
String url = m_binder.getLocal("serverURL");
if(recipients.size() > 0) {
m_binder.addResultSet("LOI_EVIN_MAIL", getLoiEvinMailResultSet(docName, docId, url));
for(String recipient : recipients) {
Log.info("Sending mail to: " + recipient);
InternetFunctions.sendMailToEx(recipient, "MH_LOI_EVIN_SEND_EMAIL", "Update Evin Law Compliance for the item: " + docName, m_service, true);
}
}
userCns.clear();
recipients.clear();
}
} catch (Exception e) {
Log.info("Error occurred in LDAPSendMail: "+ e.getMessage());
}
}
private String getUserMail(String userCn) throws NamingException {
NamingEnumeration<SearchResult> searchResults = getLdapDirContext().search(userCn, "(objectclass=person)", getSearchControls());
while (searchResults.hasMore()){
SearchResult searchResult = searchResults.next();
Attributes attributes = searchResult.getAttributes();
Attribute mail = null;
try {
mail = attributes.get("mail");
} catch (Exception e) {
mail = null;
}
if(mail != null) {
return (String)mail.get();
}
}
return null;
}
private void searchGroup() throws NamingException {
NamingEnumeration<SearchResult> searchResults = getLdapDirContext().search(groupDN, "(objectclass=groupOfUniqueNames)", getSearchControls());
String searchGroupCn = getCNForBrand(m_binder.getLocal("brandId"), m_binder.getLocal("brandName"));
while (searchResults.hasMore()) {
SearchResult searchResult = searchResults.next();
Attributes attributes = searchResult.getAttributes();
Attribute groupCn = null;
try {
groupCn = attributes.get("cn");
} catch (Exception e) {
groupCn = null;
}
if(groupCn != null) {
if(searchGroupCn.equals((String)groupCn.get())) {
Attribute uniqueMembers = attributes.get("uniqueMember");
for(int i = 0; i < uniqueMembers.size(); i++){
String uniqueMemberCN = (String) uniqueMembers.get(i);
userCns.add(uniqueMemberCN);
}
break;
}
}
}
}
private DirContext getLdapDirContext() throws NamingException {
if(context != null) {
return context;
}
ldapURL = m_binder.getLocal("ldapUrl");
baseDN = m_binder.getLocal("baseDN");
groupDN = new StringBuilder().append("ou=").append(getAccountGroup(m_binder.getLocal("account"))).append(",").append("ou=groups,").append(baseDN).toString();
username = m_binder.getLocal("username");
password = m_binder.getLocal("password");
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, ldapURL);
environment.put(Context.SECURITY_PRINCIPAL, username);
environment.put(Context.SECURITY_CREDENTIALS, password);
context = new InitialDirContext(environment);
return context;
}
private SearchControls getSearchControls() {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
return searchControls;
}
private String getCNForBrand(String brandId, String brandName) {
String[] brandIdSplittedArray = brandId.split("/");
return new StringBuilder().append(brandIdSplittedArray[0]).append("-").append(brandIdSplittedArray[1]).append("-").
append(brandIdSplittedArray[2]).append("-").append(brandName.replaceAll("\\s","")).append("-LU").toString();
}
private String getAccountGroup(String account) {
return account.split("/")[1];
}
private DataResultSet getLoiEvinMailResultSet(String docName, String docId, String url) {
DataResultSet resultSet = new DataResultSet(new String[]{"DOCNAME", "DOCID", "URL"});
Vector<String> vector = new Vector<String>();
vector.add(docName);
vector.add(docId);
vector.add(url);
resultSet.addRow(vector);
return resultSet;
}
}
What is lock? Are you using it elsewhere? Typically you want the synchronized blocks to be pretty small. If you're using lock everywhere as a general purpose lock then you might be stopping a thread from doing some useful work in a totally unrelated area (i.e., one where there is no contention for shared resources).
Second, does recipients really need to be an instance variable? It seems strange that you would keep adding emails to recipients without checking to see if that email already exists in the list. I can't see any code where you're clearing our recipients either. So that is a potential issue. If you are going to be building recipients from scratch every time, then just make it a local variable in the method. If you really need access to that data, you can always pull it out of userCns.
Once you make recipients a local variable, then you only need to synchronize by using userCns as a lock:
synchronized(userCns) {
...
}
edit: Your code shows that you only use recipients once, and that's inside the sendEmailToLegalUsers method. Another thing, as I pointed out, is that you never clear recipients so that's a bug in your code. Since you don't use recipients anywhere, make it a local variable to sendEmailToLEgalUsers. Also, just synchronize over userCns. You won't need to synchronize over recipients; you can create it inside the synchronized block.
I would do
private final List<String> userCns = new ArrayList<String>();
private final List<String> recipients = new ArrayList<String>();
with
synchronized(userCns) {
// as Vivin suggests.
}
you don't need an additional lock.
We logon users to Active Directory via LDAP using the Java LDAP API. We want to enhance our logon functionality to further check if the user is in a given AD group. Does anyone know how to do this?
Current code:
import javax.naming.*;
import javax.naming.ldap.*;
LdapContext ctx = null;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.PROVIDER_URL, Config.get("ldap-url"));
try {
Control[] connCtls = new Control[] {new FastBindConnectionControl()};
ctx = new InitialLdapContext(env, connCtls);
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, "DOMAIN\\" + username);
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
ctx.reconnect(connCtls);
/* TODO: Only return true if user is in group "ABC" */
return true; //User authenticated
} catch (Exception e) {
return false; //User could NOT be authenticated
} finally {
...
}
Update: See the solution below.
We solved this with the class below. Just call the authenticate method:
import java.text.MessageFormat;
import java.util.*;
import javax.naming.*;
import org.apache.log4j.Level;
public class LdapGroupAuthenticator {
public static final String DISTINGUISHED_NAME = "distinguishedName";
public static final String CN = "cn";
public static final String MEMBER = "member";
public static final String MEMBER_OF = "memberOf";
public static final String SEARCH_BY_SAM_ACCOUNT_NAME = "(SAMAccountName={0})";
public static final String SEARCH_GROUP_BY_GROUP_CN = "(&(objectCategory=group)(cn={0}))";
/*
* Prepares and returns CN that can be used for AD query
* e.g. Converts "CN=**Dev - Test Group" to "**Dev - Test Group"
* Converts CN=**Dev - Test Group,OU=Distribution Lists,DC=DOMAIN,DC=com to "**Dev - Test Group"
*/
public static String getCN(String cnName) {
if (cnName != null && cnName.toUpperCase().startsWith("CN=")) {
cnName = cnName.substring(3);
}
int position = cnName.indexOf(',');
if (position == -1) {
return cnName;
} else {
return cnName.substring(0, position);
}
}
public static boolean isSame(String target, String candidate) {
if (target != null && target.equalsIgnoreCase(candidate)) {
return true;
}
return false;
}
public static boolean authenticate(String domain, String username, String password) {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://1.2.3.4:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, domain + "\\" + username);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx = null;
String defaultSearchBase = "DC=DOMAIN,DC=com";
String groupDistinguishedName = "DN=CN=DLS-APP-MyAdmin-C,OU=DLS File Permissions,DC=DOMAIN,DC=com";
try {
ctx = new InitialDirContext(env);
// userName is SAMAccountName
SearchResult sr = executeSearchSingleResult(ctx, SearchControls.SUBTREE_SCOPE, defaultSearchBase,
MessageFormat.format( SEARCH_BY_SAM_ACCOUNT_NAME, new Object[] {username}),
new String[] {DISTINGUISHED_NAME, CN, MEMBER_OF}
);
String groupCN = getCN(groupDistinguishedName);
HashMap processedUserGroups = new HashMap();
HashMap unProcessedUserGroups = new HashMap();
// Look for and process memberOf
Attribute memberOf = sr.getAttributes().get(MEMBER_OF);
if (memberOf != null) {
for ( Enumeration e1 = memberOf.getAll() ; e1.hasMoreElements() ; ) {
String unprocessedGroupDN = e1.nextElement().toString();
String unprocessedGroupCN = getCN(unprocessedGroupDN);
// Quick check for direct membership
if (isSame (groupCN, unprocessedGroupCN) && isSame (groupDistinguishedName, unprocessedGroupDN)) {
Log.info(username + " is authorized.");
return true;
} else {
unProcessedUserGroups.put(unprocessedGroupDN, unprocessedGroupCN);
}
}
if (userMemberOf(ctx, defaultSearchBase, processedUserGroups, unProcessedUserGroups, groupCN, groupDistinguishedName)) {
Log.info(username + " is authorized.");
return true;
}
}
Log.info(username + " is NOT authorized.");
return false;
} catch (AuthenticationException e) {
Log.info(username + " is NOT authenticated");
return false;
} catch (NamingException e) {
throw new SystemException(e);
} finally {
if (ctx != null) {
try {
ctx.close();
} catch (NamingException e) {
throw new SystemException(e);
}
}
}
}
public static boolean userMemberOf(DirContext ctx, String searchBase, HashMap processedUserGroups, HashMap unProcessedUserGroups, String groupCN, String groupDistinguishedName) throws NamingException {
HashMap newUnProcessedGroups = new HashMap();
for (Iterator entry = unProcessedUserGroups.keySet().iterator(); entry.hasNext();) {
String unprocessedGroupDistinguishedName = (String) entry.next();
String unprocessedGroupCN = (String)unProcessedUserGroups.get(unprocessedGroupDistinguishedName);
if ( processedUserGroups.get(unprocessedGroupDistinguishedName) != null) {
Log.info("Found : " + unprocessedGroupDistinguishedName +" in processedGroups. skipping further processing of it..." );
// We already traversed this.
continue;
}
if (isSame (groupCN, unprocessedGroupCN) && isSame (groupDistinguishedName, unprocessedGroupDistinguishedName)) {
Log.info("Found Match DistinguishedName : " + unprocessedGroupDistinguishedName +", CN : " + unprocessedGroupCN );
return true;
}
}
for (Iterator entry = unProcessedUserGroups.keySet().iterator(); entry.hasNext();) {
String unprocessedGroupDistinguishedName = (String) entry.next();
String unprocessedGroupCN = (String)unProcessedUserGroups.get(unprocessedGroupDistinguishedName);
processedUserGroups.put(unprocessedGroupDistinguishedName, unprocessedGroupCN);
// Fetch Groups in unprocessedGroupCN and put them in newUnProcessedGroups
NamingEnumeration ns = executeSearch(ctx, SearchControls.SUBTREE_SCOPE, searchBase,
MessageFormat.format( SEARCH_GROUP_BY_GROUP_CN, new Object[] {unprocessedGroupCN}),
new String[] {CN, DISTINGUISHED_NAME, MEMBER_OF});
// Loop through the search results
while (ns.hasMoreElements()) {
SearchResult sr = (SearchResult) ns.next();
// Make sure we're looking at correct distinguishedName, because we're querying by CN
String userDistinguishedName = sr.getAttributes().get(DISTINGUISHED_NAME).get().toString();
if (!isSame(unprocessedGroupDistinguishedName, userDistinguishedName)) {
Log.info("Processing CN : " + unprocessedGroupCN + ", DN : " + unprocessedGroupDistinguishedName +", Got DN : " + userDistinguishedName +", Ignoring...");
continue;
}
Log.info("Processing for memberOf CN : " + unprocessedGroupCN + ", DN : " + unprocessedGroupDistinguishedName);
// Look for and process memberOf
Attribute memberOf = sr.getAttributes().get(MEMBER_OF);
if (memberOf != null) {
for ( Enumeration e1 = memberOf.getAll() ; e1.hasMoreElements() ; ) {
String unprocessedChildGroupDN = e1.nextElement().toString();
String unprocessedChildGroupCN = getCN(unprocessedChildGroupDN);
Log.info("Adding to List of un-processed groups : " + unprocessedChildGroupDN +", CN : " + unprocessedChildGroupCN);
newUnProcessedGroups.put(unprocessedChildGroupDN, unprocessedChildGroupCN);
}
}
}
}
if (newUnProcessedGroups.size() == 0) {
Log.info("newUnProcessedGroups.size() is 0. returning false...");
return false;
}
// process unProcessedUserGroups
return userMemberOf(ctx, searchBase, processedUserGroups, newUnProcessedGroups, groupCN, groupDistinguishedName);
}
private static NamingEnumeration executeSearch(DirContext ctx, int searchScope, String searchBase, String searchFilter, String[] attributes) throws NamingException {
// Create the search controls
SearchControls searchCtls = new SearchControls();
// Specify the attributes to return
if (attributes != null) {
searchCtls.setReturningAttributes(attributes);
}
// Specify the search scope
searchCtls.setSearchScope(searchScope);
// Search for objects using the filter
NamingEnumeration result = ctx.search(searchBase, searchFilter,searchCtls);
return result;
}
private static SearchResult executeSearchSingleResult(DirContext ctx, int searchScope, String searchBase, String searchFilter, String[] attributes) throws NamingException {
NamingEnumeration result = executeSearch(ctx, searchScope, searchBase, searchFilter, attributes);
SearchResult sr = null;
// Loop through the search results
while (result.hasMoreElements()) {
sr = (SearchResult) result.next();
break;
}
return sr;
}
}
None of above code snippets didn't worked for me. After 1 day spending on Google and tomcat source following code worked well to find user groups.
import java.util.Hashtable;
import javax.naming.CompositeName;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class MemberOfTest{
private static final String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
private static final String connectionURL = "ldap://HOST:PORT";
private static final String connectionName = "CN=Query,CN=Users,DC=XXX,DC=XX";
private static final String connectionPassword = "XXX";
// Optioanl
private static final String authentication = null;
private static final String protocol = null;
private static String username = "XXXX";
private static final String MEMBER_OF = "memberOf";
private static final String[] attrIdsToSearch = new String[] { MEMBER_OF };
public static final String SEARCH_BY_SAM_ACCOUNT_NAME = "(sAMAccountName=%s)";
public static final String SEARCH_GROUP_BY_GROUP_CN = "(&(objectCategory=group)(cn={0}))";
private static String userBase = "DC=XXX,DC=XXX";
public static void main(String[] args) throws NamingException {
Hashtable<String, String> env = new Hashtable<String, String>();
// Configure our directory context environment.
env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
env.put(Context.PROVIDER_URL, connectionURL);
env.put(Context.SECURITY_PRINCIPAL, connectionName);
env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
if (authentication != null)
env.put(Context.SECURITY_AUTHENTICATION, authentication);
if (protocol != null)
env.put(Context.SECURITY_PROTOCOL, protocol);
InitialDirContext context = new InitialDirContext(env);
String filter = String.format(SEARCH_BY_SAM_ACCOUNT_NAME, username);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(attrIdsToSearch);
NamingEnumeration results = context.search(userBase, filter,constraints);
// Fail if no entries found
if (results == null || !results.hasMore()) {
System.out.println("No result found");
return;
}
// Get result for the first entry found
SearchResult result = (SearchResult) results.next();
// Get the entry's distinguished name
NameParser parser = context.getNameParser("");
Name contextName = parser.parse(context.getNameInNamespace());
Name baseName = parser.parse(userBase);
Name entryName = parser.parse(new CompositeName(result.getName())
.get(0));
// Get the entry's attributes
Attributes attrs = result.getAttributes();
Attribute attr = attrs.get(attrIdsToSearch[0]);
NamingEnumeration e = attr.getAll();
System.out.println("Member of");
while (e.hasMore()) {
String value = (String) e.next();
System.out.println(value);
}
}
}
The easiest way is with 'lookup': (to open an Ldap Context: look above examples)
/**
* Tests if an Active Directory user exists in an Active Directory group.
* #param ctx LDAP Context.
* #param dnADGroup distinguishedName of group.
* #param dnADUser distinguishedName of user.
* #return True if user is member of group.
*/
public static boolean isMemberOfADGroup(LdapContext ctx, String dnADGroup, String dnADUser) {
try {
DirContext lookedContext = (DirContext) (ctx.lookup(dnADGroup));
Attribute attrs = lookedContext.getAttributes("").get("member");
for (int i = 0; i < attrs.size(); i++) {
String foundMember = (String) attrs.get(i);
if(foundMember.equals(dnADUser)) {
return true;
}
}
} catch (NamingException ex) {
String msg = "There has been an error trying to determin a group membership for AD user with distinguishedName: "+dnADUser;
System.out.println(msg);
ex.printStackTrace();
}
return false;
}
LDAP lookup methods of finding whether a user is a member of a group are not correct, especially if you're talking about a logged on user. For a user that's actually logged on the list of groups varies depending on which computer the user logged on. That list needs to include groups from domain trusts, nested groups and local groups.
If you're looking for group memberships of the currently logged on user or a user that you're logging on with a username and password in Java, try Waffle.
IWindowsAuthProvider prov = new WindowsAuthProviderImpl();
IWindowsIdentity identity = prov.logonUser("username", "password");
System.out.println("User identity: " + identity.getFqn());
for(IWindowsAccount group : identity.getGroups()) {
System.out.println(" " + group.getFqn() + " (" + group.getSidString() + ")");
}
Following up on Sundaramurthi's answer, it could be done even more straightforward way, where you don't query for all the user's group:
(&(objectClass=user)(sAMAccountName=XXXX)(memberOf=CN=YYY,OU=_Common-Access,OU=Groups,OU=_CORP,DC=XXX,DC=XX))
where
XXXX - user name
XXX.XX - domain name
YYY - group name
This lets you to just get an answer whether user is in a group or not.
So just do:
String userBase = "DC=XXX,DC=XX";
String CHECK_IF_USER_IN_GROUP = "(&(objectClass=user)(sAMAccountName=%s)(memberOf=CN=%s,OU=...,OU=...,OU=...,%s))";
String queryFilter = String.format(CHECK_IF_USER_IN_GROUP, user, group, userBase);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results = context.search(userBase, queryFilter, constraints);
if (results == null) {
throw new Exception("No answer from LDAP");
}
if (!results.hasMore()) {
System.out.println("No result found");
// user is not in the group
}
// user is in the group
Not sure about Java API specifics, but the generic way of doing this is adding a group check to the query/binding.
I can't give you a working code using java naming ldap.
I used Spring LDAP, and the way you do it:
Get the User object, do a search on the username something like sAMAccountName=USERNAME
After you get the object you retreive the property memberOf -> this will be a list and check for a specific one in Java.
That is the only way I could think of.
To query if a user belongs to a given group once you have established a connection you can query using either member or memberOf attribute in Active Directory.
Using memberOf Attribute :
filter used : (&(Group Member Attribute=Group DN)(objectClass=Group Object class))
Ex : (&(memberOf=CN=group,ou=qa_ou,dc=ppma,dc=org)(objectClass=group))
Using member Attribute :
filter used : (&(Group Member Attribute=User DN)(objectClass=Group Object class))
Ex : (&(member=CN=user,ou=qa_ou,dc=ppma,dc=org)(objectClass=group))
Unfortunately the answer varies with installations of AD as well as other types of LDAP server.
We had to solve the same problem. In the end we allowed the system administrator to provide us with an LDAP query-pattern where we substitute the user name (and group name if that needs to be variable too) into the pattern.
I found this useful:
retrieves-group-membership for Active Directory
And I have this piece of working code:
import java.util.Hashtable;
import javax.naming.CompositeName;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameParser;
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;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
public class TestAD1 {
private static String userBase = "DC=SomeName,DC=SomeName,DC=SomeName,DC=SomeName,DC=COM,DC=US";
public static void main(String[] args) {
TestAD1 tad = new TestAD1();
try {
// Create a LDAP Context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "ldap.serviceaccount#domain.com");
env.put(Context.SECURITY_CREDENTIALS, "drowssap");
env.put(Context.PROVIDER_URL, "ldap://fully.qualified.server.name:389");
LdapContext ctx = new InitialLdapContext(env, null);
InitialDirContext inidircontext = new InitialDirContext(env);
DirContext dirctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
// Print all attributes of the name in namespace
SearchControls sctls = new SearchControls();
String retatts[] = {"sn", "mail", "displayName", "sAMAccountName"};
sctls.setReturningAttributes(retatts);
sctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String srchfilter = "(&(objectClass=user)(mail=*))";
String srchbase = userBase;
int totalresults = 0;
NamingEnumeration answer = dirctx.search(srchbase, srchfilter, sctls);
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult) answer.next();
totalresults++;
System.out.println(">>> " + sr.getName());
Attributes attrs = sr.getAttributes();
if (answer == null || !answer.hasMore()) {
System.out.println("No result found");
return;
}
if (attrs != null) {
try {
System.out.println(" surname: " + attrs.get("sn").get());
System.out.println(" Email - ID: " + attrs.get("mail").get());
System.out.println(" User - ID: " + attrs.get("displayName").get());
System.out.println(" Account Name: " + attrs.get("sAMAccountName").get());
tad.GetGroups(inidircontext, attrs.get("sAMAccountName").get().toString());
} catch (NullPointerException e) {
System.out.println("Error listing attributes..." + e);
}
}
System.out.println("Total Results : " + totalresults);
// close dir context
dirctx.close();
}
ctx.close();
} catch (NamingException e) {
System.out.println("Problem Search Active Directory..." + e);
//e.printStackTrace();
}
}
// Get all the groups.
public void GetGroups(InitialDirContext context, String username) throws NamingException {
String[] attrIdsToSearch = new String[]{"memberOf"};
String SEARCH_BY_SAM_ACCOUNT_NAME = "(sAMAccountName=%s)";
String filter = String.format(SEARCH_BY_SAM_ACCOUNT_NAME, username);
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(attrIdsToSearch);
NamingEnumeration results = context.search(userBase, filter, constraints);
// Fail if no entries found
if (results == null || !results.hasMore()) {
System.out.println("No result found");
return;
}
SearchResult result = (SearchResult) results.next();
Attributes attrs = result.getAttributes();
Attribute attr = attrs.get(attrIdsToSearch[0]);
NamingEnumeration e = attr.getAll();
System.out.println(username + " is Member of the following groups : \n");
while (e.hasMore()) {
String value = (String) e.next();
System.out.println(value);
}
}
}
Also you can modify the accepted answer from here: Authenticating against Active Directory with Java on Linux with the following:
String group="name of the group";
Iterator ig = groups.iterator();
Boolean bool=false;
while (ig.hasNext()) {
String a=ig.next().toString();
if (a.equals(group)) {
JOptionPane.showMessageDialog(this, "Authentication succeeded!");
bool=true;
// here you can do smth in case of success
}
}
if (bool==false){
JOptionPane.showMessageDialog(this, "Permission denied");
}