So we have our web app up and going with entity framework. What we'd like to do is impersonate the current user when we're accessing the DB. We're not interested in setting impersonation up in our web config.
Ideally using something like this: Link when we're about to access data.
UPDATED: I'm looking for a way to abstract this code out so I don't have to have it in every repository function call.
Your EF connection string is going to need to be set up for using a trusted connection.
You won't need to set up Impersonation in your web.config, but you do need to be using Windows Authentication.
Then just do this:
using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
using (var dbContext = new MyEntityFrameworkContainer())
{
...
}
Any code inside the curly braces of the using statements will run as the authenticated user.
Related
In the new SPA (react and angular) web templates for .Net core 5. I'd like to fetch the current logged in User. However, when I try to get a user in the controller the User doesn't have anything populated.
Does anyone know how to achieve this with the new Identity Classes?
I've made a repo of the vanilla reactJS template, the only thing I changed is the line highlighted in my screenshot below to show there's no user set.
I've done a bit of googling and these pages are all I could find on the topic, unfortunately, they don't give enough detail for me to be able to implement anything practical.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-5.0
Backend:
ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);
On the frontend if you need yo access it
//with UserManager
UserManager<ApplicationUser> UserManager
#{
var user = await UserManager.GetUserAsync(User);
}
// with SignInManager
SignInManager<ApplicationUser> SignInManager
#if (SignInManager.IsSignedIn(User))
To answer my own question.
In order to populate the User detail in the HttpContext you have 1 of 2 routes. Either change
services.AddDefaultIdentity<IdentityUser>();
to
services.AddIdentity<IdentityUser, IdentityRole>();
or you can continue to use the Core Identity
services.AddIdentityCore<IdentityUser>();
but then you also need to implement your own Microsoft.AspNetCore.Identity.ISecurityStampValidator and add it as transient services.AddTransient<ISecurityStampValidator, MyValidator>();
Your MyValidator implementation will be responsible for validating the cookie. You can see the default implementation here on github
Edit: Under the hood services.AddDefaultIdentity<IdentityUser>(); uses services.AddIdentityCore<IdentityUser>();. I feel like its importatnt to know this.
First things first. I'm a complete OAuth newbie. This will be my first stab at it, and things are getting hairy...
I'm writing a single page application using Durandal & Web API.
The user needs to be able to login using any social network.
I don't have access to a database whatsoever, I have to call an unprotected 3rd party web service which I consume server-side, and need to protect using OAuth.
So I've managed to add the files to my solution which generates the login using facebook contol/button (created a new MVC4 web application, and did a manual copy and paste of all the auth related files, updated bootstrappers etc..), and the code seems to work for the most part.
When facebook redirects back to
[AllowAnonymous]
public ActionResult ExternalLoginCallback(string returnUrl)
{
AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(this.Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
if (!result.IsSuccessful)
{
return this.RedirectToAction("ExternalLoginFailure");
}
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
{
return this.RedirectToLocal(returnUrl);
}
//code removed for brevity ....
}
I get the error specified once the following line tries to execute.
OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false)
I've removed the [InitializeSimpleMembership] attribute from the controller, as I don't have a database.
Please forgive me if this is the dumbest question ever, but...
Why does the login fail? I mean at that point, isn't the app trying to log into facebook, why does it need a databse? Or am I correct in saying I can remove/replace that code section, with a login/authorise call on the web-service I'm using?
Not the dumbest question ever. Not by a long shot. But you are getting the error because your membership provider is still set to use the SimpleMembershipProvider and OAuthWebSecurity will use the default membership provider. If you don't want to use a database you will have to create or find a different membership provider to use.
EDIT:
I know you said you don't have access to a DB but if you can use SQL Compact you can just stick with the default SimpleMembershipProvider(check out Hanselman's blog) or DevArt has a SQLLite provider. Also the MemFlex Project has a RavenDb provider. If none of those work I think you might just have to write your own.
Lets suppose that I have some web app that using backbone.js in the client side, and on the server side some RESTful API that support the DELETE method.
The database of the app contains some categories and posts, and on the client side I have collection that called "categories" that using fetch() to retrieve all the categories from the server using GET method.
How can I prevent from any user to just open his console in chrome or firebug in Firefox, explore my JavaScript files, figuring the structure of my backbone models and just run collections.destroy() from his console and delete all my database....
Am I missing something here?
I've googled it but didn't find an answer...
You have to put up some validation on your server side since you cannot trust what came from the client.
For example you could write some security checks that run before execute the database's calls, like these (PHP pseudo-code):
$model = Posts;
if($model->checkUserRights('read')) {
$model = Posts->findById($_GET['id']);
echo json_encode($model);
} else {
echo "You have not the require rights to access ".$model->tableName;
}
And in Posts's model:
public function checkUserRights($op){
// Run some code for each possible operations's type
}
You could also add some rules to filter the values you will return to the clients or the values they will post to your server, before process an update request.
It's really up to you and what technology you will use on your server.
You can easily prevent this on the server side by not doing anything when the DELETE method is received from the client.
If you're using rails, your delete method would look like this
def destroy
#not allowing deletions through the REST api
end
I'm successfully using Node.js + Express + Everyauth ( https://github.com/abelmartin/Express-And-Everyauth/blob/master/app.js ) to login to Facebook, Twitter, etc. from my application.
The problem I'm trying to wrap my head around is that Everyauth seems to be "configure and forget." I set up a single everyauth object and configure it to act as middleware for express, and then forget about it. For example, if I want to create a mobile Facebook login I do:
var app = express.createServer();
everyauth.facebook
.appId('AAAA')
.appSecret('BBBB')
.entryPath('/login/facebook')
.callbackPath('/callback/facebook')
.mobile(true); // mobile!
app.use(everyauth.middleware());
everyauth.helpExpress(app);
app.listen(8000);
Here's the problem:
Both mobile and non-mobile clients will connect to my server, and I don't know which is connecting until the connection is made. Even worse, I need to support multiple Facebook app IDs (and, again, I don't know which one I will want to use until the client connects and I partially parse the input). Because everyauth is a singleton which in configured once, I cannot see how to make these changes to the configuration based upon the request that is made.
What it seems like is that I need to create some sort of middleware which acts before the everyauth middleware to configure the everyauth object, such that everyauth subsequently uses the correct appId/appSecret/mobile parameters. I have no clue how to go about this...
Suggestions?
Here's the best idea I have so far, though it seems terrible:
Create an everyauth object for every possible configuration using a different entryPath for each...
Apparently I jumped the gun and wrote this before my morning cup of coffee, because I answered my own question, and it was quite easy to implement. Basically I just had to create my own custom express middleware to switch the everyauth configuration before the everyauth gets its grubby paws on the request, so...
var configureEveryauth = function()
{
return function configure(req, res, next) {
// make some changes to the everyauth object as needed....
next();
};
}
and now my setup becomes:
var app = express.createServer();
everyauth.facebook
.entryPath('/login/facebook')
.callbackPath('/callback/facebook');
app.use(configureEveryauth());
app.use(everyauth.middleware());
everyauth.helpExpress(app);
app.listen(8000);
Notice that I don't even bother fully configuring the everyauth Facebook object during the startup, since I know that the middleware will fill in the missing params.
Using the new ASP.NET Web API beta. I can not seem to get the suggested method of authenticating users, to work. Where the suggested approach seems to be, to add the [Authorize] filter to the API controllers. For example:
[Authorize]
public IEnumerable<Item> Get()
{
return itemsService.GetItems();
}
This does not work as intended though. When requesting the resource, you get redirected to a login form. Which is not very suitable for a RESTful webapi.
How should I proceed with this? Will it work differently in future versions?, or should I fall back to implementing my own action filter?
Double check that you are using the System.Web.Http.AuthorizeAttribute and not the System.Web.Mvc.AuthorizeAttribute. This bit me before. I know the WebAPI team is trying to pull everything together so that it is familiar to MVC users, but I think somethings are needlessly confusing.
Set your authentication mode to None:
<authentication mode="None" />
None Specifies no authentication. Your application expects only anonymous users or the application provides its own authentication.
http://msdn.microsoft.com/en-us/library/532aee0e.aspx
Of course then you have to provide some sort of authentication via headers or tokens or something. You could also specify Windows and use the built in auth via headers.
If this site is mixed between API and actual pages that do need the Forms setting, then you will need to write your own handling.
All the attribute does is return an HttpUnauthorizedResult instance, the redirection is done outside of the attribute, so its not the problem, its your authentication provider.
Finally, I've found a solution at:
ASP.NET MVC 4 WebAPI authorization
This article shows how you can fix this issue.
You are being redirected to login page because forms authentication module does this automatically. To get rid of that behavior disable forms authentication as suggested by Paul.
If you want to use more REST friendly approach you should consider implementing HTTP authorization support.
Take a look at this blog post http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/
ASP.NET 5 Introduced the new Microsoft.AspNet.Authorization System which can secure both MVC and Web API controllers.
For more see my related answer here.
Update:
At that time 2 years ago it was Microsoft.AspNetCore.Authorization.
As #Chris Haines pointed out. now it resides on
Microsoft.AspNetCore.Authorization.
From .NET core 1.0 to 2.0 many namespaces have been moved i think.
And spread functionality between .net classic and core was obscure.
That's why Microsoft introduced the .net standard.
.net standard
Also, look at my answer for:
How to secure an ASP.NET Web API
There is a NuGet package I have created which you can use for convenience.
If you're using a Role, make sure you have it spelled correctly :
If your role is called 'Administrator' then this - for instance will not work :
[System.Web.Http.Authorize(Roles = "Administator")]
Neither will this :
[System.Web.Http.Authorize(Roles = "Administrators")]
Oops...
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Produces("application/json")]
[Route("api/[controller]")]
public class CitiesController : Controller
{
[HttpGet("[action]")]
public IActionResult Get(long cityId) => Ok(Mapper.Map<City, CityDTO>(director.UnitOfWork.Cities.Get(cityId)));
}
Use
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Filter with authentication type