I need help of experts!
I write ASP.NET MVC 4 Intranet application. I using Windows Authentication, the domain name get through User.Identity.Name. I have a database with the configured data context, where more complete information about the user: Last name, First name, E-mail, etc. As well as a list of user access groups.
Needed to make sure that a user open a program, has received the required access from the database, his name brought up in the upper right corner of the page.
Now I have realized that with the use of OWIN Asp.Net Identity. I created a base controller that inherits the other controllers, it ordered CurrentUser method for the user and his SignIn:
protected ApplicationUser CurrentUser
{
get
{
var curUser = AppUserManager.FindByName(User.Identity.Name);
if (curUser != null)
SignInManager.SignIn(curUser, true, true);
else
curUser = new ApplicationUser();
return curUser;
}
}
protected ApplicationSignInManager SignInManager
{
get
{
return HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
}
I understand that these operations are unnecessary, when you refresh the page every time it is necessary to drag into the database, users receive and make SignIn, which is unnecessary.
I'm sure you can realize all without using Asp.Net Identity. For example by expanding IPrincipal User, adding him to the field name, which are needed when displaying pages and adding once Roles from the database and save all in Cookies.
Please, help me! And sorry for my bad english...
Related
I have mvc 4 project with default Account Controller and UsersContext as DbContext. When a user, Suppose User1 logged in with REMEMBER ME checked on mobile. And next day User1 login in Laptop and changed its password, now User1 opened his mobile it is already logged in even when password is changed.
Is there any way by which i can force that User1 to Logout all the Devices,
without storing any session id in database?
I imagine you could store a "last password change date" in the cookie. On authentication, if the user has changed his password since the stored date, then do not authenticate the user.
You should probably store a hash of the last password change date, so that it can't be tampered with from the client side.
Have a flag in the database that checks users on Session_Start that invalidates their session if that flag is set. May not necessarily use a boolean, you can use a DateTime value and invalidate all sessions that started prior to that time. This could be done by checking a value stored in a cookie upon login.
There is nothing built into ASP.NET MVC (that I know of) that provides this functionality
I know this is an old topic but I ran across this today. The cause was slightly different, but I needed to do the same thing - log off a user if 'remember me' had been chosen.
The cause in my case was a change of database. I changed the database name in my connection string (from a 'test' DB to a 'dev' DB), and I will still logged in after running the project, which caused a problem because the user did not actually exist in this new DB.
So in Global.asax I did the following:
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
protected void Session_Start()
{
if (User.Identity.IsAuthenticated)
{
var user = UserManager.FindByName(User.Identity.Name);
if (user == null)
{
HttpContext.Current.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
Response.Redirect("/", true);
}
}
}
You need to redirect and terminate execution of the current page (by passing true) because (as I understand it) the sign out does not affect the current request, so the page that was loading will still load as if the user is logged in. Anyone feel free to correct, clarify or expand upon this.
I have a AngularJS client application that uses javascript (not coffeescript or typescript) Oauth2 to authenticate against a WebAPI 2 application using the latest Identity 2. All the software in my application is the very latest and is based on this example. My client browser targets are IE9 and above.
Note that I made some minor changes from the example above in that I do not urlencode all of the data sent to the server using the transform. Instead I urlencode only in the authenticate method below:
user.authenticate = function (userName, password, rememberMe, successCallback, errorCallback) {
var config = {
method: 'POST',
url: '/Token',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password),
};
I am developing with VS2013 Update 2 and on the server, I use C#, the latest Entity Framework and SQL Server 2012.
To login my client calls a /Token method to the WebAPI and passes the userid and password. The WebAPI then responds with a token to the client which I store. With each request to the WebAPI the token is sent back and authenticated:
$http.defaults.headers.common.Authorization = 'Bearer ' + user.data.bearerToken;
This works very well so far but as it stands the application is unable to tell the difference between users that have different roles assigned to them.
Some of the WebAPI methods can only be executed by users who have a certain role. I would like to adjust the menus of my front-end AngularJS application so that only if the user has this role then the appropriate links will appear visible. I do realize that this would not stop a user from checking the HTML and posting but I am not concerned about this as I will still have method decoration to limit the ability of users not in a role to perform actions.
Can someone give me an example of how I can do this using just the suite of products mentioned above that I mention in the question plus JavaScript Web Tokens if they help make bring the solution up to date. From what I understand roles are handled by claims but I do not understand how to add these and send them back to the client with tokens. I have done a lot of research on the internet but I've not been able to find any good examples as I think most of this is very new and not many people have had the chance to explore how a SPA can use these very latest software components.
When answering this question please note that I am not looking for an answer that can tell the community how to set up roles on the server or an answer that explains about how important it is to provide role checks on the server. I think almost everyone is aware of this. What I really think will be of use is some very detailed technical suggestions with sample code and an explanation. To keep the answer focused it would probably be of help to everyone if answers that do not meet this need are not posted as suggested answers.
Thank you in advance.
The short answer to your question is ApplicationOAuthProvider.CreateProperties method. Its created for you by default and is found under WebApi2/Provider/ApplicationOAuthProvider.cs, By default it only sends the userName
//WepApi2/Providers/ApplicationOAuthProvider.cs
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
I would make the following update (in case I need to send more user data later on):
public static AuthenticationProperties CreateProperties(string userName, ClaimsIdentity oAuthIdentity)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName},
{ "roles",string.Join(",",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())}
};
return new AuthenticationProperties(data);
}
If you haven't made major changes to the WebApi project, ApplicationOAuthProvider.CreateProperties is only referenced in two places, just update the calling code to pass the oAuthIdentity along with user.UserName and you'll get the user roles sent along with the access token response:
{
"access_token": "ZpxAZyYuvCaWgShUz0c_XDLFqpbC0-DIeXl_tuFbr11G-5hzBzSUxFNwNPahsasBD9t6mDDJGHcuEqdvtBT4kDNQXFcjWYvFP7U2Y0EvLS3yejdSvUrh2v1N7Ntz80WKe5G_wy2t11eT0l48dgdyak8lYcl3Nx8D0cgwlQm-pePIanYZatdPFP9q5jzhD-_k9SF-ARTHgf0ePnbvhLBi1MCYQjvfgPKlbBHt0M5qjwGAeFg1IhSVj0gb4g9QTXoiPhRmxGBmjOpGgzxXixavmrpM7cCBFLoR3DCGnIJo6pwT-6VArxlB8-ZyyOZqh_6gGtptd0lIu8iJRUIGwO9HFNkROdoE9T4buwLnhPpWpy9geBjPVwsB1K3xnbch26YbklhxIHVybBxeIVXd17QTw_LjlQ5TJdqpAYfiZ5B9Nx2AFYYYe3--aemh4y1XOIvN",
"token_type": "bearer",
"expires_in": 1209599,
"userName": "MK",
"roles": "Admin,Public",
".issued": "Fri, 23 May 2014 17:36:54 GMT",
".expires": "Fri, 06 Jun 2014 17:36:54 GMT"
}
Now you have the roles available, you can use Angular conditional directives to show/hide actions according to user roles.
If you need more clarification, please let me know.
Edit:
Decorating your controller methods with Authorize attribute is valid, since the HttpContext.Current.User.Identity is actually a ClaimsIdentity. But as not to hard code security logic inside the application, I prefer using ClaimsAuthorizationManager
public ActionResult Secure()
{
if(!ClaimsPrincipalPermission.CheckAccess("resource", "action"))
return new HttpUnauthorizedResult();
ViewBag.Message = "You are allowed to perform action on resource.";
return View();
}
Roles creation using RoleManager:
RoleManager roleManger = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>());
roleManager.Create(new IdentityRole() { Name = "Admin" });
Roles assignment using UserManager:
userManager.AddToRole(user.Id, "Admin");
There are 2 ways I see you can approach your problem.
include the "Role" Information to the token by a hash or a simple string append as you are the one generating the token, then you can decipher it on the angular.
it seems you want to use ASP.NET Identity system and store and retrieve the role information there. If that is the case you can go through this post pay attention to "Initialize the database to create Admin Role and Admin User" section.
IMO, #1 will give you more flexibility on how you store and use your user data as #2 you are following Microsoft's IdentityUser , although it look magic sometimes and it tend to post limitation and you need to spend time to understand how it works behind the scene and make it work for your project.
To know more about the "Individual User Accounts" you pick during the WebAPI project you created, you can go to http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visual-studio#indauth
I have a very similar scenario as yours, but instead of using tokens to authenticate, I use an Identity Server (Thinktecture) to handle my authentication. My app redirects to the Identity Server to authenticate and it comes back with some very basic claims (username and email). This happens as soon as someone tries to first browse to the page. Once the user is authenticated and redirected to my app I make another call to the server to get the user's permissions. These permissions are stored inside a Security service (AngularJS) which also exposes a "hasPermissions" method. I then use ng-if to decide if I am going to display certain parts of the page - including menu items. Something to this effect:
var service = {
currentUser: ...,
isAuthenticated: function() {
return ...;
},
checkAccess: function(permission) {
return service.isAuthenticated() ?
!!(service.currentUser.permissions.indexOf(permission) > -1) : false;
}
}
Remember that all all the permissions and html elements are visible to anyone who decides to hit the dev tools button and take a peek. You have to do the same checks on the server side before you perform any action. We have a custom Authorization attribute based off of this that checks if the user has the necessary permissions to execute the MVC/WebAPI action before it is executed for simple cases or actually check it within the Action or the HTTP resource before doing anything that needs elevated privileges.
If you want the client to not see any html elements or certain sections of your site you can either point your templates to a MVC action that will authenticate and then return the HTML template or redirect to another page (not the SPA realm) and have them authenticated on the server before the response is served back.
Here another answer:
In ApplicationOAuthProvider.cs
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
simply add a custom header!
context.OwinContext.Response.Headers.Add("Roles", userManager.GetRoles(user.Id).ToArray());
I have a MVC 5 asp.net website where I need to expose a number of REST APIs to a stand-alone mobile client. The rest of the site is using Forms based security where it sets the ASP.NET_SessionId as a cookie, and that is used to authenticate the user with the request after they log in. With my mobile application, I am not able to use the cookie method because of the cross-doman issue. What I would like to do is add a header "X-SessionId" with the value of the ASP.NET_SessionId, then on the server side, have a filter that looks for that field, and if it is present, associates the request with the given session. (Client will log in with an AJAX POST call which will return the ASP.NET_SessionId upon successful login).
Is this possible?
Something like this?
public sealed class CustomSecurityAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (string.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["X-SessionId"]) && IsAuthenticated(ilterContext.HttpContext.Request.Headers["X-SessionId"]))
filterContext.Result = new HttpNotFoundResult();
}
private bool IsAuthenticated(string sessionId)
{
// get your user details from your database (or whatever)
var user = new UserRepository().Get(sessionId);
if (user == null)
return false;
// build up an identity, use your own or out of the box.
FormsIdentity itentity = new MyIdentity(user);
// Set the user
filterContext.HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(itentity , user.Roles);
return true;
}
}
You are going to have to store current sessions in your database, so for example when a user logs in grab the sessionid and stick it in the db, so you know they have 1..n current sessions.
Then you can look it up as part of your authentication.
Edit:
Let's take a step back, never mind cookies and sessions for the moment.
You have a website and a restful api, they both servce different purposes and clients and have different security requirements.
So what are the most common options for securing your Api?
Basic authentication.
Most restful APIs require a username/password to be sent through with each request, as part of the headers or in the request itself.
An authentication token
You can provide a token associated with a user account (a guid could suffice) when requests are made you check for the token.
Using an existing protocal like OAuth
I would recommend using these common scenarios to be sure you don't miss something and open your self up to security vulnerabilities.
Is there a reason you can't use any of these?
I have a couple of systems which uses external authentication, google authentication.
I'm just keeping the login information in a session variable and keep track of the user that way (no membership provider).
I would like to have the user identity in the HttpContext.Current.User object.
Should I assign the user manually on an event in Global.asax.cs, or could I have the user automatically identified during the session?
You could write a custom Authorize attribute which will take care of assigning the HttpContext.Current.User property from the session:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var user = httpContext.Session["username"] as string;
if (string.IsNullOrEmpty(user))
{
// we don't have any username inside the session => unauthorized access
return false;
}
// we have a username inside the session => assign the User property
// so that it could be accessed from anywhere
var identity = new GenericIdentity(user);
httpContext.User = new GenericPrincipal(identity, null);
return true;
}
}
Then simply decorate your controllers/actions that require authentication with this custom attribute.
Use a membership provider, it will give you exactly what you want. Even creating your own provider isn't too difficult, just implement the abstract class MembershipProvider and plug into config, or use some of the out-of-the-box providers.
Don't roll your own solution for something critical like security, it will have gaping security holes. Storing authentication info in the session is a really bad idea. It leaves it open to session hijacking, session replay attacks etc.
If you really want to go down the route of custom authentication. Then have a look at the code I posted here. It will show you how you can take control of the authentication cookie, and use this to create your own HttpContext.Current.User instance.
I'm writing a silverlight application that resembles a shopping cart system.
This app can only be launched from the asp.net website after the user is logged in to the site.
Upon first load, the app will send a request to the backend through WCF service to retreive all the existing items in the shopping cart.
Therefore the silverlight app needs to know who the current user is, to find which shopping cart to load.
I found there are a couple of ways so far, but not happy with any of them:
using wcf aspnet compat. silverlight can ask who the current user is by asking the wcf service.
pass parameters from the page to xaml by using xaml.InitParameters and pass in the minimum amount of information to identify a user in a serialized format.
pass parameters through query string to xaml (apparently this is also possible)
Can anyone share the best practice to achieve this?
Thanks
We use the first solution in our projects. You haven't to invent any type of serialization format or so in this case. A disadvantage of this approach - extra async logic at startup.
The example of service:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class UserInfoService : IUserInfoService
{
public UserInfo GetUserInfo()
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
return null;
var userInfo = new UserInfo
{
Login = HttpContext.Current.User.Identity.Name,
Fullname = ...,
};
return userInfo;
}
}
Sending userid via initParams or query string is not good idea I think. Such things should be more hidden.
The real important thing is to verify user on server on each service call because anyone can call your services in similar way as your app.
HTH