I want to access shared resources on the other machine from code. My environment is a Sharepoint 2010 WebApplication working in Claims Authentication mode. Application's Windows identity is NT AUTHORITY\IUSR - not the user that has logged in, so to access the net share resources on the other machine I need to perform impersonation. Since I have no valid windows token to perform impersonation I need to use Claims To Windows Token Service, which I have configured to be able to be accessed by NT AUTHORITY\IUSR. The service is running as Local System account. I am able to get the impersonation level windows token from the service which I am using to perform impersonation using following code:
using (wi = S4UClient.UpnLogon(upn))
{
using(WindowsImpersonationContext wic2 = wi.Impersonate())
{
//code to access windows shares
}
}
The service is properly returning the token and the impersonation is successful in a way that when I return the current loggedin user's identity using following code:
WindowsIdentity.GetCurrent().Name;
I am getting the username of the user that is logged in to sharepoint.
The problem is that there is an "access denied" error when trying to access the network resources. The problem is surly because of the impersonation via c2wts since when I am providing the actual credentials (login and password) to impersonate the user using following code:
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Int32 LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, Int32 dwLogonType, Int32 dwLogonProvider, ref IntPtr phToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern Int32 ImpersonateLoggedOnUser(IntPtr hToken);
private static IntPtr ImpersonateUser(string user, string domain, string password)
{
IntPtr lnToken = new IntPtr(0);
Int32 TResult = LogonUser(user, domain, password, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_WINNT50, ref lnToken);
if (TResult > 0)
{
ImpersonateLoggedOnUser(lnToken);
}
return lnToken;
}
I am able to enumerate shares on the server without any problem.
From the information I found on the internet to properly configure the service to access the sql database on another server I need to enable protocol transition and constrained delegation in the Active Directory and set that constrain to the mysql service. Still I am not sure how to enable delegation in this case since what I am trying to achieve is to be able to access any share on any machine, if only the user has permissions to do it.
To sum things up, I want to impersonate the user from within Sharepoint Claims Based Authentication WebApplication to access net shares on other computers but even tough impersonation using c2wts seems to be successful(correct username returned when checking current username) I am not able to access the resources on the other computer. On the other hand when impersonating using login and password provided directly in the code everything works ok, but that is not an option for me.
Ok I actually managed to solve it.
What I did was setting the impersonation in the web.config of my webapplication to false:
<identity impersonate="false" />
In that case I was able to see files on the local shares. To enable acccess in other computers I had to create Service Principal Name (SPN) for the account on which my webapplication was running.
SETSPN -A HTTP/ServerName myDomain\webAppAccountUserName
SETSPN -A HTTP/FQDNServerName myDomain\webAppAccountUserName
and SPN for the computer that webapplication and c2wts (c2wts is working as LocalSystem) was running
SETSPN -A HOST/ServerName ServerName
SETSPN -A HOST/FQDNServerName ServerName
Next step is to configure constrained delegation and protocol transitioning so we can delegate to the file share on the other computer to do that we need to open Active Directory Users And Computers Tool and configure delegation for the web application account and computer account that c2wts is working on. Specifically we need to:
select the account we are interested in, like computer account,
right click,
select properties,
select delegation tab,
select "Trust this computer for delegation to specified services only" and
"Use any authentication protocol",
add "common internet file system (cifs)" from the computer we want to connect to
We need to do exactly the same thing for the webapp account
Setting the value "Trust this computer for delegation to any service" will not work!
Related
We have a web app that runs on our corporate intranet. I get the following error when I try to access a network path in my MVC controller:
Access to the path '\Server001\SharedFiles\CA' is denied.
The App is hosted on IIS and app pool is set to ApplicationPoolIdentity. I do not want to set it with an account that has access right to all the directories. I'd like each user to only access the folders they're allowed to.
After some research I figured the only way is to programmatically impersonate the user when it's needed. To test this out, I created a New ASP.NET Core 6 MVC project with Authentication set to Windows(Also enabled Windows Authentication in IIS site). Then I added the following code to my controller:
public async Task<IActionResult> Index()
{
// The user used as Log On as for the Windows Service
var serviceUser = WindowsIdentity.GetCurrent();
// returns "IIS APPPOOL\MvcTest"
// The user to be impersonated
// COMPANYDOMAIN\MyName
var userToImpersonate = (WindowsIdentity)HttpContext.User.Identity;
await WindowsIdentity.RunImpersonatedAsync(userToImpersonate.AccessToken, async () =>
{
var ImpersonatedUser = WindowsIdentity.GetCurrent();
_logger.LogInformation(ImpersonatedUser.ImpersonationLevel.ToString());
// returns "impersonate"
_logger.LogInformation(ImpersonatedUser.Name);
// Here we are getting "COMPANYDOMAIN\MyName"
try
{
var files = Directory.GetFiles("\\\\Server001\\SharedFiles\\CA");
return View(files);
}
catch (Exception ex) { }
});
}
Although this shows that WindowsIdentity.GetCurrent().Name has changed to my domain account(what I logged in as) but for some reason it is not accepting the impersonated user. I still get access denied error. Is this permission issues?
I am able to browse the "\Server001\SharedFiles" using my domain account(COMPANYDOMAIN\MyName), Also when I change the app pool identity to my domain account, the app still works.
If WindowsIdentity.GetCurrent().Name shows the correct user, then your impersonation is likely working correctly.
File shares in Windows have two sets of permissions that define what a user can do:
The share permissions. This defines who is allowed to access the folder remotely. These are set in the same place where you initially setup the share.
File system permissions. These are the normal file permissions that you would think of.
Make sure that both the share permissions and the file system permissions allow the user access. It is possible for the file system permissions to allow someone full control, but the share permissions to deny them any access. In that case they could access and modify any files locally, but couldn't do anything through the share.
I would usually set the share permissions to Read/Write for Everyone and then use the file system permissions to restrict access.
My web app's web.config used form authentication mode in <system.web><authentication mode="Form" /></system.web> and the IIS Authentication settings is as below:
In addition the appPool's identity is using another specific user 'domain\godMode' as the service account. So eventually, whenever I use HttpContext.Current.Request.LogonUserIdentity.Name or Security.Principal.WindowsIdentity.GetCurrent().Name or Page.User.Identity.Name.ToString()
I would get either an scrambled string as an user name or the appPool's Identity 'domain\godMode'.
I am getting concerned that within this constrained setting with anonymous auth. mode without impersonation, there is nothing I can do to get my real 'doamin\user' name back...
So my question is how can I get these User.Identity.Name classes to list as 'domain\user' ?
Trying to implement windows authentication on my published asp.net core 2.2 application.
Hosting server is Windows server 2016 (IIS).
I would like to use the active directory logged in user account to authenticate the user on my application.
I'm getting the user details by these methods:
User.Identity.Name; //return null in local host, worked when IIS
System.Security.Principal.WindowsIdentity.GetCurrent() // local host
I keep getting in the browser, the Sign in dialog box (although I would like to get rid of it, even when entering credentials - <username> + password - it doesn't authenticated).
I would like to get rid of it
Stop getting error 401 - unauthorized
I've configured what ever I was advised - both IIS and browser, but still - keep getting it:
Browser:
Browser security - Entered the host IP address to the trusted sites
IIS:
Set Authentication => enable Windows Authentication to true.
Through web.config - set "forwardWindowsAuthToken" to "true".
Site Configuration:
In the IIS site configuration (applicationHost) - system.webserver -> Security -> Authentication -> windows authentication -> "UseKernelmode" = "true"
ApplicationPool:
.NET CLR Vesrion = "No Managed Code"
Managed Pipeline Mode = " Integrated"
event tried to change in the "advanced settings" the Identity from "ApplicationPoolIdentity" to "NetworkService"
NTFS permissions:
Set basic and defaults Permissions to the account<Server host Name>\IIS_IUSRS on the server published code directory: Read & Execute, List folder contents, Read.
Maybe the problem is here - because the IIS_IUSRS account is defined in the server and not in the domain ?
You can try this method to solve the problem:
Open iis and in Windows Authentication, Right-Click to set the Providers, set the NTLM to be FIRST.
Check that under Advanced Settings... the Extended Protection is Accept and Enable Kernel-mode authentication is checked.
I have installed "Domino Sample REST Service Feature" from 901v00_11.20141217-1000 version of XPages Extension Library. OpenNtfSample service (com.ibm.domino.services.sample.service.SampleService) works as it should in general and the only problem with it that it completely ignores authentication settings of the server.
I have tried both Basic and Session Authentication as described in Authenticating Domino REST Service Requests and the result I get is the following - the service returns data always and does not ask for any user name and password.
The server is configured with Session Authentication now and I get password prompt when I try to access
{my_server}/api/data
but does not get it when I open
{my_server}/api/sample
After I had added this Web Site Rule
Description: DAS service
Type of rule: Override Session Authentication
Incoming URL pattern: /api/
the server changed password prompt for
{my_server}/api/data
but
{my_server}/api/sample
remained open.
Has anybody experienced this kind of error? Can anybody help me password protect this sample service so that I could start developing my own once based this example?
The /api/sample resource is wide open on purpose. That just returns a link to the contacts resource -- /xpagesext.nsf/api/sample/contacts.
If you really want to prevent anonymous access to the /api/sample resource, there are two possible solutions: 1) Disable anonymous access for all HTTP requests, or 2) Make a change to the RootResource class. The first solution is a server config change. I'm sure you can find details about that elsewhere. Since this is StackOverflow, I'll focus on the second solution.
As you have already noticed, we don't allow anonymous access to the /api/data resource. You can mimic that behavior in the /api/sample resource with a simple change to RootResource.getLinks(). Near the top of the method, just add these lines of code:
boolean authenticated = false;
Session session = ContextInfo.getUserSession();
if ( session != null ) {
String userName = session.getEffectiveUserName();
if ( userName != null && !userName.equals("Anonymous")) {
authenticated = true;
}
}
if ( !authenticated ) {
throw new NoAccessSignal("Need user context");
}
By the way, you won't need to make the same change to the contacts resource class (ContactsListResource.java). Because the contacts resource URL includes a database name (xpagesext.nsf), the web server will attempt to open the database before forwarding the request to the REST service. You can prevent anonymous access to the contacts resource by changing the ACL of xpagesext.nsf. Just make sure the default access is "No access".
I am trying to connect to Office Communication Server using the Unified Communications Managed API. I have tried my user and a fresh user enabled for OCS. Both account can successfully log into the Office Communicator client, but fail using the API. When creating the network credential, if I pass in the username in the form domain\username, I get this error:
SupportedAuthenticationProtocols=Ntlm, Kerberos
Realm=SIP Communications Service
FailureReason=InvalidCredentials
ErrorCode=-2146893044
Microsoft.Rtc.Signaling.AuthenticationException: The log on was denied. Check that the proper credentials are being used and the account is active. ---> Microsoft.Rtc.Internal.Sip.AuthException: NegotiateSecurityAssociation failed, error: - 2146893044
If I leave off the domain in the username I this error:
ResponseCode=404 ResponseText=Not Found
DiagnosticInformation=ErrorCode=4005,Source=OCS.mydomain.com,Reason=Destination URI either not enabled for SIP or does not exist
Turns out this was an oversight on my part. Our AD domain and communicator domain are different, I had assumed they were the same.
The network credential is domain\username, and the sip address should have been sip:username#companyname.com, I was using sip:username#domain.com.
Two things to note:
Username should not contain the domain. There should be a separate Domain property of NetworkCredential that you should be using.
You also need to pass in the user URI as well - for example:
//Initialize and register the endpoint, using the credentials of the user the application will be acting as.
UserEndpointSettings userEndpointSettings = new UserEndpointSettings(_userURI, _userServer);
userEndpointSettings.Credential = _credential;
_userEndpoint = new UserEndpoint(_collabPlatform, userEndpointSettings);
_userEndpoint.BeginEstablish(EndEndpointEstablish, _userEndpoint);