Simple bind to AD-LDS fails from remote computer - c#

I am using the API System.DirectoryServices.AccountManagement to bind to an AD-LDS instance. I am using simple bind with a user that exists locally in the AD-LDS instance. It works when I run the client on the server that hosts AD-LDS but it doesn't work when I run the client on a remote computer.
This is the code I use to bind and search for a user:
var c = new PrincipalContext(ContextType.ApplicationDirectory, "fullhostname:50001", "CN=Users,DC=app,DC=local", ContextOptions.SimpleBind, "CN=joe,CN=Users,DC=app,DC=local", "abc");
var u = UserPrincipal.FindByIdentity(c, IdentityType.Name, "john");
This is the exception that is thrown when I run it on a remote computer:
System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server is not operational.
---> System.Runtime.InteropServices.COMException: The server is not operational.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectoryEntry.get_Options()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
--- End of inner exception stack trace ---
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoApplicationDirectoryInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
at System.DirectoryServices.AccountManagement.PrincipalContext.get_ConnectedServer()
at MyApplication.DiagnosticsController.TryAdLdsSettings(AdLdsData data) in C:\code\MyApplication\DiagnosticsController.cs:line 166
If I instead use the System.DirectoryServices API it works also from remote computer:
var obj = new DirectoryEntry("LDAP://fullhostname:50001/CN=Users,DC=app,DC=local", "CN=joe,CN=Users,DC=app,DC=local",
"abc", AuthenticationTypes.None);
obj.RefreshCache();
This works, but I need to use System.DirectoryServices.AccountManagement API instead.
Anyone knows what is wrong?

I was able to get this to work on a domain, with a few minor changes, I hope these tips help.
Your 2nd-to-last parameter when creating PrincipalContext, "CN=joe,CN=Users,DC=app,DC=local", should be the fully qualified username, not the LDAP path; this will normally look like COMPUTER-NAME\\joe (whatever your computer is named) or if you are on a domain as I am, DOMAIN-NAME\\joe. (If fullhostname is not your local workstation, then you may be on a domain, or you may need to specify fullhostname\joe to request authentication against the host server rather than your local, since your local's credentials probably won't work on the host server).
For testing this on a Domain, I had to change the first parameter from ContextType.ApplicationDirectory to ContextType.Domain; it sounds like you are not on a domain, so you will probably need ContextType.ApplicationDirectory, but the error message makes me think that Active Directory Services aren't running.
Since :50001 is high enough to be blocked, make sure you don't have firewall software that is blocking the request, either outgoing from your machine, or incoming to the "fullhostname" machine; and, of course, make sure your active directory services are actually available on 50001, and not some other authentication protocol.

I ended up rewriting my usages of PrincipalContext and UserIdentity to use DirectoryEntry directly instead. It took me a few hours to find appropriate reimplementations for the convenient UserIdentity functions I needed, but after doing so everything worked fine.
It's quite a mystery to me why the problem occurred in the first place. My only guess is that with my particular version of AD LDS in my particular configuration, there's a bug somewhere in the underlying libraries. Rewriting everything directly in DirectoryEntry, getting everything as exactly similar as I know how to do, fixed the problem.

Related

OData, DataServiceClientException: Unauthorized

