Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impersonation without password in .NET Core #5021

Closed
wstaelens opened this issue Aug 5, 2020 · 12 comments
Closed

Impersonation without password in .NET Core #5021

wstaelens opened this issue Aug 5, 2020 · 12 comments

Comments

@wstaelens
Copy link

We are currently moving a project that was written in .NET Full Framework to .NET Core 3.1. Our project has Windows services, signalr, a web part etc... Choosing for .NET Core feels to be the right thing to do and will hopefully make it future proof (cf. .NET 5)

We intercept print jobs and in the Full Framework project we used impersonation without having to know the users password (policy: "act as part of the operating system").
However we are currently stuck in .NET Core 3.1 as we can't find a way to make the impersonation code working without having to provide a user password. (print jobs need to be processed regarding specific users, not e.g. system).

Impersonation without password in .NET Full Framework:

        if (string.IsNullOrEmpty(sPassword)) {         
          string upn = string.Format("{0}@{1}", sUsername, sDomain);
          var id = return new WindowsIdentity(upn, null)
          id.Impersonate();
          ...
        }

How can this be done using .NET Core?

@mairaw
Copy link
Contributor

mairaw commented Sep 7, 2020

@blowdart is this something you can help with?

@blowdart
Copy link
Contributor

blowdart commented Sep 7, 2020

No.

From the documentation it looks like there is a constructor for WindowsIdentity which doesn't need a password and examples of impersonation.

If those are incorrect then a bug should be logged.

@GrabYourPitchforks
Copy link
Member

@wstaelens Please clarify the problem you are encountering. Are you receiving a compiler error, a runtime exception, or something else? Take note that the particular ctor overload you are calling doesn't exist in .NET Core 3.1. You can choose from one of the other available overloads instead.

If you're receiving a runtime exception, please provide the exception message and repro code.

@GrabYourPitchforks GrabYourPitchforks added the needs-more-info Not enough information has been provided. Please share more detail as requested. label Sep 10, 2020
@no-response
Copy link

no-response bot commented Sep 20, 2020

This issue has been automatically closed due to no response from the original author. Please feel free to reopen it if you have more information that can help us investigate the issue further.

@wstaelens
Copy link
Author

@GrabYourPitchforks yes that constructor doesn't work. It is code from Full .NET Framework.
We are looking on how you can impersonate WITHOUT a password in .NET Core 3.1, similar as we would do with the piece of code from the full .NET Framework.

From our understanding .NET Core 3.1 does NOT have a working solution to impersonate WITHOUT supplying a password.
(we are aware that this only works in combination with the security policy "act as part of the operating system". But in enterprise environments (e.g. print processing, where you only receive user names) this is really needed!)

The WindowsIdentity and other solutions we tried, just do not impersonate. It doesn't do a thing. The impersonation doesn't work, as a result the user is always incorrect.

The only way we have found something working is porting ±8000 lines of code from Full Framework to .NET Core and modifying it so that we could build and impersonate. Because the WindowsIdentity code doesn't impersonate.
One of the many many classes we needed to copy and modifying to get it working

System.Security.Principal.StackCrawlMark
System.Security.Principal.TokenInformationClass
System.Security.Principal.TokenType
System.Security.Principal.Win32
System.Security.Principal.WindowsImpersonationContext
System.Security.Principal.WinSecurityContext
System.Security.Principal.Claim
System.Security.Principal.IdentifierAuthority
System.Security.Principal.IdentityReference
System.Security.Principal.IdentityReferenceCollection
System.Security.Principal.IdentityReferenceEnumerator
System.Security.Principal.NTAccount
....

