C# Connection to Oracle Identity Management LDAP Server - c#

We are working with another company whom has a Oracle Identity Management Server setup. We are to connect to this and authenticate users based on LDAP data retried from the server.
We have tried to plug into this by using an LdapConnection object passing in the server name and port along with the Network credentials they are providing to us so we are using a AuthType of Basic. However on the Bind() we are always failing because it says that we have invalid credentials. We have worked with the client to make sure they are correct and we have been able to log in to Oracle Identity Management with the credentials, although the user name we had to use data from the SearchRequests distinguished name. But even using that we keep on receiving the same error. Client is also using the credentials to connect via Java.
This is an issue where as I think there is no solution really, but does anyone out there have any idea on how to go about doing this? We have the same code running which is working and pulling from Active Directory. So our code should be fine as long as Oracle supports connecting in this fashion. But finding anything in regards to this topic is like pulling teeth.
Anyone have any experience with this out there? Please let me know I would be happy to provide any additional details if needed.
Thanks in advance!

I recently fumbled through connecting to OID using LDAP. Here's the code that ended up working for me:
// make sure the server and port are correct
using (var ldap = new LdapConnection("ldap.company.com:3060"))
{
// make sure to pass the username as a distinguishedName
var dn = string.Format("cn={0},cn=users,dc=company,dc=com", username);
// passing null for the domain worked for me
var credentials = new System.Net.NetworkCredential(dn, password, null);
ldap.AuthType = AuthType.Basic;
try
{
ldap.Bind(credentials);
return true;
}
catch (LdapException ex)
{
return false;
}
}

Related

Programatically creating an AD account through secure LDAP

Currently I'm successfully creating AD accounts through C# via an LDAP connection using the PrincipalContext. I create a new UserPrincipal, apply the various properties as required and call save()
Essentially something like this
using(var pc = new PrincipalContext(ContextType.Domain))
{
using(var up = new UserPrincipal(pc))
{
up.SamAccountName = "whatever";
up.EmailAddress = "test#example.com";
up.SetPassword(password);
up.Enabled = true;
up.Save();
}
}
All works fine but now we need to do the same thing over a secure LDAP connection and I'm struggling to find any info online regarding the specifics of how to do this. This makes me think that perhaps there's no difference from how I'm currently doing and instead all I need do is make sure the server supports LDAPS and is configured to use it.
Perhaps SO is wrong forum for this, am happy to move the question to a different forum if so.
The default TCP port for LDAP is 389. That's what's used if you don't tell it otherwise. To use LDAPS, you have to specify the LDAPS port of 636. For example:
using(var pc = new PrincipalContext(ContextType.Domain, "example.com:636"))
Where example.com is your domain name.
However, using LDAPS requires that your computer trusts the SSL certificate that the server uses. Sometimes a self-signed cert is used and that will cause this to fail. PrincipalContext doesn't report certificate errors. It reports it as if the server could not be contacted. So if you have an issue there, you can use this PowerShell script to download the certificate and inspect it:
$webRequest = [Net.WebRequest]::Create("https://example.com:636")
try { $webRequest.GetResponse() } catch {}
$cert = $webRequest.ServicePoint.Certificate
$bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
set-content -value $bytes -encoding byte -path "certificate.cer"
Change the first line to have your domain name. If that works, there will be a file called certificate.cer that you can double-click on and inspect. If your computer doesn't trust it, you will see a message saying so. If that is a problem, you probably just need to install the root certificate as a "Trusted Root Certificate" on your computer.

The LDAP Server is Unavailable using PrincipalContext and ADLDS