I'm developing (as a totally no-C#-guy) a web app which communicates with an external data source over OData (server B, some windows 2k12 machine).
The web app runs (is about to run) on an IIS (server A, another windows 2k12 machine), the OData source is a Dynamics NAV 2015 service (the first mentioned windows 2k12 machine, server B).
I'm developing it in VS2013 and if I'm running this locally (meaning: without publishing it, only running it within the local express IIS) it works without any problems at all.
But as soon as I publish it to the target IIS (server A) I'm getting:
An error occurred while processing this request. ---> >System.Data.Services.Client.DataServiceClientException: Unauthorized
at System.Data.Services.Client.QueryResult.ExecuteQuery()
at System.Data.Services.Client.DataServiceRequest.Execute[TElement]>(DataServiceContext context, QueryComponents queryComponents)
--- End of inner exception stack trace ---
This is esentially the piece of code which deals with the OData call:
ODataOrders.NAV odata = new ODataOrders.NAV(new Uri(serviceUri));
System.Net.NetworkCredential nc = new
System.Net.NetworkCredential(_oDataUsername, _oDataUserPassword, _oDataDomain);
odata.Credentials = nc;
DataServiceQuery<ODataOrders.Orders> query =
odata.CreateQuery<ODataOrders.Orders>("Orders");
orderList = query.Execute().ToList(); // "Unauthorized" is being thrown here
It looks like the credentials are being sent/accepted if running from local IIS. And if running from the target (production) server A, the credentials are being somehow lost/overwritten? I really don't know now...
Server A and Server B are in the same domain. My development environment isn't - I can even connect from home through VPN to my work domain and launch my local IIS and still be able to get that request done (the request goes through my local IIS and reaches the Dynamics NAV service so the data is being actually fetched).
Any help would be appreciated...
EDIT
It's Dynamics NAV 2015 CU11.
After some serious hours of reading, programming and trying I've stumbled upon a post here which gave me an idea.
And guess what? It worked - somehow...
Instead of:
System.Net.NetworkCredential(_oDataUsername, _oDataUserPassword, _oDataDomain);
I submitted only:
System.Net.NetworkCredential(_oDataUsername, _oDataUserPassword);
I turns out somehow the domain caused the call not to be authorized (401 error).

TIBCO.EMS.IllegalStateException: connect failed: server in standby mode