Hopefully it will work with the WindowsIdentity soon as currently the impersonation + act as part of the operating system doesn't use the correct user and we receive no errors, no exceptions,... except the message that we don't have permissions, because the code is not executed under the correct (impersonated) user (because the impersonation doesn't work).

@no-response no-response bot removed the needs-more-info Not enough information has been provided. Please share more detail as requested. label Sep 22, 2020
@no-response no-response bot reopened this Sep 22, 2020
@GrabYourPitchforks
Copy link
Member

The WindowsIdentity.Impersonate method does not exist in .NET Core. Use the WindowsIdentity.RunImpersonated method instead. This method invokes a provided callback under the impersonation context of the supplied access token. There are some code samples showing how to call the API.

If you need an access token, you can get one via the WindowsIdentity.AccessToken property. You can construct a WindowsIdentity instance by calling the constructor that takes only a UPN string.

Beyond this, I don't know what you mean by "that constructor doesn't work". If you're receiving a compiler error, a runtime error, or an exception, then please provide the details of the error. Without this information we can't provide much more than very high-level guidance.

@GrabYourPitchforks GrabYourPitchforks added the needs-more-info Not enough information has been provided. Please share more detail as requested. label Sep 22, 2020
@no-response
Copy link

no-response bot commented Oct 2, 2020

This issue has been automatically closed due to no response from the original author. Please feel free to reopen it if you have more information that can help us investigate the issue further.

@no-response no-response bot closed this as completed Oct 2, 2020
@wstaelens
Copy link
Author

maybe the issue is related: dotnet/runtime#29935 (comment)

@no-response no-response bot removed the needs-more-info Not enough information has been provided. Please share more detail as requested. label Oct 5, 2020
@no-response no-response bot reopened this Oct 5, 2020
@antonGritsenko
Copy link

It just doesn't work in the .net core 3.x. Super simple example:

static void Main(string[] args)
        {
            WindowsIdentity f = new WindowsIdentity("[email protected]");

            WindowsIdentity.RunImpersonated(
                f.AccessToken,
                () =>
                {
                    var userName = WindowsIdentity.GetCurrent().Name;
                    // Check the identity.  
                    Console.WriteLine("During impersonation: " + userName);
                }
            );

            // Check the identity again.  
            Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
        }

Reference: System.Security.Principal.Windows 4.7.0

This raise exception:

Unhandled exception. System.IO.FileLoadException:
File name: 'System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at System.Console.get_Out
   at System.Console.WriteLine(String value)
   at doetnetCoreImpersonation.Program.<>c.<Main>b__0_0()
   at System.Security.Principal.WindowsIdentity.<>c__DisplayClass67_0.<RunImpersonatedInternal>b__0(Object <p0>)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Security.Principal.WindowsIdentity.RunImpersonatedInternal(SafeAccessTokenHandle token, Action action)
   at System.Security.Principal.WindowsIdentity.RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action)
   at doetnetCoreImpersonation.Program.Main(String[] args)

Weird things: the userName variable is correct. If remove the Console.WriteLine then no exception.
Similar exception if replace Console to Debug:

Unhandled exception. System.IO.FileLoadException:
File name: 'System.Diagnostics.Debug, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at doetnetCoreImpersonation.Program.<>c.<Main>b__0_0()
   at System.Security.Principal.WindowsIdentity.<>c__DisplayClass67_0.<RunImpersonatedInternal>b__0(Object <p0>)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Security.Principal.WindowsIdentity.RunImpersonatedInternal(SafeAccessTokenHandle token, Action action)
   at System.Security.Principal.WindowsIdentity.RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action)
   at doetnetCoreImpersonation.Program.Main(String[] args) in F:\VisualStudio\Dev Playground\doetnetCoreImpersonation\doetnetCoreImpersonation\Program.cs:line 14

@GrabYourPitchforks
Copy link
Member

@antonGritsenko Please open a new issue for this if you're experiencing a problem here. Though I suspect in your case it has to do with that files like System.Runtime.Extensions.dll are sitting in a local folder and ACLed to your local user account, and [email protected] doesn't have read access to the folder containing these libraries.

@antonGritsenko
Copy link

@GrabYourPitchforks its definitely not the case: this test user can run this app from same location. I found workaround: you have to load assembly with calling method before the impersonation, so this will work:

static void Main(string[] args)
        {
            // this fix the error Unhandled exception. System.IO.FileLoadException
            Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);
            WindowsIdentity f = new WindowsIdentity("[email protected]");

            WindowsIdentity.RunImpersonated(
                f.AccessToken,
                () =>
                {
                    var userName = WindowsIdentity.GetCurrent().Name;
                    // Check the identity.  
                    Console.WriteLine("During impersonation: " + userName);
                }
            );

            // Check the identity again.  
            Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
            // but uncomment this line will fail entire block
           // Debug.WriteList("Test");
        }

May be author had the same issue. I will play around of this and if I will find more I will create a new issue

@wstaelens
Copy link
Author

we copied .net framework code and modified it for .net core as we had to move forward.
.net core 3.1 and .net 5 are still messy in many parts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants