WCF Service Impersonate One User But Still User Windows Authentication? - silverlight

I am using LinqToEntitiesDomainService to connect to a SQL Server Database. This requires Windows Authentication, which I have working.
I wrote a web service that uses Activator.CreateInstance(...) to run an executable on the server. I would like this to use Windows Authentication, as well. However, I need the service to have the proper permissions to run the executable.
When I run the service right now, it works fine. My account has the proper roles to authenticate. I also have god-like permissions on the server, which allows me to have the Activator.CreateInstance(...) command work.
While other users who have the proper roles can authenticate, their account doesn't have permissions on the server, nor should it.
Is there some (preferably, easy) way to run the service as one user, but have all of the authentication done with windows authentication? It would also be best if I could do it all in just one app pool...
Thank You!

Yes you can, take a look at this article. This shows some techniques for impersonating users.
using (WindowsImpersonationContext impersonationContext =
((WindowsIdentity)User.Identity).Impersonate())
{
// do something as current user
}
Or in WCF you can also define this declaritively.
public class HelloService : IHelloService
{
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string Hello(string message)
{
return "hello";
}
}
Note these two techniques impersonate the client (caller).
To impersonate another user explicitly you need some P/Invoke. There's a project here that wraps it all up for you quite neatly. You can then do this:
using (new Impersonator("myUsername", "myDomainname", "myPassword"))
{
// do something as myUsername
}

Related

SSPI: acquire credentials for another user from a process running with local admin privileges

I am running a process with loacl admin privilege in Windows and trying to obtain a credential handle for another user using AcquireCredentialsHandle .
It is possible to pass in SEC_WINNT_AUTH_IDENTITY structure with user info ( e.g. user, domain, password) and obtain the handle. I have verified it. Without the SEC_WINNT_AUTH_IDENTITY passing only the pszPrincipal does not work.
I wonder is there any other way one can do it without providing the user password?
I am running the following scenario:
Client obtains a kerberos token using UPN and sends it to server
Server tries to acquire the credential handle (AcquireCredentialsHandle) using UPN of the client.
Any suggestions please?
You normally don't get to request a ticket on behalf of other users. That would be a very dangerous security issue.
There are two ways around this.
Use S4U2Self which is where the application requests a ticket to themselves using the passed in username, which will get them a ticket on behalf of the user to themselves. This lets you see things like user group membership. You need to be running as SYSTEM or have SeImpersonatePrivilege to do this.
Use S4U2Proxy aka protocol transition which is where the application requests a ticket for another service using the passed in username. This lets you impersonate the user based only on the name, and must be explicitly granted to the server and target by AD. This is an incredibly dangerous privilege because you're allowing your application to have the equivalent rights as a KDC.
Unfortunately this is a fairly complicated bit of code so it's not shareable in this post as-is. You can find a sample application here: https://github.com/SteveSyfuhs/DelegatedAuthentication
The gist of the process is:
Client sends username to service.
Service is configured for SeImpersonatePrivilege or SeTcbPrivilege (meaning running as SYSTEM)
Service calls LsaLogonUser and passes just the username, returning an NT token handle.
Service calls SetThreadToken with the token from (3).
Service calls AcquireCredentialsHandle without any credentials (uses default SSO creds).
Service calls InitializeSecurityContext
Service sends token to target server

Accessing user details using Active Directory in an ASP.NET Core MVC app with Windows authentication