We have a big system with bunch of services communicating with each other via TIBCO EMS Messaging.
Now, one of the services keeps throwing this exception when it tries to connect to EMS server:
TIBCO.EMS.IllegalStateException: connect failed: server in standby mode
However, other services on the same EMS server are working just fine without any exception.
I tried to reproduce this by creating a console application which would use same credentials to connect to EMS server on the same destination (Queue) but couldn't reproduce this error.
EMS connection is fault-tolerant and it might have been failed over to secondary server, however, now I see primary server is back up.
I also tried to connect to primary server only (which I can see is up & running) but it fails with the same exception.
Below is the stack trace for reference:
TIBCO.EMS.IllegalStateException: connect failed: server in standby mode
at TIBCO.EMS.CFImpl._CreateConnection(String userName, String password, Boolean xa)
at TIBCO.EMS.ConnectionFactory.CreateConnection(String userName, String password)
at Ems.makeConn()
We're using TIBCO.EMS.dll v. 8.1.0.10 on .NET 4.0.
Any idea what can cause this exception ?
Could your connection string only mention one of the hosts inside an FT/HA setup ? This looks like the error message returned when you are trying to connect to only one of the HA/FT host, but not the one active at the moment.
If it is the case, the connection string will work most of the time, but a proper EMS HA connection string include two (or more!) EMS host and port. Only one is active at the same time.
It typically looks like this:
serverUrl=tcp://server0:7222, tcp://server1:7344
See source doc here in TIBCO docs.
It turned out tools we were using to check if server is active (we don't have admin rights on the servers) was misbehaving (showing incorrect status), so none of those servers were really active (not primary nor secondary).
As soon as server was brought up this error message went away.

WCF Named Pipe Server Fails With AddressAccessDeniedException

I have a process which is hosting a WCF Named Pipe server.
The process runs under a user account with no admin privileges.
When a client tries to connect to the pipe it receives a timeout exception and the server fails with the following exception:
Throwing an exception. Source: System.ServiceModel 4.0.0.0. Exception details: System.ServiceModel.AddressAccessDeniedException: Cannot listen on pipe 'net.pipe://localhost/path/to/endpoint': Access is denied. (5, 0x5) ---> System.IO.PipeException: Cannot listen on pipe 'net.pipe://localhost/path/to/endpoint': Access is denied. (5, 0x5)
--- End of inner exception stack trace ---
at System.ServiceModel.Channels.PipeConnectionListener.CreatePipe()
at System.ServiceModel.Channels.PipeConnectionListener.BeginAccept(AsyncCallback callback, Object state)
at System.ServiceModel.Channels.ConnectionAcceptor.AcceptIfNecessary(Boolean startAccepting)
After reading Chris Dickson's blog, I can think of three possible things that cause this:
Somehow, the user in not being added to the ACL
The user is not given the FILE_CREATE_PIPE_INSTANCE permission
The deny ACE for the Network Users group is denying permission
Notes:
Using a non-WCF named pipe, adding current user and the built-in administrator to the ACL works just fine.
A similar endpoint in a process running under a SYSTEM account works just fine.
When testing the code under my own user account everything works fine.
The host must remain a process and must have non-admin privileges.
I tried adding the current user and the built-in administrator to the ACL as suggested in Chris Dickson's blog but it did not help.
I tried setting NetNamedPipeSecurityMode to None but that didn't help either.

Azure service bus relay connecting to unknown ip address: 40.112.124.x:9352

We deliver on-premise software that is exposed to the cloud using Azure Service bus relay, the basic code we use to expose is as follows (I have removed everything identifiable):
ServiceHost sh = new ServiceHost(typeof(BasicHttpEntityService));
BasicHttpRelayBinding basicHttpRelayBinding = new BasicHttpRelayBinding();
Uri uriEndPointAddress = ServiceBusEnvironment.CreateServiceUri("https", "ourdomain", "test-url-appendage");
m_shRelayServiceHost.AddServiceEndpoint(
typeof(IMyService),
basicHttpRelayBinding,
uriEndPointAddress
).Behaviors.Add(
new TransportClientEndpointBehavior
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(
"MyUser",
"MyPassword")
});
sh.Open();
This works fine at most of our customers, however, one of our customers has a strict firewall policy.
According to the SB guidelines we have found, we asked them to open ports 9351-9354 to ourdomain.servicebus.windows.net. Now we find out that when there is an incoming request, the service connects to both 'ourdomain' (we see this succeeds in Wireshark, and also in the WCF log) AND an unknown (to us) service on 40.112.124.x:9352 (the last octet changes with every request).
I have been able to reproduce the problem in my development environment by disallowing connections to any 40.x.x.x address on any port. This is what happens in the WCF log:
System.Net.Sockets.SocketException (0x80004005): An attempt was made to access a socket in a way forbidden by its access permissions 40.112.124.25:9352
Server stack trace:
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at Microsoft.ServiceBus.RelayedConnectionSession.ConnectAsyncResult.<GetAsyncSteps>b__4(ConnectAsyncResult thisRef, IAsyncResult r)
at Microsoft.ServiceBus.Messaging.IteratorAsyncResult`1.StepCallback(IAsyncResult result)
Exception rethrown at [0]:
at Microsoft.ServiceBus.Common.AsyncResult.End[TAsyncResult](IAsyncResult result)
at Microsoft.ServiceBus.RelayedConnectionSession.EndConnect(IAsyncResult result)
There is no DNS-request going out during this time, so there is no host name that provides any clues to the function of this outgoing connection.
From my investigation, this appears to be a Microsoft controlled subnet, so I'm fine with the relay service connecting to it, but I would like to know:
Is this additional connection optional?
If not, should we allow the entire subnet?
Could this IP-range change in the future? Is it hardcoded somewhere?
In the end, we requested support from Microsoft.
In short their answers were as follows:
Is this additional connection optional?
No it is not optional. For the relay listener, there is a control channel on port 5671, this connection is always there. Then there is a data channel on portal 9352, this connection established when there is a relay client tries to communicate with the listener.
Could this IP-range change in the future?
Currently, for relay this IP can change, so you need to allow the IP range for the entire datacenter in your region (https://www.microsoft.com/en-us/download/confirmation.aspx?id=41653). The SB product team will be working on to significantly reduce this IP range in the future, to make it much more predictable. There is no exact ETA on this future.
So the good news is they are working on it. The bad news is, that right now, we will need to add a LOT of IP addresses to the white-list to ensure smooth operation.

Configuring mq websphere 7 with .net

I am trying to connect to a remote queue using c#.
I tried many ways to connect to the remote queue but it always fails with common errors like: MQRC_CHANNEL_CONFIG_ERROR or MQRC_HOST_NOT_AVAILABLE.
What I am doing is this:
string channel = "QM_TEST.SVRCONN";
string hostname = "<serverIp>";
string queueName = "QM_TEST";
string port = 1414;
props.Add(MQC.HOST_NAME_PROPERTY, hostname);
props.Add(MQC.CHANNEL_PROPERTY, channel);
props.Add(MQC.PORT_PROPERTY, port );
props.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
MQQueueManager mqQueue = new MQQueueManager(queueName, props);
I have tried changing this but all failed.
I think that my problem is the server configurations..
can you point me to a full guide to how to configure a server and connect to it with .net?
My problem is connecting to a REMOTE server using .net and not to a local server.
Thank you!
The problem was that the CCSID between the client and the server were different.
http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/index.jsp?topic=%2Fcom.ibm.mq.csqzaf.doc%2Fcs12480_.htm
On the client side I had to put
Environment.SetEnvironmentVariable("MQCCSID", "437");
Thats why I got:
MQRC_CHANNEL_CONFIG_ERROR
I'm guessing the problem (or at least a problem) is here:
MQQueue mqQueue = new MQQueueManager(queueName, props);
This should be
queueManager = new MQQueueManager(queueManagerName, properties);
If you have installed the WebSphere MQ client to the default location, there are many sample programs under the following directory:
C:\Program Files (x86)\IBM\WebSphere MQ\tools\dotnet\samples\cs\base\
There are a number of sample programs there for various tasks. If you have the latest V7.1 client installed then you will see the following programs:
SimpleAsyncPut
SimpleClientAutoReconnectGet
SimpleClientAutoReconnectPut
SimpleGet
SimpleMessageProperties
SimplePublish
SimplePut
SimpleReadAhead
SimpleSharingConversation
SimpleSubscribe
SimpleXAGet
SimpleXAPut
There are also WCF and XMS samples.
If you need the client code, please see my response to another SO question here for links.
Update:
Here's the normal diagnostic process.
If the WMQ components were installed by relocating libraries or classes from somewhere else, perform an install using the full vendor-supplied client media. This includes troubleshooting utilities such as trace, dspmqver, etc. It also resolves any library or class mismatch issues.
Use the pre-compiled client programs to test the connection. The amqsputc, amqsgetc and amqsbcgc programs require the MQSERVER environment variable as described here. The Q program from SupportPac MA01 is a separate download but has the advantage of NOT requiring any environment variables, CCDT files or other dependencies.
If the sample programs fail, check the QMgr's error logs at [WMQ install]/qmgrs/[QMgr name]/errors/AMQERR01.LOG for messages. Also check for FDC files and errors in [WMQ install]/errors.
If no errors on the QMgr side, attempt the connection again while using a client-side trace as described here and here.
Most client problems are resolved through installation of the full WMQ client as supplied by IBM. (Conversely that implies most people are installing by grabbing DLL or JAR files.) If the problem persists, error log inspection on the QMgr and client side usually reveals the underlying cause. If these do not work then tracing usually diagnoses the remaining issues.
UPDATE 2:
Per the error messages posted at MQSeries.net, the channel has a security exit set. A security exit is external code that the channel calls out to when starting a channel. There is no way to know what the exit expects or does without having access to the code or docs of the exit. If the exit is written in-house, you'll need to talk to the programmer to figure out what it requires. If the exit is a commercial product then you will need to get the documentation for it.
Alternatively, alter the channel so that SCYEXIT is blank to disable the exit.
The data posted at MQSeries.net was as follows:
MQ9575: DCE Security: failed to get the user's login name.
EXPLANATION:
System call 192.168.50.55 to get the login name of the user running WebSphere
MQ client application process 5 failed with error value -1. This occurred in
security exit function create_cred. The exit will now attempt to open channel
using the DCE default login context.
ACTION:
If you wish to run using the DCE default login context take no action. If you
wish to run using the user's login name as the DCE security exit principal
examine the documentation for the operating system on which you are running MQ
clients and reconfigure the operating system as necessary to allow the
192.168.50.55 call to succeed.
Note that it states the call is failing in the security exit.

Categories

Resources