We are making use of ADLDS for our user management and authentication. We can successfully query the instance without problems. However, trying to perform an operation such as SetPassword will fail or even trying to create a new user if a password is not set, it fails. I can successfully update a user as long as its not password I'm trying to update. I've been reading a lot of different articles relating to this but not finding a resolution. Posting to see if I can get some fresh perspective on this issue, thanks for any input.
EXAMPLE
ContextType ctxType = ContextType.ApplicationDirectory;
string server = "myadldsserver.com";
string usersCN = "CN=Users,..."; // container where users reside
ContextOptions ctxOpts = ContextOptions.SimpleBind;
string uname = "myuser";
string pswrd = "mypass";
using(var ctx = new PrincipalContext(ctxType, server, usersCN, ctxOpts, uname, pswrd)
using(var newUser = new UserPrincipal(ctx)) {
newUser.Name = "newusername";
newUser.Enabled = true;
newUser.UserPrincipalName = "newusername";
newUser.Save();
newUser.SetPassword("newuserpassword");
}
ERROR 1
The first problem I encounter if I try to create a new UserPrincipal and call Save without having set the password like in Example above I get the exception A constraint violation occurred. with an InnerException extend message of 0000052D: AtrErr: DSID-033807D7, #1:0: 0000052D: DSID-033807D7, problem 1005 (CONSTRAINT_ATT_TYPE), data 2246, Att 9005a (unicodePwd)
Because of this error I tried moving the SetPassword before calling Save along with other approaches I found online such as getting the DirectoryEntry from the UserPrincipal and trying to call SetPassword but got a different error.
ERROR 2
Calling SetPassword before calling UserPrincipal.Save, when save is called, results in the error The directory property cannot be found in the cache.
Note that the same error will occur if I trying calling ResetPassword or getting a DirectoryEntry and calling Invoke("SetPassword"... as well
ERROR 3
From my research most seem to indicate this could have to do with needing to access AD LDS using a Secure connection. So, I changed my server to include the port of 636 string server = "myadldsserver.com:636" and I changed the ContextOptions to be ContextOptions.SimpleBind | ContextOptions.SecureSocketLayer.
Making these changes when the PrincipalContext is being constructed I get the following exception The server could not be contacted. with an inner exception of The LDAP server is unavailable., HResult is -2146233087
JAVA and LDP
To add some background to this, we do have similar code written in an older Java application. We are trying to port some of this logic over to .NET side in C#. The code in Java makes use of a Java keystore that contains the certificate that was generated on the AD LDS server. The Java application of course has no issues using the SSL port. We know the server seems to be configured correctly, it's just an issue of how to access it from .NET side.
Is there an equivalent on the .NET side such as the keystore in Java? We know that an SSL connection can be made to server. We have verified this using LDP as well.
GOALS
Be able to create a new user and set their password during creation
Be able to ResetPassword or ChangePassword for a user
Connect to our AD LDS instance from .NET securely
Have you tried using Microsoft Management Console to import the certificate?
Two ways to install the certificate
Either
Open a cmd.exe console and type "MMC"
File > Add/Remove Snap-In...
Select Certificates, click Add
Choose Computer Account and Local Computer when prompted, then OK...
Certificates should now be showing under Console Root
Certificates > Trusted Root Certification Authorities > Certificates > (right-click) > All Tasks > Import Certificate...
Find the certificate you want to import, click Next and choose defaults (Trusted Root Certification Authorities should already be
selected)
Click Next, Finish
(or)
Simply double-click on the .cer file for the certificate in Windows
Explorer, click Install Certificate... > Next > select the option to
"Place all certificates in following store" > Browse... > Select
Trusted Root Certification Authorities. Continue with next until done.
At this point your certificate is installed, and you should be able to communicate securely with your ADLDS server.

authentication failed while connecting to tfs using tfs api

I am facing a strange issue.I want to connect tfs server using tfs api programmitcally.
Even after giving proper authentcaion crediatials it is failing.But if I do it manually by typing tfs server name in browser its got connected.
code:
TeamFoundationServer tfs = new TeamFoundationServer(new Uri("http://10.112.205.145:8080/tfs"), new NetworkCredential(#"usrname", "pwd", "domain"));
tfs.EnsureAuthenticated()
Please suggest.
A simple way to do this is to add the "Syetem.Net" namespace to your code and then use the "CredentialCache" object. Using "DefaultCredentials" will Authenticate with the credentials of the active user.
// connect to the collection
using (TfsTeamProjectCollection teamProjectCollection = new TfsTeamProjectCollection("http://server:8080/tfs/DefaultCollection", CredentialCache.DefaultCredentials))
{
//Do Stuff here
}
Have you tried doing it this way..
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(
new Uri(http://server:8080/tfs/DefaultCollection,
new System.Net.NetworkCredential("domain_name\\user_name", "pwd"));
collection.EnsureAuthenticated();
For your problem, normally you get an error like:
Possible reasons for failure include:
- The name, port number, or protocol for the Team Foundation Server is incorrect.
- The Team Foundation Server is offline.
- The password has expired or is incorrect.
The root cause of your problem is that the URI should be ended up with the collection name. So the fix would be, to change "http://10.112.205.145:8080/tfs" to "http://10.112.205.145:8080/tfs/%YourCollectionName%", then it will work! :-)

Connecting to remote mysql database with API

I am designing a desktop application in C#, which needs to be connected to my online mysql database. I tried to give access in control panel a "%" which means from any IP, but it is not working. May be the hosting provider (bigrock) not allowing that.
Alternatively, I am trying to write some code in online on PHP which will get the "sql" as parameter and returns the output as JSON format using json_encode.
Is there any alternate methods which is better approach.
What error do you get when you try to connect? Timeout = firewalled; Permission denied = permissions not right etc.
One solution is to create a proxy with pre-coded queries (let's call then "stored procedures") - you can then say "Run query 5, parameters A, B and C". As this would be server-server (not public) you just need to add some basic authentication system (e.g. shared rotating key, checksum using parameters etc), but also ensure the queries are not dangerous if any parameters are thrown at it.
Disclaimer: It's a solution, but I'm not actually recommending that I'd do it unless you're very sure it's safe!
Do you have Cpanel ? If yes, then try adding your host in remote MySQL.
Here the link http://www.liquidweb.com/kb/enable-remote-mysql-connections-in-cpanel/ if you are unsure on how to do that.
I'd advise that you do not create a wildcard user that can connect to the database from anywhere using embedded MySQL credentials in your application. This is a bad idea.
It would be extremely easy to determine the credentials used by your application and then a malicious user could directly connect to your DB server and begin issuing queries to your database.
They will be able to issue SELECT statements for any information in your tables, even info they shouldn't see. It then becomes much easier to exploit any known or unknown vulnerabilities in MySQL much easier since now they have console access and can send data directly to the server. If the account has the DELETE privilege, they can erase all the data in your table(s).
Also, having a PHP script that issues queries provided by the application/end-user is not ideal because one can still freely issue queries. While that option is better than giving blanket access to a remote user, it is still a bad idea.
The way to go would be to identify all of the information that the C# application needs to access, and how, and write a simple web service/API that will receive parameters and issue its own queries and return the results using XML, JSON, or even SOAP. Try to abstract the database access as much as possible from the outside world for the best security.
Hope that helps.
I would do the following:
Create a user with the host of your public ip (www.whatismyip.com).
If that doesn't work, create a user with your host as your public ARPA/PTR record:
>nslookup
> set q=ptr
> 8.8.8.8
Non-authoritative answer:
8.8.8.8.in-addr.arpa name = google-public-dns-a.google.com
8.in-addr.arpa nameserver = ns1.Level3.net
8.in-addr.arpa nameserver = ns2.Level3.net
The host would then be set to google-public-dns-a.google.com.
The second worked, and I am not sure why for me on a project I worked on in the past, where you would have thought the IP address to be sufficient.
I am not sure if you have root access or access to my.cfg. If you can edit it, make sure the line "skip-networking" is commented or removed and it contains line "bind-address = *". Restart mysql after editing config.
For security reasons you shouldn't access the database directly over the (public) network.
One way is to write a php script on the database server and access it via HTTP/POST.
You should authenticate the client via username and a hashed password. The data you are sending should be encrypted (eg with the users clear text password). Don't send complete queries, only what you want to do and the parameters. As example, you want the orders for the customer, you can send a post request with the following parameters
user=abc,password=9151440965cf9c5e07f81eee6241c042a7b78e9bb2dd4f928a8f6da5e369cdffdd2b70c70663ee30d02115731d35f1ece5aad9b362aaa9850efa99e3d197212a,data=EncryptedData
You can notice, that the password is an SHA512 Hash.
The data can be json or anything else:
{
"Command": "GetOrder",
"Limit": "10"
}
In your php code you do the following steps:
1. Authenticate the user, if the password is not correct, respond with error code etc
2. Decrypt the data
3. Execute a query
4. Return the result as encrypted data
If you don't want to store the clear text password in your database, you could store in your database the hashed value and use a double hashed value for authentication and single hashed value for encryption.
If you wan't to execute the queries with parameters from the request you should use prepared statements to prevent sql injection.
More information about en/decrypting in php see: http://php.net/manual/de/ref.mcrypt.php
Like some answers suggested, I think you are firewalled by bigrock.
Now if you want to use AJAX/PHP, you need three things:
- your C# class to send requests and receive the result
- your HTML/JS (or jQuery) file to receive the request and hand it over to your PHP. Then send you the result.
- your PHP file to query your DB.
The AJAX seems superfluous to me, you could just send your query passing it through POST or a GET parameter (i.e. example.com/query.php?req='SELECT * FROM clients')
The code would be as follow:
C# using this class made by Ali Ahsan Rana:
//create the constructor with post type and few data
MyWebRequest myRequest = new MyWebRequest("http://www.example.com/query.php","POST","req=");
//use System.Web.Script.Serialization and myRequest.GetResponse();
Some tutorial on System.Web.Script.Serialization.
On the PHP side:
<?php
$request=$_POST['req'];
$dsn = 'mysql:dbname=mydb;host=example.com';
$user = 'ajay';
$password = '0000';
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
$response = $dbh->query($request);
while ($rep = $response->fetch())
{
$response_array[] = $rep;
}
$response->closeCursor();
$return = json_encode($rep);
return($return);
?>
That's a quick draft but should work AFAIK.

Authenticating local users off the network

I am trying to authenticate a local user based on the username and password provided. I came across this thread: Validate a username and password against Active Directory?
Here is how I validate the user:
PrincipalContext pc = new PrincipalContext(ContextType.Machine);
bool isValid = pc.ValidateCredentials(user, pass);
It works as long as I am on a network, but if I disconnect my computer it gives me:
The network path was not found.
All I am trying to do is validate on the local machine which may or may not be a part of a network.
EDIT: UserPrincipal.FindByIdentity seems to still work with no AD, it's the pc.ValidateCredentials that is giving me trouble.
You should probably look into this link: How to validate domain credentials?
It seems that using the LogonUser Win32 API function is the only option if you have to be able to accomplish your validation even when AD is not online. However, not without serious drawbacks (as indicated in the thread). You need to pimp the account executing your app with a lot of privileges.
As you've noted, the System.DirectoryServices namespace is not very useful in a disconnected context -- you need to talk to the LSA, not its Active Directory parent.
I don't know of an official .Net API that corresponds to advapi32.LogonUser, but you can call it to validate against a locally cached logon. If the machine has network access but can't see a domain controller, though, it may take a while to return.
The function has a declaration on pinvoke.net if you want to call it via P/Invoke. (I haven't reviewed it, though; I've found that the quality of signatures on pinvoke.net varies wildly.)
A possible ugly workaround -
Using ValidateCredentials() with ContextType.Machine will always check the credentials against the local system first. It only performs network activity if the credentials are NOT found locally. You could catch the PrincipalOperationException if thrown and safely ignore it, knowing that if the method got this far the credentials are not valid.
bool valid = false;
using (PrincipalContext checkpass = new PrincipalContext(ContextType.Machine)) //checks local machine first
{
try // you need to use try catch when you only have local user
{
valid = checkpass.ValidateCredentials(user, password);
}
catch (Exception ex) { valid = true; }
if (valid)
{
// returns ok
}
else
{
// returns false
}

Categories

Resources