Is an SPN required when using Kerberos with DCOM? - windows

I'm using DCOM to provide various application services on a Windows network, using Kerberos to handle authentication. The system normally works fine, but I'm running into issues accessing the service from a separate (trusted) domain. Particularly, the service is unable to make callbacks to the client application, receiving the error "A security package specific error occurred". Also, if I tweak the service to specifically require Kerberos authentication (rather than using SNEGO/negotiate), the client can't even call into the server (again receiving "A security package specific error occurred").
The confusing thing is that things have been working for years without issue. However, a few things are different here, as compared to what we've done before. For one, the servers involved are running Windows 2008, which I have not previously used. Also, as noted above, the errors are only occurring when the service is accessed from an account from a separate domain, and previous usage has never attempted this.
Now to the question: I'm not using an SPN (service principal name) for this DCOM service, but some of the errors and event logs makes me think that might be the problem. However, all the docs I've found are unclear on whether this is correct, or how I would set up the SPN if I do need it. Does anybody know for sure whether an SPN is what I'm missing here? If so, can you point me to how this should be done?
Additional details:
For the scenario where the server is set to force Kerberos authentication, turning on Extended RPC Debugging gives some additional clues. The client can successfully connect using CoCreateInstanceEx, but calls on the service interface fail as noted above. The RPC error records show an error at location 140, and the error code is 0x80090303 ("The specified target is unknown or unreachable"), and the third parameter for that record is an empty string. This points to a missing SPN as the culprit.

