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.
Related
I have an ASP.NET Core 5 MVC hosted in an Azure AppService.
I've use Azure AD to limit access to the app to specific set of users.
This has been working fine without any Authentication code or configuration in the app.
Now I'm trying to use Azure AD App Roles to limit functionality per roles. I defined App Roles in Azure AD, and assigned them to different users.
Running the App, and going to ./auth/me, I get the user access token the roles are showing as expected.
Now I thought I can only use the [Authorize(Roles = "SomeRole")] on top of ASP.NET controller actions to control access.
First trial, I get the following error when invoking the controller action with the [Authorize] attribute:
InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
I can solve this error by adding the following call in the ConfigureServices method:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
But now trying to invoke the controller action I get the following error:
Access Denied, you are not Authorized.
So apparently I'm missing something to link the [Authorize] attribute with the access token received, which has the correct roles.
Please advise.
This has been working fine without any Authentication code or
configuration in the app
Then I'm afraid you are using azure APP service easy auth. You only need to register an Azure AD application and set it in your azure web app instance. And then all the users in your tenant can sign in with their account.
Your requirement now is that you also want to allow specific users to access your app, so you come up with an idea that you can assign roles to some of the users and let your application to validate the role. So you add services.AddMicrosoftIdentityWebApiAuthentication and [Authorize] in your code. But to be honest, that's not the easiest way to do it because you already enabled easy auth and it's better to not adding any code as well. So I'm afraid you can take a look at this document. It allows you to set a list of users who can sign in your app which configure to use the Azure ad app. If users aren't assigned to the Aad app try to sign in, they will get error information.
The steps to do it can be summarized as:
Going to Azure Active Directory -> Enterprise applications -> choose
the app you used in your app -> Properties -> Assignment required? set
to yes then save
Switch from Properties blade to Users and groups blade -> click add
user/group -> select users which you allow them to sign in your app ->
click assign
What you have done is implement by codes. You integrated Azure AD authentication into your MVC project. It can't validate user roles, and the user roles are used for api authorization. Here's a blog introducing it. The roles defined in Azure AD app is different from the asp.net core identity roles.
=====================================================
Ok I got your point, you want to set attributes like [Authorize(Policy = "mypolicy")] for different Controller method in your MVC project to restrict specific users to specific method. You want to use roles to differ the users.
Here's the solution:
you have to create azure ad app roles and assign app roles to users. The app roles is different from default Azure ad user roles, app roles are used for your scenario.
modify your MVC application following this sample or do what I shared below:
var builder = WebApplication.CreateBuilder(args);
// This is required to be instantiated before the OpenIdConnectOptions starts getting configured.
// By default, the claims mapping will map claim names in the old format to accommodate older SAML applications.
// 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' instead of 'roles'
// This flag ensures that the ClaimsIdentity claims collection will be built from the claims in the token
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration);
builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme,options =>
{
// The claim in the Jwt token where App roles are available.
options.TokenValidationParameters.RoleClaimType = "roles";
});
// Adding authorization policies that enforce authorization using Azure AD roles.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("mypolicy", policy => policy.RequireRole("Tiny.AccessEndpoint"));
});
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
Then in the Controller, adding [Authorize] and adding [Authorize(Policy = "mypolicy")] action method. The test with a user who doesn't assign the app role will show error below.
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 have an application that should be open to the Internet at the time of development. The application has its own authorization (forms).
We can not restrict access to the server over a range of IP addresses. We also need the site to behave similarly as in the absence of global access check (QA test application in this environment).
How to access can be arranged at IIS?
User steps:
Go to site.com
User sees a pop-up window (global user name; global password - the same for all users)
Redirect to site (as anonymous user)
Go to login page and enter local user name and password (specific for current user)
I will be grateful for any advice
Thanks
Create filter (inherit from ActionFilterAttribute)
Override OnActionExecuting method (check custom cookie). If custom auth cookie absent:
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusDescription = "Unauthorized";
filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", "Basic realm=\"Secure Area\"");
filterContext.HttpContext.Response.Write("401, please authenticate");
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.Result = new EmptyResult();
filterContext.HttpContext.Response.End();
base.OnActionExecuting(filterContext);
Register filter in Global.asax in Application_Start()
I have IIS 7.5 site:
Authentication = Windows Aythentication enabled
Application Pool = DefaultAppPool
DefaultAppPool Identity = ApplicationPoolIdentity
Load User Profile = True
On the filesystem,
DefaultAppPool has Read and Execute privileges to the entire site.
Also added a security group with Read and Execute privileges to the entire site.
With these settings, only users in the security group are able to access the site. All others get a AD login window, which has no affect. I'm not understanding this behaviour.
From research, it looks like I don't need to add the DefaultAppPool to the filesystem, if users are only executing, but still doesn't explain why they get the login challenge.
I'm also unclear if i need to set the AuthenticatedUserOverride (in Config Editor) from UseAuthenticatedUser to UseWorkerProcessUser if i want to use the filesystem security of DefaultAppPool. When i set this, i get an access error, not even the login challenge.
Note: site is not in the Default Web Site, but on a specific port number.
I'm unclear why i seem to need users listed in an ACL rather than using the generic DefaultAppPool.
Windows authentication determines how you determine who is who. Impersonation means which user account the security context runs under. Because you are loading the user profile, the context is taking on the AD user's security. Your DefaultAppPool identity is now out of the picture which is why you need ACL's on your files / folder.
Users will continue to receive the login prompt who are not cleared at the ACL level because IIS doesn't know what to do until an account that can access the files is provided. Watch in fiddler and you'll continue to see challenge messages from the server.
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!