I was trying to access user information like first name, last name of the user in my ASP.NET Core MVC project with Windows authentication. I actually make it work after searching for a solution on the web but I am quite new to this stuff and beginner level programmer so not understanding what is happening in the part that I just copy paste in my project.
I couldn't find any explanation in that website as well. I would be really happy if someone can explain this to me. Many thanks in advance.
The website reference for this code: https://sensibledev.com/how-to-get-user-details-from-active-directory/
Home controller:
var username = User.Identity.Name;
using (var context = new PrincipalContext(ContextType.Domain, "yourdomain"))
{
var user = UserPrincipal.FindByIdentity(context, username);
if (user != null)
{
ViewData["UserName"] = user.Name;
ViewData["EmailAddress"] = user.EmailAddress;
ViewData["FullName"] = user.DisplayName;
ViewData["GivenName"] = user.GivenName;
}
}
That code takes the username of the user who logged into your website and looks it up on your domain to find more information about the person.
var username = User.Identity.Name;
The User property is ControllerBase.User, which refers to the user currently logged into your website. Since you're using Windows Authentication, this will refer to an Active Directory user. User.Identity.Name gets just the username.
The rest is for looking up the account in Active Directory.
new PrincipalContext(ContextType.Domain, "yourdomain")
This means "I want to talk to a domain called yourdomain".
UserPrincipal.FindByIdentity(context, username)
UserPrincipal.FindByIdentity finds an account on the domain. So this is saying "find this username on the domain".
Then the users details from the account are put into the ViewData collection so that the data is accessible in the view. More details on that here.
From your website's perspective, all Windows code runs under some Windows account.
If you use IIS and Forms authentication for example, then Windows knows nothing about you - you are likely to be running under an anonymous account name which all users will run under. If you drill down through your running code, it is possible to find different Windows accounts at different code levels, such as in your top level code, the underlying IIS thread, etc.
You are trying to use Windows accounts for your web site but you have to ensure that the web server it is running on is also using Windows Authentication - I know you checked this option when creating your site.
Your user identity can be cast to various types because it has to work seamlessly whichever authentication methodology is in use. You can also check your user to see if it is of a particular security regime.
Have a look at https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio
You get the security principle information using
var context = new PrincipalContext(ContextType.Domain, "yourdomain")
PrincipleContext is the class that has the information once you create a new instance of it, passing in parameters for the type of domain (an enumeration) and the name of your domain (a string).
The USING block ensures that the instance is disposed once the block completes - otherwise you have to call DISPOSE on that instance yourself (remember if there is an exception you might not have captured this so you will at least have to manage this scenario.
Once you have an instance of of your domain context you can use it to search (in the case of Windows, the LDAP database) for users, whether by SID or unique name, in your case (every name must be unique - two users in the domain cannot have the same name).
The website has the security ID of the user, the code you are following gets a Domain object for that user which has the properties you will display. You could call other objects that might tell you which Windows Security Groups the user is a member off. In that way you can have a web site where a users ability to view a web page or click a button is down to which Groups in the Domain the user is a member of.

MVC: how to print account trying to login to SQL database when using app pool identity specific account

I can print
System.Security.Principal.WindowsIdentity.GetCurrent().Name is #System.Security.Principal.WindowsIdentity.GetCurrent().Name
in a razor (.cshtml) file, however, I do not know how to print the app pool or verify that it is indeed accessing the database to login to it (as the login currently fails, that portion is an even tougher question).
This may require creating a string in the controller action trying to access the database, e.g. near something like:
db.myTable // etc
Thanks in advance.
The name you are returning in the code sample is the windows user id that the app pool is using (look in the app pool properties to see what windows username it is using).
This user name, complete with domain name, needs to have access to the db.
You may like to create your own windows user just for the app pool to use something other than local service as it may not be a good idea to give any local service access to your database.
As Will says in his comment, sql profiler should be able to help you find out what's happening if you are not sure.

User.IsInRole("fake group") results in "The trust relationship between the primary domain and the trusted domain failed"

I have an MVC 3 app, using Windows Authentication with Claims using WIF 4.5.
Access to the application is controlled (currently) via membership in an AD group:
<deny users="?" />
<allow roles="domain\somegroup" />
<deny users="*" />
In addition to the AD groups, we have custom roles that need to be added. (This app is being converted from Forms to Windows authentication)
To support these custom roles (until they are managed in AD), we are adding them as ClaimTypes.GroupSid claims to the user, so that existing code utilizing [Authorize("ADMIN")] and User.IsInRole("ADMIN") continues to function:
Application_PostAuthenticateRequest(object sender, EventArgs e)
{
var identity = ClaimsPrincipal.Current.Identity as WindowsIdentity;
var roles = userDAL.GetRoles(identity.Name);
foreach(var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.GroupSid, role));
}
}
And this is all working as expected.
Except when the current user is NOT a member of some custom role (like ADMIN) and that role also doesn't exist in AD
We use [Authorize("ADMIN")] on Controller Action Methods, as well as various instances of User.IsInRole("ADMIN") depending in the scenario. It's in those instances where the error occurs and the app blows up.
The AD infrastructure is in the midst of an upgrade/migration. I'm not privy to all the details there, but I do know there are a handful of domains, supposedly with trust between them, and it's been alluded to me by the infrastructure folks that these trust relationships are up and running.
So really I guess I'm wondering 2 things:
This really doesn't seem like something our code should have to handle. So what could really be wrong with the domain? Can I find out what 'trusted' domain the trust relationship is failing for?
What is the best way to work around this? I dislike the idea of writing helper methods & Authorize() subclasses just to trap this exception.
Please go to inetmgr, sites, default web site, site name, iis group, double-click authentication, disable anonymous authentication, then reset the app pool.
This appears to happen when windows cannot decipher the roles defined under the 'authorization, allow roles' tag in the web.config file. For testing comment out the custom roles tags from the web.config file. The issue appears to be caused when mixing up Forms authentication and Windows authentication. The magic happens in the Global.asax file Application_PostAuthenticateRequest method, when using Forms authentication you can Cast the User.Identity as FormsIdentity, then create the custom identity from the FormsIdentity Ticket, then create the custom principle from the custom identity, you will then be able to attach the CustomPrincipal to the Current User and Current Principal, ie.
Dim fIdent As FormsIdentity = CType(User.Identity, FormsIdentity)
Dim ci As New CustomIdentity(fIdent.Ticket)
Dim cp As New CustomPrincipal(ci)
HttpContext.Current.User = cp : Thread.CurrentPrincipal = cp
For IIS you want to enable Forms authentication and anonymous authentication, everything else should be disabled. When using Windows authentication the Global.asax file Application_PostAuthenticateRequest method can create the custom principle directly from the User.Identity ie.
Dim cp As New CustomPrincipal(User.Identity)
HttpContext.Current.User = cp : Thread.CurrentPrincipal = cp
In this case the IIS settings should be Windows authentication and ASP.Net Impersonation is enabled and everything else is disabled.
Getting these authentication methods mixed up results in the 'The trust relationship between the primary domain and the trusted domain failed' error because if your Application_PostAuthenticateRequest method is not implementing the CustomPrinciple for some reason then windows will try to use the built in IsInRole function that checks the role against the domain roles instead of using your custom IsInRole that is in your CustomPrinciple code behind file.
Here is a useful article and links:
http://www.codeproject.com/Articles/8819/Authorize-and-authenticate-users-with-AD
https://msdn.microsoft.com/en-us/library/ff647405.aspx
https://support.microsoft.com/en-us/kb/306359
This happens if you have a trusted domain configuration that is not available, IsInRole searches the group in the trusted doamins as well, and if the trusted domain is not available, throws the Trust exemption.

User member of group in a particular computer?

I'm writing a web application and I'm trying to authenticate admin users. I was hoping to do this by having a local group on the server that I add domain users into. I have a group called ProductionManagers which I add people with admin rights into. Other users have a view-only access.
What I want to do is to search query the AD (right?) on the server and find out if the currently logged in user is member of the ProductionManagers group (which is a group on the server, not a domain group).
What's the best way of doing this? Or maybe you have a suggestion on a better mechanic than having a local group where I add admins?
If using ASP.NET and form authentication,
WindowsPrincipal principal = new WindowsPrincipal(new WindowsIdentity("youruser#domain.com"));
if (principal.IsInRole("ProductionManagers"))
{
// Authenticated
}
If using ASP.NET and Windows authentication,
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
if (principal.IsInRole("ProductionManagers"))
{
// Authenticated
}
If using something else like Java, PHP, Ruby, you need to call the .NET API or Win32 API to do that. You cannot simply make a LDAP query to retrieve that information. The reason is that the group membership information for local group is actually stored at local machines but not that Active Directory.
You need to call something like NetLocalGroupGetMembers to retrieve the group membership information from the local store.

Resources