I'm trying to set user properties for a newly created user. Properties like samaccount and userprincipalname work but other properties like address and phone number don't. I'm making use of textboxes. Here's a property example:
newUser.Properties["givenName"].Value = txt.FName
The error I get is that the field is invalid yet the other fields named above do work. Could anyone explain why this is?
I think this help you out..
public void SetAdInfo(string objectFilter, Property objectName,
string objectValue, string LdapDomain)
{
string connectionPrefix = "LDAP://" + LdapDomain;
DirectoryEntry entry = new DirectoryEntry(connectionPrefix);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(cn=" + objectFilter + ")";
mySearcher.PropertiesToLoad.Add(""+objectName+"");
SearchResult result = mySearcher.FindOne();
if (result != null)
{
DirectoryEntry entryToUpdate = result.GetDirectoryEntry();
if (!(String.IsNullOrEmpty(objectValue)))
{
if (result.Properties.Contains("" + objectName + ""))
{
entryToUpdate.Properties["" + objectName + ""].Value = objectValue;
}
else
{
entryToUpdate.Properties["" + objectName + ""].Add(objectValue);
}
entryToUpdate.CommitChanges();
}
}
entry.Close();
entry.Dispose();
mySearcher.Dispose();
}
You can check this article for more info:
https://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C
The full code that creates a user is this:
private void btn_AddStudent_Click(object sender, EventArgs e)
{
try
{
// Username en wachtwoord in variabelen zetten.
string userName = generator(8);
string password = generator(8);
// Juiste OU pad aangeven. Afhankelijk van geselecteerde richting.
string ouString = "OU = " + cmb_Study.Text;
string LDAPstring = "LDAP://" + ouString + ", DC=DR, DC=GUI";
DirectoryEntry dirEntry = new DirectoryEntry(LDAPstring);
// User aanmaken.
string userString = "CN = " + userName;
DirectoryEntry newUser = dirEntry.Children.Add(userString, "user");
newUser.CommitChanges();
newUser.Properties["userPrincipalName"].Add(userName + "#DR.GUI");
newUser.Properties["sAMAccountName"].Value = userName;
newUser.Invoke("SetPassword", new object[] {password});
newUser.Properties["initials"].Value = txt_Initials;
newUser.Properties["Given-Name"].Value = txt_FName;
newUser.Properties["sn"].Value = txt_LName;
newUser.Properties["mail"].Value = txt_Mail;
newUser.Properties["mobile"].Value = txt_Mobile;
newUser.Properties["telephoneNumber"].Value = txt_Telephone;
newUser.Properties["streetAddress"].Value = txt_Street + " " + txt_Number;
newUser.Properties["postalCode"].Value = txt_PostalCode;
newUser.Close();
dirEntry.Close();
newUser.Dispose();
dirEntry.Dispose();
MessageBox.Show("User has been succesfully added");
There's a catch under that piece of code that does work.
Related
I am tasked with implementing single sign-on for our customers as part of our next release, the idea is as follows:
When our customer has access to the website, they won't need to go through an extra login step, because they are already logged into their PC with their AD account and only accounts in AD will have can access the website.
I have tried to research and learn but there seems to be no specific guide.
I'm using web forms and AD in windows server 2019.
Please suggest steps or references to me. Thanks a lot.
using System.DirectoryServices;
using System.Collections.Generic;
namespace LdapAuthentication
{
public class LdapAuthentication
{
private string _path;
private string _filterAttribute;
public LdapAuthentication(string path)
{
_path = path;
}
public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
try
{
//Bind to the native AdsObject to force authentication.
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
//Update the new path to the user in the directory.
_path = result.Path;
_filterAttribute = (string)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
public string GetGroups()
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
StringBuilder groupNames = new StringBuilder();
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
string dn;
int equalsIndex, commaIndex;
for (int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
{
dn = (string)result.Properties["memberOf"][propertyCounter];
equalsIndex = dn.IndexOf("=", 1);
commaIndex = dn.IndexOf(",", 1);
if (-1 == equalsIndex)
{
return null;
}
groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
groupNames.Append("|");
}
}
catch (Exception ex)
{
throw new Exception("Error obtaining group names. " + ex.Message);
}
return groupNames.ToString();
}
}
}
I tried to create reset password and user creation functions for Active Directory. On my PC with below code is works just fine without any error. But when I publish to the server, I received error: Exception has been thrown by the target of an invocation.
ADResult hasil = new ADResult();
DirectoryEntry de = new DirectoryEntry(_path, _adminID, _adminPassword, AuthenticationTypes.Secure);
DirectorySearcher ds = new DirectorySearcher(de);
string query = string.Format("(&(objectCategory=person)(sAMAccountName={0}))", user.userID);
ds.Filter = query;
ds.Sort.PropertyName = "CN";
ds.SearchScope = SearchScope.Subtree;
ds.CacheResults = false;
try
{
SearchResult sr = ds.FindOne();
if (sr == null)
{
hasil.errorCode = -1;
hasil.result = "User name not found in this domain.";
}
else
{
DirectoryEntry userCredentials = sr.GetDirectoryEntry();
userCredentials.Invoke("SetPassword", new Object[] { user.password });
userCredentials.CommitChanges();
userCredentials.Close();
hasil.errorCode = 0;
hasil.result = "Password for " + user.userID + " changed successfully.";
}
}
catch (Exception e)
{
hasil.errorCode = -1;
hasil.result = e.Message + "<br/>" + e.StackTrace + "<br/>" + e.Source;
}
return hasil;
Is there something configuration/settings that I missed on the server side?
I changed my code using
UserPrincipal
instead of
DirectoryEntry
and it works perfectly.
I use this code:
PrincipalContext PrincipalContext4 = new PrincipalContext(ContextType.Domain, "full_domain_name.com", "OU=User_OU,DC=domain_name,DC=co,DC=id", _adminID, _adminPassword);
UserPrincipal UserPrincipal1 = new UserPrincipal(PrincipalContext4, user.userID, user.password, true);
//User Logon Name
UserPrincipal1.UserPrincipalName = user.userID;
UserPrincipal1.Name = user.firstName + " " + user.lastName;
UserPrincipal1.GivenName = user.firstName;
UserPrincipal1.Surname = user.lastName;
UserPrincipal1.DisplayName = user.firstName + " " + user.lastName;
UserPrincipal1.Enabled = true;
UserPrincipal1.Save();
I still don't know why I use DirectoryEntry is not working on windows server 2019
That't not the exact error message,real error must be wrapped.You can write loggers or event logging after lines which you think could be culprit.You can check event log on that server if you can find elaborated stack Trace. You can check that user have admin privilege for that server to lookup in AD.
I have a C# (WinForms) application that can scan documents via a printer. After scanning, I will be able to enter document details on it and have a button to finalize the documents. The documents details and info will be stored in my database ABC in certain tables.
Now, I have another web application written in Java(IntelliJ) that has some button functionality to upload documents and then start a workflow and route it to another user to approve the document. I won't go into detail on the specifics. This application also connects to the same database ABC.
So now comes the tougher part, I need to link these two applications in a way that when I finalize my document
on the C# application, it has to auto trigger the workflow on the web application side. Rather than manually starting the workflow on the web application, it would just call or trigger the workflow, so I do not need to access the web application at all for the process to start.
private void FinButton_Click(object sender, EventArgs e)
{
int count = 0;
var txtBoxFields = new List<TextBox>
{
textBox1,
textBox2,
textBox3,
textBox4,
textBox5,
textBox6,
textBox7,
textBox8,
textBox9,
textBox10,
textBox11,
textBox12,
textBox13,
textBox14,
textBox15
};
var templateFields = new List<String>
{
"T1",
"T2",
"T3",
"T4",
"T5",
"T6",
"T7",
"T8",
"T9",
"T10",
"T11",
"T12",
"T13",
"T14",
"T15"
};
//long tid = 0;
//Start insert query into templatebatch table in db
var dbConnection2 = DBConnection.Instance();
dbConnection2.DatabaseName = ConfigurationManager.AppSettings["dbName"];
if (dbConnection2.IsConnect())
{
bool test = true;
for (int i = 1; i <= 15; i++)
{
var input = txtBoxFields[i - 1].Text;
var insertQuery = "INSERT INTO templateinfo(TID, THEADER, " + templateFields[i - 1] + ") VALUES(#tid, #theader,#t" + i + ")";
var insertCmd = new MySqlCommand(insertQuery, dbConnection2.Connection);
insertCmd.Parameters.AddWithValue("#tid", tid);
insertCmd.Parameters.AddWithValue("#theader", "N");
if (String.IsNullOrEmpty(input))
{
count = 1;
insertCmd.Parameters.AddWithValue("#t" + i, String.Empty);
break;
}
else
{
if (test)
{
insertCmd.Parameters.AddWithValue("#t" + i, txtBoxFields[i - 1].Text);
insertCmd.ExecuteNonQuery();
test = false;
var selectQuery = "select TINFOID from templateinfo where TID=" + tid + " and THEADER = 'N'";
var selectCmd = new MySqlCommand(selectQuery, dbConnection2.Connection);
var selectReader = selectCmd.ExecuteReader();
using (MySqlDataReader dr = selectReader)
{
while (dr.Read())
{
tinfoid = Convert.ToInt32(dr["TINFOID"]);
}
}
}
else
{
var updateQuery = "update templateinfo set " + templateFields[i - 1] + "='" + txtBoxFields[i - 1].Text + "' where TINFOID = '" + tinfoid + "' and TID=" + tid + " and THEADER='N'";
var updateCmd = new MySqlCommand(updateQuery, dbConnection2.Connection);
var updateReader = updateCmd.ExecuteReader();
using (var reader = updateReader)
{
}
}
}
}
}
if (count == 1)
{
//MessageBox.Show("Input field(s) cannot be left empty.");
}
//Finalize here
var client = new LTATImagingServiceClient();
client.Finalize(userID, tid, tinfoid, batchID);
Debug.WriteLine(userID + ", " + tid + ", " + tinfoid + ", " + batchID);
var batchName = templateView.SelectedNode.Text;
var folderPath = #"C:\temp\batches\" + mastertemplatename + #"\" + subtemplatename + #"\" + batchName + #"\";
ThumbnailLists.Items.Clear();
// var img = Image.FromFile(#"C:\temp\batch-done.png");
if (ImageBox.Image != null)
{
ImageBox.Image.Dispose();
}
ImageBox.Image = null;
try
{
using (new Impersonation(_remoteDomain, _remoteUser, _remotePassword))
{
// MessageBox.Show(_remoteUser);
// MessageBox.Show(_remotePassword);
var tPath = #"\\126.32.3.178\PantonSys\SAM\Storage\3\" + mastertemplatename + #"\" + subtemplatename + #"\" + batchName + #"\";
bool exists = System.IO.Directory.Exists(tPath);
if (!exists)
{
System.IO.Directory.CreateDirectory(tPath);
}
string[] fileList = Directory.GetFiles(folderPath, "*");
foreach (var file in fileList)
{
File.Copy(file, tPath + Path.GetFileName(file));
}
CurrentPageBox.Text = "";
NumberPageBox.Text = "";
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
MessageBox.Show(ex.Message);
}
var dbConnection = DBConnection.Instance();
dbConnection.DatabaseName = ConfigurationManager.AppSettings["dbName"];
if (dbConnection.IsConnect())
{
var deleteBatchQuery = "DELETE FROM templatebatch WHERE batchname ='" + templateView.SelectedNode.Text + "'";
var deleteBatchCmd = new MySqlCommand(deleteBatchQuery, dbConnection.Connection);
var deleteBatchReader = deleteBatchCmd.ExecuteReader();
using (var reader = deleteBatchReader)
{
while (reader.Read())
{
}
}
templateView.Nodes.Remove(templateView.SelectedNode);
Directory.Delete(folderPath, true);
MessageBox.Show("Successfully Transferred.");
foreach (var txtFields in txtBoxFields)
{
txtFields.Text = "";
txtFields.Enabled = false;
}
finButton.Visible = false;
finButton.Enabled = false;
}
bindButton.Visible = false;
}
Would this be possible to achieve or just being far-fetched?
I would appreciate any suggestions or pointers on this. Do let me know if there is anything unclear in my explanation.
EDIT:
Request URL: http://126.32.3.178:8111/process/taskmanager/start/start.jsp
Request Method: POST
Status Code: 200 OK
Remote Address: 126.32.3.178:8111
Referrer Policy: no-referrer-when-downgrade
Is there a way I could call this from the C# application?
You can send your file directly from your C# app with use of Http client. Here is code sample:
private async Task<bool> Upload(string filePath)
{
const string actionUrl = #"http://126.32.3.178:8111/process/taskmanager/start/start.jsp";
var fileName = Path.GetFileName(filePath);
var fileBytes = File.ReadAllBytes(filePath);
var fileContent = new ByteArrayContent(fileBytes);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileContent, fileName);
var response = await client.PostAsync(actionUrl, formData);
return response.IsSuccessStatusCode;
}
}
Also, note that there maybe some sort of authentication should be performed before you can post a request.
I'm passing username and password to check whether a user is valid from Active Directory.
Here is my code :
private bool ValidUser(string name, string userPwd)
{
string UserName = "XXXXXXXXXX";
string Password = "XXXXXXXXXXXXX";
DirectoryEntry objRootEntry = new DirectoryEntry("XXXXXXXX.com", UserName, Password);
DirectorySearcher objADSearcher = new DirectorySearcher(objRootEntry);
objADSearcher.Filter = ("(&(sAMAccountType=xxxxxxxxx)(samAccountName=" + name + "))");
SearchResult objResult = objADSearcher.FindOne();
DirectoryEntry objLoginEntry = (objResult != null) ? objResult.GetDirectoryEntry() : null;
if (objLoginEntry != null)
{
return true;
}
return false;
}
Now it checks the user name alone.I need to check whether the entering password (userPwd) matches with the Active directory. How to do that.
Please help me out.
//You are entering password while finding in Directory entry is enough. Don't need to check again
Check this detail code
public bool ValidateUser(string domain, string username, string password,string LdapPath, out string Errmsg)
{
Errmsg = "";
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(LdapPath, domainAndUsername, password);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
// Update the new path to the user in the directory
LdapPath = result.Path;
string _filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
Errmsg = ex.Message;
throw new Exception("Error authenticating user." + ex.Message);
}
}
I was able to get the account-disabling part of my code to work, but to keep our AD tree even more clean, we have a specifically created !Disabled OU. I'd like my code to be able to both disable the computer account and move it into the !Disabled OU.
Here's what I have so far:
string computerName = Environment.MachineName;
using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, null, "username", "password"))
{
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(domainContext, computerName);
if (computer != null)
{
try
{
computer.Enabled = false;
label3.Visible = true;
computer.Save();
label3.Text = "Computer was disabled in Active Directory." + "\n";
try
{
string LdapDomain = "prefix.domain.suffix";
string distinguishedName = string.Empty;
string connectionPrefix = "LDAP://" + LdapDomain;
DirectoryEntry entry = new DirectoryEntry(connectionPrefix);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=computer)(|(cn=" + computerName + ")(dn=" + computerName + ")))";
SearchResult result = mySearcher.FindOne();
if (result == null)
{
label3.Text += ("Unable to locate the distinguishedName for the object " + computerName + " in the " + LdapDomain + " domain." + "\n");
}
else if (result != null)
{
DirectoryEntry directoryObject = result.GetDirectoryEntry();
distinguishedName = "LDAP://" + directoryObject.Properties["distinguishedName"].Value;
label3.Text += ("Distinguished name is " + distinguishedName + "\n");
string newLocation = "OU=!Disabled,DC=prefix,DC=domain,DC=suffix";
DirectoryEntry nLocation = new DirectoryEntry("LDAP://" + newLocation);
string newName = directoryObject.Name;
//directoryObject.MoveTo(nLocation, newName);
DirectoryEntry moveParent = new DirectoryEntry(newLocation);
directoryObject.MoveTo(moveParent); //Comes from Microsoft example, as prior may have been possible cause of errors.
label3.Text += ("Successfully moved computer to the !Disabled OU");
nLocation.Close();
directoryObject.Close();
entry.Close();
entry.Dispose();
mySearcher.Dispose();
}
else
{
label3.Text += ("Unexpected error in moving computer.");
}
button1.Visible = true;
}
catch (Exception p)
{
label3.Text += ("Failed to move computer with exception " + p);
button1.Visible = true;
}
/*
public void Move(string objectLocation, string newLocation)
{
//For brevity, removed existence checks
DirectoryEntry eLocation = new DirectoryEntry("LDAP://" + objectLocation);
DirectoryEntry nLocation = new DirectoryEntry("LDAP://" + newLocation);
string newName = eLocation.Name;
eLocation.MoveTo(nLocation, newName);
nLocation.Close();
eLocation.Close();
}
*/
}
catch (Exception x)
{
label3.Visible = true;
label3.Text = "Unable to disable computer with exception " + x;
button1.Visible = true;
}
}
else if (computer == null)
{
label3.Visible = true;
label3.Text = "Computer was not found in Active Directory.";
button1.Visible = true;
}
else
{
label3.Visible = true;
label3.Text = "Unexpected error in computer search.";
button1.Visible = true;
}
}
The display aspects are pretty sloppy, but it's a quick and dirty Windows Form that displays all the things that are going on. The problem I'm having is that even though I have the distinguished name and can get a DirectoryEntry object from the search, when I call the MoveTo() method I get an error about the object not existing or not being found. Could someone point me in the right direction here?
I've considered binding to the two different OU's and using the DirectoryEntry.Children.Add() and DirectoryEntry.Children.Remove() methods as a workaround, but that doesn't fix the problem I'm having traversing AD.