Authenticate an Active Directory user with UnboundID using username - java

I'm building an application where I need to connect to Active Directory using UnboundID. Using an example, I managed to connect a user with their distinguishedName and password.
However I would like to authenticate them using only the domain and the username, similar to how it's done in Windows. Browsing AD using a tool called JXplorer it seems like the sAMAccountName might be the property I need. However replacing the distinguishedName with the sAMAccountName resulted in an AcceptSecurityContext error. Using the "uid=..." syntax shown in the example also yielded the same error.
Is there a way to logon using only the domain, username/sAMAccountName and password. or do I somehow need to search through AD and find the distinguishedName of the user I wish to authenticate, and then bind the connection using their distinguishedName and password?

As #ioplex said in his comment, AD accepts a bind using the username from the sAMAccountName with the domain name appended to it. Just use it instead of the DN on the bind:
String userId = username + "#" + domain;
SimpleBindRequest adminBindRequest = new SimpleBindRequest(userId, passsword);
The final userId will be something like 'eharris#contoso.local'

You will need to use an account with appropriate permissions to perform a search for samAccountName to locate the user and then bind as the found user using the Distinguished Name.
You need to be sure you only return one entry from the search.
Sample For Demonstration Purposes ONLY!
Parameters would be something like:
"adldap.example.com" "CN=bob,OU=Users,DC=example,DC=com" "connPwd" "OU=Users,DC=example,DC=com" "samAccountName" "findUserValue" "userPassword"
/**
* #author jwilleke <br/>
* Use For Demonstration Purposes ONLY!
* #param args
*/
public static void main(String[] args)
{
String connHost = args[0];
String connID = args[1];
String connPwd = args[2];
String searchBase = args[3];
String findUserByAttribute = args[4];
String findUserValue = args[5];
String userPassword = args[6];
int connPort = 389;
// TODO Auto-generated method stub
String actualLDAPServer = null;
RootDSE rootDSE = null;
// If I were doing this for real, I would use a POOL for Connections
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager()); // Use For Demonstration Purposes ONLY!
SSLSocketFactory sslSocketFactory = null;
try
{
sslSocketFactory = sslUtil.createSSLSocketFactory();
}
catch (GeneralSecurityException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
SimpleBindRequest adminBindRequest = new SimpleBindRequest(connID, connPwd);
LDAPConnection adminConnection = new LDAPConnection(sslSocketFactory);
try
{
adminConnection = new LDAPConnection(connHost, connPort);
log.debug("Successful LDAP adminConnection to:" + connHost + ":" + connPort);
adminConnection.bind(adminBindRequest);
log.debug("Successful Bind as:" + connID);
}
catch (LDAPException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
LDAPConnection userConnection = new LDAPConnection(sslSocketFactory);
try
{
userConnection = new LDAPConnection(connHost, connPort);
log.debug("Successful LDAP userConnection to:" + connHost + ":" + connPort);
}
catch (LDAPException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
// Construct Filter to find user
Filter findUserfilter = null;
findUserfilter = Filter.createEqualityFilter(findUserByAttribute, findUserValue);
// Create Search Request
SearchRequest searchRequest = new SearchRequest(searchBase, SearchScope.SUB, findUserfilter);
searchRequest.setSizeLimit(1); // We will error if we get more than one hit
SearchResult searchResult = null;
try
{
searchResult = adminConnection.search(searchRequest);
}
catch (LDAPSearchException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
String userDN = null;
if (searchResult.getEntryCount() > 1)
{
log.error("We got more than one Entry for:" + searchRequest.getFilter());
}
if (searchResult.getEntryCount() == 0)
{
log.error("We got No Entries for:" + searchRequest.getFilter());
}
for (SearchResultEntry entry : searchResult.getSearchEntries())
{
userDN = entry.getDN();
log.debug("Found an Entry: " + userDN);
}
SimpleBindRequest userBindRequest = new SimpleBindRequest(userDN, userPassword);
if (userBindRequest.getBindDN() == null)
{
log.warn("We got a null for the userBindRequest UserDN and therefore the bind is anonymous !");
}
if (userBindRequest.getPassword() == null)
{
log.warn("We got a null for the userBindRequest Password and therefore the bind is anonymous !");
}
try
{
userConnection.bind(userDN, userPassword);
log.debug("Successful userConnection Bind as:" + userDN);
}
catch (LDAPException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
-jim

Related

How to tackle time delay in inserting email Alias using Google's ADMIN SDK APIs/Directory API?

Context:
In my organization, we are using google's services for email. In the UI, we let user change their email alias, and delete their email alias. They can only have one email alias.
I am using Directory API or ADMIN SDK in Spring boot to insert/delete alias.
The Problem:
I am inserting an alias using, directoryService.users().aliases().insert(primaryEmailId, alias).execute();
It takes 1 minutes for a new alias to reflect.
Now if a user wants to delete/change the email alias within one minute of adding up a new alias, the request for deletion will fail at the backend since the newly inserted alias has not been reflected yet. As a result, a newest alias will be created but the old one will not get deleted.
How to tackle this?
One way to fix this is to disable edit button for 1 minute in the UI, but this is not a good user experience.
So are there any other ways?
Insert Alias METHOD:
Alias alias = new Alias();
alias.setAlias(newEmailAlias);
try {
directoryService.users().aliases().insert(primaryEmailId, alias).execute();
} catch (IOException e) {
e.printStackTrace();
}
GET ALIAS METHOD:
public List<String> getAliases(String primaryEmailId) {
User user = null;
try {
user = directoryService.users().get(primaryEmailId).execute();
} catch (IOException e) {
e.printStackTrace();
}
return user.getAliases();
}
Delete alias:
try {
directoryService.users().aliases().delete(primaryEmailId, emailAlias).execute();
} catch (IOException e) {
e.printStackTrace();
}
Adding some more details on how i am generating directory object. I am using a service account to get the service object:
private static final String APPLICATION_NAME = "Google Aliases List";
private static final List<String> SCOPES = Collections.singletonList(DirectoryScopes.ADMIN_DIRECTORY_USER);
private static final String CREDENTIALS_FILE_PATH = "/gmail-api-randonnum-randomletter.json";
#Bean
public Directory directoryService() {
HttpTransport httpTransport = null;
Directory service = null;
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = GsonFactory.getDefaultInstance();
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(getCredentials());
service = new Directory.Builder(httpTransport, jsonFactory, requestInitializer)
.setApplicationName(APPLICATION_NAME)
.build();
} catch (GeneralSecurityException | IOException e) {
System.out.println(e);
}
return service;
}
private GoogleCredentials getCredentials() throws IOException {
// Load client secrets.
InputStream in = GoogleDirectoryAPIConfig.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
return GoogleCredentials.fromStream(in).createScoped(SCOPES).createDelegated("admin#email.com");
}

How to get Notes field from Google Contacts API

I have successfully retrieved a Contact Entry from Google Contacts, but I couldn't get the Notes field yet. How can I do that?
This is part of what I have done so far...
public static void main(String[] args) throws IOException, ServiceException, SQLException {
System.out.println("Start elaboration");
Credential credential =authorize();
if (!credential.refreshToken()) {
throw new RuntimeException("Failed OAuth to refresh the token");
}
ContactsService myService = new ContactsService(APPLICATION_NAME);
myService.setOAuth2Credentials(credential);
URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
Query Query = new Query(feedUrl);
Query.setMaxResults(32767);
ContactFeed feed=null;
try {
feed = myService.query(Query, ContactFeed.class);
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (ContactEntry contact : feed.getEntries()) {
if (contact.hasName()) {
Name name = contact.getName();
if (name.hasFullName()) {
String fullNameToDisplay = name.getFullName().getValue();
if (name.getFullName().hasYomi()) {
fullNameToDisplay += " (" + name.getFullName().getYomi() + ")";
}
System.out.println("Full Name = " + fullNameToDisplay);
}
}
/*
* insert here the code to retrive Notes Field
*/
}
System.out.println("End elaboration");
}

How to schedule a java code having messageArrived method of MqttCallback

I am new in MQTT world. I have written a code to subscribe a topic and get message from topic and store it in database. Now my problem is how to put this code on server so that it will keep receiving message infinitely. I am trying to create a scheduler but in that case i am Getting Persistence Already in Use error from MQTT. I cannot change the clientId every time it connect. It is a fixed one in my case. Is there any way to get the persistence object which is already connected for a particular clientId?
Please help. Thanks and advance.
Please Find the code subscribe topic and messageArrived method of mqqt to get message from topic
public class AppTest {
private MqttHandler handler;
public void doApp() {
// Read properties from the conf file
Properties props = MqttUtil.readProperties("MyData/app.conf");
String org = props.getProperty("org");
String id = props.getProperty("appid");
String authmethod = props.getProperty("key");
String authtoken = props.getProperty("token");
// isSSL property
String sslStr = props.getProperty("isSSL");
boolean isSSL = false;
if (sslStr.equals("T")) {
isSSL = true;
}
// Format: a:<orgid>:<app-id>
String clientId = "a:" + org + ":" + id;
String serverHost = org + MqttUtil.SERVER_SUFFIX;
handler = new AppMqttHandler();
handler.connect(serverHost, clientId, authmethod, authtoken, isSSL);
// Subscribe Device Events
// iot-2/type/<type-id>/id/<device-id>/evt/<event-id>/fmt/<format-id>
handler.subscribe("iot-2/type/" + MqttUtil.DEFAULT_DEVICE_TYPE
+ "/id/+/evt/" + MqttUtil.DEFAULT_EVENT_ID + "/fmt/json", 0);
}
/**
* This class implements as the application MqttHandler
*
*/
private class AppMqttHandler extends MqttHandler {
// Pattern to check whether the events comes from a device for an event
Pattern pattern = Pattern.compile("iot-2/type/"
+ MqttUtil.DEFAULT_DEVICE_TYPE + "/id/(.+)/evt/"
+ MqttUtil.DEFAULT_EVENT_ID + "/fmt/json");
DatabaseHelper dbHelper = new DatabaseHelper();
/**
* Once a subscribed message is received
*/
#Override
public void messageArrived(String topic, MqttMessage mqttMessage)
throws Exception {
super.messageArrived(topic, mqttMessage);
Matcher matcher = pattern.matcher(topic);
if (matcher.matches()) {
String payload = new String(mqttMessage.getPayload());
// Parse the payload in Json Format
JSONObject contObj = new JSONObject(payload);
System.out
.println("jsonObject arrived in AppTest : " + contObj);
// Call method to insert data in database
dbHelper.insertIntoDB(contObj);
}
}
}
Code to connect to client
public void connect(String serverHost, String clientId, String authmethod,
String authtoken, boolean isSSL) {
// check if client is already connected
if (!isMqttConnected()) {
String connectionUri = null;
//tcp://<org-id>.messaging.internetofthings.ibmcloud.com:1883
//ssl://<org-id>.messaging.internetofthings.ibmcloud.com:8883
if (isSSL) {
connectionUri = "ssl://" + serverHost + ":" + DEFAULT_SSL_PORT;
} else {
connectionUri = "tcp://" + serverHost + ":" + DEFAULT_TCP_PORT;
}
if (client != null) {
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
client = null;
}
try {
client = new MqttClient(connectionUri, clientId);
} catch (MqttException e) {
e.printStackTrace();
}
client.setCallback(this);
// create MqttConnectOptions and set the clean session flag
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
options.setUserName(authmethod);
options.setPassword(authtoken.toCharArray());
//If SSL is used, do not forget to use TLSv1.2
if (isSSL) {
java.util.Properties sslClientProps = new java.util.Properties();
sslClientProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
options.setSSLProperties(sslClientProps);
}
try {
// connect
client.connect(options);
System.out.println("Connected to " + connectionUri);
} catch (MqttException e) {
e.printStackTrace();
}
}
}

LDAPContext.search() returns empty result

Using LDAPContext class I search for a specific user and try to get whether it exists. But search() method returns an empty response.
private int checkUserOnLDAP() {
String strLDAPServer = "ldap://ldap.forumsys.com:389";
String strLDAPPricipal = "cn=read-only-admin,dc=example,dc=com";
String strPassword = "password";
String strSearchBase = "ou=mathematicians,dc=example,dc=com";
String strUserToSearch = "riemann";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, strLDAPServer);
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, strLDAPPricipal);
environment.put(Context.SECURITY_CREDENTIALS, strPassword);
LdapContext ctxGC = null;
try {
ctxGC = new InitialLdapContext(environment, null);
ctxGC.getAttributes("");
} catch (NamingException e) {
System.err.print("SEARCHER BLOCKED USER");
e.printStackTrace();
} catch (Exception e) {
System.err.print("SEARCHER WRONG PASSWORD");
e.printStackTrace();
}
System.out.println("SEARCHER LOGIN SUCCESSFUL");
System.out.println("NOW TRYING TO SEARCH");
try {
String searchFilter = "(&(objectClass=user)(sAMAccountName=" + strUserToSearch + "))";
String returnedAtts[] = new String[0];
SearchControls searchCtls = new SearchControls();
searchCtls.setReturningAttributes(returnedAtts);
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<?> answer = ctxGC.search(strSearchBase, searchFilter, searchCtls);
if (answer.hasMoreElements()) {
Object a = answer.nextElement();
System.out.println("SUCCESFULLY, FOUND USER");
return 0;
} else {
System.out.println("ANSWER HAS NO ELEMENTS");
}
} catch (Exception e) {
System.out.println("SEARCH FAILED");
e.printStackTrace();
}
return 0;
}
While testing, I use an online ldap service: http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/
Considering this online test service how can I check whether user exists?
Your search filter uses the sAMAccountName attribute, but that attribute is not available in the test server. Use uid instead.

get ldap attribute PwdLastSet using java

I am trying to retrieve the PwdLastSet attribute from LDAP using java. It fails and doesn't throw an error. Here's the code:
private String getPasswordLastSet() {
int searchScope = LDAPConnection.SCOPE_BASE;
int ldapVersion = LDAPConnection.LDAP_V3;
int ldapPort = 389;
String ldapHost = "Adapps.domain.mycompany.com";
String loginDN = "cn=myNTusername,OU=users,OU=colorado,OU=corporate,dc=domain,dc=mycompany,dc=com";
String password = "myNTpassword";
String baseDn = "dc=mycompany,dc=com";
LDAPConnection lc = new LDAPConnection();
String attributes[] = {"PwdLastSet"};
String pwdLastSet = null;
try {
lc.connect( ldapHost, ldapPort );
lc.bind( ldapVersion, loginDN, password.getBytes("UTF8") );
String filter = "(sAMAccountName=myNtusername)";
LDAPSearchResults searchResults =
lc.search( baseDn,
searchScope,
filter,
attributes,
true); // return attributes and values
while ( searchResults.hasMore()) {
LDAPEntry nextEntry = null;
try {
actionlogger.debug("about to searchResults.next...");
nextEntry = searchResults.next();
actionlogger.debug("about to nextEntry.getAttribute...");
LDAPAttribute pwdLastSetAttribute = nextEntry.getAttribute("PwdLastSet");
pwdLastSet = pwdLastSetAttribute.getStringValue();
} catch(LDAPException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}
} catch( LDAPException e ) {
actionlogger.error( "Error occured while LDAP Search : " + e.getMessage(),e );
} catch (Exception e) {
e.printStackTrace();
}
return pwdLastSet;
}
The output is
about to searchResults.next...
But
about to nextEntry.getAttribute...
is never hit. Any ideas?
It was nearly correct. I just
Changed searchScope to LDAPConnection.SCOPE_SUB;
Changed loginDN = DOMAIN\MyNTusername;
Changed baseDN = "dc=mydomain,dc=mycompany,dc=com";
Changed true to false in lc.search.
Not sure which of those changes caused it to start working.

Categories

Resources