For what its worth, Kerberos by definition requires SPNs. You might be able to utilize the built-in SPNS (host/) and the various flavors that host implies (This alias translation is stored in the AD, but for the life of me, I can't seem to find the article listing where this is found).
I'd start by looking at the cross-domain authentication - It can be tricky with kerberos. I'd first turn on full kerberos logging on both the client and server and see if that turns up anything.

Edit: It looks like I may be somewhat mistaken about this. At least one website I found states that DCOM handles SPNs automatically for you (see the bottom of the page), and I confirmed that clients can successfully connect if they demand Kerberos authentication and use "host/[computername]" as the SPN.
It does look like an SPN is required for the service, if you explicitly require Kerberos authentication when calling CoInitializeSecurity in the DCOM server process. For me, the call looked like this:
Warning: Please do not copy this code directly without ensuring that the values are proper for your security needs.
SOLE_AUTHENTICATION_SERVICE sas;
sas.dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
sas.dwAuthzSvc = RPC_C_AUTHZ_NONE;
sas.pPrincipalName = L"myservice/mymachine";
sas.hr = S_OK;
CoInitializeSecurity( 0, 1, &sas, 0, RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_DEFAULT, 0, EOAC_NONE, 0 );
The SPN can be configured using setspn, as demonstrated below:
setspn -A myservice/mymachine serviceusername
(see the setspn docs for details).
Unfortunately this still didn't solve my problem, but I think the remaining issue is related to some specific problem with the test machines.

I have come across this error while trying to create an instance of the remote COM object. We may face this error If "Delegate" impersonation level is used by the client during the call to CoInitializeSecurity(), and the COM+ service is running under a user account which doesn't have "delegation" permission at the domain level.

Related

Can a java TestContainer be started without attempting to call the default registry?

At work, we have decided we would like to use the java TestContainers package, and it has fallen to me to learn and implement this package. It is important to note that security is a top priority at work, so we are behind a proxy and run our own registry to contain our docker images.
This is what I've got so far.
var dockerImage = DockerImageName.parse("<secure-registry>/mongo:latest")
.asCompatibleSubstituteFor("mongo");
MongoDBContainer mongoDBContainer = new MongoDBContainer(dockerImage)
.withImagePullPolicy(PullPolicy.defaultPolicy())
.withExposedPorts(27019);
mongoDBContainer.start();
Not alot, but that's because I can't progress any further. Any time I attempt to run this code, it gets as far as .start() before throwing the following error
com.github.dockerjava.api.exception.InternalServerErrorException: Status 500: {"message":"Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io on 192.168.65.1:53: no such host"}
The issue is obviously that our proxy is blocking the default registry. I could probably fiddle with proxy settings on my machine so the registry can be resolved, but that is not a company wide solution. This app will be developed and run on many different machines and environments, and reconfiguring all of them would be more effort than it's worth. Furthermore, it shouldn't be communicating with the default registry at all. We have our own registry for a reason. The only real solution I see here is to remove this call entirely but so far, the documentation for both DockerImageName and the containers have been of no help.
If anyone has attempted this, or has another solution, it would be very helpful.
I have since realised my mistake. This page in the documentation reveals the problem. When running, the TestContainers library creates additional containers mainly for management of said containers. Unless a location is specified, it will attempt to pull these from the default registry. The preferred registry can be specified using the instructions in the link above.
As yuppie-flu also mentioned in their comment, this link may provide a nice, global way to set registries.

Is a serviced component shared between user sessions on a terminal server, or is one process started for each user session?

I have some .NET code in a COM+/Enterprise Services serviced component. I communicate with this component from a WPF application and also from a legacy VBA application.
This arrangement works well when only one user is logged on to a machine. The component starts in its own process when either the .NET or the legacy application instantiates one of its COM objects.
The system also works for the first user to try to run it on a terminal server installation. However, when another user logs on, he/she is unable to use the application. I had hoped that each session would run in isolation, and that one host process would run per session. Am I wrong in this expectation?
In Component Services on the Activation tab my application is configured to run as a "Server application". On the Identity tab, "Interactive user" is selected. On the Security tab, "Enforce access checks for this application" is unchecked.
There isn't session isolation as you describe, instead process ownership limits what you have access to.
Your conclusion seems correct & you will need to determine a suitable mechanism to exchange data with the service.
I used WCF to create a service with a net named pipe listener https://learn.microsoft.com/en-us/dotnet/framework/wcf/index
The idea of using proxies to make rpc calls is attractive, but I found the proxy definitions and stubs to link it all together quite clumsy to use.
If you have events that may be triggered at either end then keeping client/service in sync becomes problematic.
AIUI you cannot invoke a rpc method that ends up invoking an rpc back at the originating end, although that could be a named pipe limitation.
If I was doing this again I would use a socket server in the service & the websocket protocol for biderectional data transfer, even though you might need to implement some thread handling to avoid the listener thread blocking whilst servicing requests.
Hard to find anything authoritative on this. For standard COM you can set the identity to 'Launching user'. The same is not available for COM+.
According to this archived post,
A COM+ application can be configured to run under the logged in account, or
a specified account. Under the application properties, see the Identity tab.
...
Once set however, it remains under that account until the application shuts
down, so you can't have multiple users using the same COM+ application under
different IDs.
That seems to match what is said in this knowledge base article too.
My conclusion is, I should probably accept that my component must run once per machine rather than once per session. It will need to be modified to accommodate this. Since it needs to start new processes in individual sessions, it will have to run as a Windows service under the Local System account (giving due attention to the security implications).

Starting an Application from Windows Service

I am building a Windows service that will watch for specific occurrences of events and disk activity. When such an event occurs my plan is to alert the user to the event via a client app, and provide remediation if necessary. I have (mostly) completed both the client and service components, which work great... unless the client app isn't running.
In short, I am looking for a way to start up the client app from the Windows service via CreateProcess to provide information to the user. However, it appears the service can't even see the file/folder of the client app to execute it. I suspect this is due to the credentials under which the service is running, or maybe due to service level restrictions, but wanted to reach out for some advise before I get into this any deeper.
So, the obvious question first... am I thinking about this clearly? Is the architecture plan sound, or should I look at another method? I would prefer not to re-do any of the work I have already completed, but obviously want to make sure the plan and process is solid.
Question #2, what are the limitations I face with this model? Is there a service account that will allow this level of access?
I am obviously struggling with this right now, so any thoughts or assistance will be greatly appreciated!
Thanks,
Kris
As others have mentioned already, you can't (easily) launch an application directly from the service, so I think the easiest way around the problem is to create a process that starts on login and runs with the credentials of the logged in user, eg an app that sits in the system tray, and it opens up a named pipe or a network port to the service. If the service needs to alert the user, it sends a message down that channel and then the client process can either show its own UI or launch an application. Interprocess communication using pipes or ports are the simplest way to deal with the restrictions on session 0 processes.
A Windows service does not have access to the user session in Vista and above, so it is blocked from starting an executable on that session. You can download a white paper from Microsoft that goes into detail: Impact of Session 0 Isolation on Services and Drivers in Windows.
Since Vista, services run in session 0 and the user's desktop is always in a different session. Thus you need to work hard to start a service on the user's desktop.
It can be done but it is pretty tricky. Details can be found here: http://blogs.msdn.com/b/winsdk/archive/2009/07/14/launching-an-interactive-process-from-windows-service-in-windows-vista-and-later.aspx?wa=wsignin1.0

Windows API Clear Authentication Tokens

I'm using the WNetEnumResource to enumerate all network share connections and WNetCancelConnection2 to close them. Then I am using WNetUseConnection to connect to a share using discrete credentials. This process happens multiple times throughout the day.
The problem that I'm running into is that after the first flow through the process I'm getting:
System Error 1219 has occurred.
Multiple connections to a server or shared resource by the same user,
using more than one user name, are not allowed. Disconnect all
previous connections to the server or shared resource and try again.
This happens even when the enumeration says there are no current connections.
My question is: why? Why am I getting this error? Is the authenticated connection to the server still cached? Can I enumerate these authentication tokens? Kerberos? LSA?
I haven't been able to find the smallest foothold of information to progress forward on this project. Any help is appreciated!
I'm trying to remember the solution we used when we came across this problem for a network backup program a few years ago.
I'm certain the solution involves using either WNetAddConnection2 or WNetAddConnection3 instead of WNetUseConnection. I think that passing the flag CONNECT_CRED_RESET should take care of this, but I'm not absolutely certain.
Note that CONNECT_CRED_RESET is only documented for WNetAddConnection2 and not WNetAddConnection3, though MSDN says the only difference between the two is the hWnd parameter for owner of dialog windows - I'd try with WNetAddConnection2 and only if it works, experiment with WNetAddConnection3. You may even get it to work with WNetUseConnection!
Make sure to note the dependencies CONNECT_CRED_RESET has on other flags.

Is passing a windows security token between processes permitted

Imagine I have an existing process running under windows as a particular user. Would it be permitted for that process to take its current token (with something like OpenThreadToken and DuplicateTokenEx), pass it to another process on the same machine (perhaps through a network socket or some other IPC), and then expect that process to be able to use it to call CreateProcessAsUser?
From the documentation I have read (http://msdn.microsoft.com/en-us/library/ms682429%28VS.85%29.aspx), I've seen nothing which prohibits this but perhaps the token can only be used by the thread or process which created it.
(Why would you? I want to has a web request come to IIS, be authenticated, have IIS arrange the impersonation of the remote user and then pass the impersonation token to another server process (on the same machine) so that the server process can perform some security checks in the context of the remote user)
Yes, that is possible. You can use DuplicateHandle to get a handle that is valid for the target process (send the new handle value to the target process, so it knows it.).
However, the target process must still have the privileges to use the token accordingly. E.g. SE_IMPERSONATE to impersonate the user and SE_ASSIGN_PRIMARY to be used by CPAU. Of course there are some exceptions that you can read in MSDN for ImpersonateLoggedOnUser and CPAU.
I haven't tried it, but it seems that this is the same question asked here. The description seems to make sense. Pass the process ID via whatever mechanism you choose (e.g., IPC), then call OpenProcess, OpenProcessToken, and finally ImpersonateLoggedOnUser. The resulting handle could be passed to CreateProcessAsUser. Well ... I know it could be passed to that function but whether it would have the desired result I do not know. Interesting question, though.
Why not just use named pipes, and then call ImpersonateNamedPipeUser() - it's safe and secure and easy! Note that the process doing the impersonation MUST have the Impersonation privilege.

Resources