Having problems with accessing active directory using C# - active-directory

My IS manager provided me with parameters in this format and I am trying use C# to validate a user against Active directory.
Here is a code sample (of course not the real credentials). How do I use these parameters to against a DirectoryEntry object so I can search for users etc.
provider-url=ldap://email.acmetech.com:1111/
base-dn= DC=acmetecg,DC=com
security-authentication= simple
security-principal= CN=ldap,cn=users,DC=acmetech,DC=com
security-credentials= Ldap000
I know this should be simple but its been years since I've programmed active directory.
Edit: How do I pass my params to a directory entry object so I can query objects in AD?

Using .NET 3.5 it's pretty easy.
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "acmetecg"))
{
// check the creds (assuming ldap is the user name, and ldap000 is the password)
bool isValid = pc.ValidateCredentials("ldap", "ldap000")
}

Related

Fetch the user details from LDAP Active directory from MULTIPLE domains using Java

My requirement is, based on user id I need to fetch the user details (like first name and last name ) from LDAP active directory.
But the catch here is we don't know in which domain user will be exists. And we have around 12 different domains each has different provider URL.
Currently I am able to fetch the user details from one domain when I provide the input as -
1. providerURL (this is domain specific, each domain has different URL)
2. username
3. password
Since the problem is we don't know in which domain user will be exists, I don't want to make a sequential or parallel calls to search user one by one in each domain .
Is there any other way around so that in one call I can search particular user across all available domains?
looking any simple Java based or spring-java based solution.
We heard there is global Catlog in LDAP active directory but not aware of it much. Is it possible that if we create some global account (which will act as super user) then using that global account details we can then search particular user across all domains.
I am not aware of LDAP active directory server structure, if I can have
service account (with special role access permissions) so that using it I can search user details across all domains.
Another query is -> instead of global service account, If we create a service account in one domain with some extra special role access permissions then can I use it to search user from any other domains ?
Please suggest the solution approach for our project requirement.
Currently I am able to fetch the user details from one domain using that using below code->
public class LDAPExaminer {
public static void main(String[] args) {
LDAPExaminer ldapExaminer = new LDAPExaminer();
ldapExaminer.printUserBasicAttributes("userId", ldapExaminer.getLdapContext());
}
public LdapContext getLdapContext() {
LdapContext ctx = null;
try {
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, "user#domain");
env.put(Context.SECURITY_CREDENTIALS, "password");
env.put(Context.PROVIDER_URL, "ldap://example.domain.com");
env.put(Context.REFERRAL, "follow");
System.out.println("Attempting to Connect...");
ctx = new InitialLdapContext(env, null);
System.out.println("Connection Successful.");
} catch (NamingException nex) {
System.out.println("LDAP Connection: FAILED");
nex.printStackTrace();
}
return ctx;
}
private void printUserBasicAttributes(String username, LdapContext ctx) {
try {
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {"distinguishedName", "UN", "givenname", "mail", "telephonenumber", "canonicalName", "userAccountControl", "accountExpires"};
constraints.setReturningAttributes(attrIDs);
NamingEnumeration answer = ctx.search("DC=example,DC=domain,DC=com", "sAMAccountName=" + username, constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
System.out.println(attrs.get("distinguishedName"));
System.out.println(attrs.get("givenname"));
System.out.println(attrs.get("sn"));
System.out.println(attrs.get("mail"));
System.out.println(attrs.get("telephonenumber"));
System.out.println(attrs.get("canonicalName"));
System.out.println(attrs.get("userAccountControl"));
System.out.println(attrs.get("accountExpires"));
} else {
throw new Exception("Invalid User");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
The Global Catalog works the same way as a normal LDAP connection, but it just runs from a different port. So you just need to specify the GC port of 3268:
env.put(Context.PROVIDER_URL, "ldap://example.domain.com:3268");
That's it.
The GC will let you find all accounts in the same AD forest, which is a group of domains that have a complete trust in each other. Accounts on one domain can authenticate on the other and permissions can be easily granted between them.
You will have to know how your 12 domains are organized. You will have to make one search for each AD forest. You can't make one search that will find accounts in separate forests.
There are other caveats, like some AD attributes are not replicated to the Global Catalog. For example, the accountExpires attribute that you are looking for is not replicated to the GC. If you look up the attribute on the Microsoft site, you'll see that "In Global Catalog" is "False".

Need to supply DB password to run evolutions at run time - Play + Slick

I need to avoid storing plain text passwords in config files, and so I'm storing the Postgres password externally (in AWS Secrets Manager).
Similarly to the solution provided here:
Encrypted database password in Play + Slick + HikariCP application, I've been able to override dbConfig and supply the password to my DAO classes like this:
trait MyDaoSlick extends MyTableDefinitions with HasDatabaseConfig[MyPostgresDriver] {
protected val dbConfigProvider: DatabaseConfigProvider
override protected val dbConfig: DatabaseConfig[MyPostgresDriver] = secretDbConfig(dbConfigProvider)
def secretDbConfig(dbConfigProvider: DatabaseConfigProvider): DatabaseConfig[MyPostgresDriver] = {
DatabaseConfig.forConfig[MyPostgresDriver]("", dbConfigProvider.get[MyPostgresDriver].config
.withValue("db.user", ConfigValueFactory.fromAnyRef(getUN))
.withValue("db.password", ConfigValueFactory.fromAnyRef(getPWD)))
}
}
This works great for regular DB queries, however evolutions bypass this and still expect the username and the password to be in application.conf, which kind of defeats the purpose of the password being a secret.
Any advice on how evolutions could get the DB credentials from a function?
I ran into the same issue, and I managed to resolve it like this:
Create a custom application loader, as shown here: https://www.playframework.com/documentation/2.7.x/ScalaDependencyInjection#Advanced:-Extending-the-GuiceApplicationLoader
Inside the custom loader's builder, append the DB configuration parameters for Slick:
val extra = Seq(
"slick.dbs.default.db.url" -> secrets.url,
"slick.dbs.default.db.user" -> secrets.user,
"slick.dbs.default.db.password" -> secrets.pass
)
Nothing else needs to be changed, as you've basically added the configuration needed for anything Slick, evolutions included.
On older versions of Play, we used to do this inside GlobalSettings.onLoadConfig, but, at some point, that has been deprecated in favour of DI. More details here: https://www.playframework.com/documentation/2.7.x/GlobalSettings

IFSFile when user PASSWORD *NONE

I am facing some troubles while trying to create an IFSFile using IFSFile object from JT400.jar. The problem that I am facing is when the process that calls the JAVA is called by a BATCH user(without login enabled into AS400 machine).
Exception given
Password is *NONE.:XXXXXX com.ibm.as400.access.AS400SecurityException: Password is *NONE.:XXXXXX
at com.ibm.as400.access.AS400ImplRemote.returnSecurityException(AS400ImplRemote.java:2219)
at com.ibm.as400.access.CurrentUser.getUserInfo(CurrentUser.java:79)
at com.ibm.as400.access.AS400ImplRemote.getPassword(AS400ImplRemote.java:1411)
at com.ibm.as400.access.AS400ImplRemote.signon(AS400ImplRemote.java:2507)
at com.ibm.as400.access.AS400.sendSignonRequest(AS400.java:3351)
at com.ibm.as400.access.AS400.promptSignon(AS400.java:2938)
at com.ibm.as400.access.AS400.signon(AS400.java:4246)
at com.ibm.as400.access.AS400.connectService(AS400.java:1336)
at com.ibm.as400.access.IFSFile.chooseImpl(IFSFile.java:630)
at com.ibm.as400.access.IFSFile.copyTo(IFSFile.java:729)
at com.ibm.as400.access.IFSFile.copyTo(IFSFile.java:699)
Code used:
AS400 as400 = new AS400("localhost");
//Obtain the template path
String templatePath ="/HOME/XXX/auth.txt";
IFSFile templateAuth = new IFSFile(as400,templatePath);
templateAuth.copyTo(fileXML + ".xml");
I have check some opened threads but no results obtained. (find below the threads commented)
JT400 Read File From IFS with user without password
Java IFSFile on Iseries testing over PC
There is any option to generate an IFSFile when the process is called by a BATCH user(note that when the process is called by a user with login enabled, the process is working as expected)
I need something similar to what is done when a JDBCAppender is created, JDBCAppender object allows setUser(null) and setPassword(null) to enable batch users to write into a table.
Thanks all!
I have recently had a similar problem when trying to use CommandCall whilst running under a profile with PASSWORD is *NONE. I (eventually) solved it by using the native Java toolbox at /QIBM/ProdData/Java400/jt400ntv.jar (which happens to be a symbolic link). I didn't have to make any code changes:
AS400 as400 = new AS400();
CommandCall cc = new CommandCall(as400);
String wrkenvvar_cmd = MessageFormat.format("ADDENVVAR ENVVAR('JAVA_HOME') VALUE(''{0}'') REPLACE(*YES)",path);
boolean ok = cc.run(wrkenvvar_cmd);
I hope that helps.

Silveright - extending AuthenticationService to provide custom authentication

I am trying to add to the authentication system provided in the Silverlight 4 business template as my model does not completely fit that provided in the template. I have an existing web service that performs my authentication and provides roles and also permitted operations for each role. This is the model provided by AzMan/Authentication Manager.
However, rather than just get a single role, following authentication I provide the user with a list of available roles and allow the user to select one of these roles and then get a list of operations/actions for that selected role.
The problem that I have is that I can't work out how to add new methods to the authenticationservice to allow me to get the operations for the current user, and currently selected role in order to complete the login process e.g.
public SessionInfo GetOperations(string username, string selectedRole)
{
SessionInfo sessionInfo;
using (AzManServiceClient azClient = new AzManServiceClient("AnonymousAuthentication"))
{
sessionInfo = azClient.LoginUserByUsername("msldap://CN=LiveApps,CN=Program Data,DC=HLSUK,DC=local", "AIRS", selectedRole, null, username);
}
return sessionInfo;
}
The above method is not accessible from the LoginForm.xaml.cs using WebContextBase.Current.Authentication... Only methods such as Login are visible which is even more baffling because I can't see these methods in authenticationbase. I'm completely confused. How do I add new methods to the authentication service, or should I create a new domainservice, or should I access the azman service to get the operations directly from the silverlight client.
Have you tried to Override the methods in AuthenticationBase?
Then you can expand your authenticationservice with whatever logic you want.
<EnableClientAccess()>
Public Class AuthenticationRiaService
Inherits AuthenticationBase(Of UserAccount)
Protected Overrides Function ValidateUser(ByVal userName As String, ByVal password As String) As Boolean
End Function
End Class
Also set
WebContext.Current.Authentication To your authenticationservice as found in namespace System.ServiceModel.DomainServices.Client.ApplicationServices
Sorry for stupid VB code. :D

System.DirectoryServices vs system.directoryservices.accountmanagement

I have an array (propertyList) that contains the names of certain Active Directory properties whose data I want to retrieve. Using Ironpython and .NET library System.DirectoryServices I solve the retrieval of properties to be loaded in this way:
for propertyActDir in propertyList:
obj.PropertiesToLoad.Add(propertyActDir)
res = obj.FindAll()
myDict = {}
for sr in res:
for prop in propertyList:
myDict[prop] = getField(prop,sr.Properties[prop][0])
The function getField is mine. How can I solve the same situation using the library system.directoryservices.accountmanagement? I think it is not possible.
Thanks.
Yes, you're right - System.DirectoryServices.AccountManagement builds on System.DirectoryServices and was introduced with .NET 3.5. It makes common Active Directory tasks easier. If you need any special properties you need to fall back to System.DirectoryServices.
See this C# code sample for usage:
// Connect to the current domain using the credentials of the executing user:
PrincipalContext currentDomain = new PrincipalContext(ContextType.Domain);
// Search the entire domain for users with non-expiring passwords:
UserPrincipal userQuery = new UserPrincipal(currentDomain);
userQuery.PasswordNeverExpires = true;
PrincipalSearcher searchForUser = new PrincipalSearcher(userQuery);
foreach (UserPrincipal foundUser in searchForUser.FindAll())
{
Console.WriteLine("DistinguishedName: " + foundUser.DistinguishedName);
// To get the countryCode-attribute you need to get the underlying DirectoryEntry-object:
DirectoryEntry foundUserDE = (DirectoryEntry)foundUser.GetUnderlyingObject();
Console.WriteLine("Country Code: " + foundUserDE.Properties["countryCode"].Value);
}
System.DirectoryServices.AccountManagement (excellent MSDN article on it here) is designed to help you more easily manage user and groups, e.g.
find users and groups
create users and groups
set specific properties on users and groups
It is not designed to handle "generic" property management like you describe - in that case, simply keep on using System.DirectoryServices, there's nothing stopping you from doing this!
Marc

Resources