How do i get the identity. The following code enters a value into orderItem. I wish to return orderItemId.
public static StoredProcedure StoreAddToCartSAS(string userName, SAS.Business.Domain.Product product)
{
SubSonic.StoredProcedure sp = new SubSonic.StoredProcedure("Store_AddItemToCart", DataService.GetInstance("dashCommerce"), "dbo");
sp.Command.AddParameter("#productName", product.ProductName, DbType.String);
return sp;
}
That code only creates an SP for you - it doesn't execute it. Assuming the SP returns the new ID with a SELECT:
SELECT ##IDENTITY as newID;
Then you can do this:
var newID=sp.ExecuteScalar();
Related
I am wondering how to create and assign roles in Razor Pages 2.1. application.
I have found how to make them for MVC application (How to create roles in asp.net core and assign them to users and http://hishambinateya.com/role-based-authorization-in-razor-pages), however it does not work for razor pages as I have no IServicesProvider instance.
What I want is just to create admin role and assign it to seeded administrator account. Something similar has been done in this tutorial https://learn.microsoft.com/en-us/aspnet/core/security/authorization/secure-data?view=aspnetcore-2.1, but it seems be sutied for MVC and does not work properly after I applied it to my application. Please help me to understand how to create and seed roles in Razor Pages.
Will be very greatfull for help!
I handle the task next way. First, I used code proposed by Paul Madson in How to create roles in asp.net core and assign them to users. Abovementioned method I have inserted into Startup.cs. It creates administrator role and assigned it to seeded user.
private void CreateRoles(IServiceProvider serviceProvider)
{
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
Task<IdentityResult> roleResult;
string email = "someone#somewhere.com";
//Check that there is an Administrator role and create if not
Task<bool> hasAdminRole = roleManager.RoleExistsAsync("Administrator");
hasAdminRole.Wait();
if (!hasAdminRole.Result)
{
roleResult = roleManager.CreateAsync(new IdentityRole("Administrator"));
roleResult.Wait();
}
//Check if the admin user exists and create it if not
//Add to the Administrator role
Task<ApplicationUser> testUser = userManager.FindByEmailAsync(email);
testUser.Wait();
if (testUser.Result == null)
{
ApplicationUser administrator = new ApplicationUser
{
Email = email,
UserName = email,
Name = email
};
Task<IdentityResult> newUser = userManager.CreateAsync(administrator, "_AStrongP#ssword!123");
newUser.Wait();
if (newUser.Result.Succeeded)
{
Task<IdentityResult> newUserRole = userManager.AddToRoleAsync(administrator, "Administrator");
newUserRole.Wait();
}
}
}
Then, in the same file in Configure method I add argument (IServiceProvider serviceProvider), so you should have something like Configure(..., IServiceProvider serviceProvider). In the end of Configure method I add
CreateRoles(serviceProvider).
To make this code work create ApplicationUser class somwhere, for example in Data folder:
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sobopedia.Data
{
public class ApplicationUser: IdentityUser
{
public string Name { get; set; }
}
}
Finally, inside ConfigureServices method substitute
services.AddIdentity<ApplicationUser>()
.AddEntityFrameworkStores<SobopediaContext>()
.AddDefaultTokenProviders();
with
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<SobopediaContext>()
.AddDefaultTokenProviders();
As a result, after programm starts in table AspNetRoles you will get a new role, while in table AspNetUsers you will have a new user acuiering administrator role.
Unfortunatelly, after you add the following code
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<SobopediaContext>()
.AddDefaultTokenProviders();
pages Login and Registration stop working. In order to handle this problem you may follow next steps:
Scaffold Identity following (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.1&tabs=visual-studio).
Then substitute IdentityUser for ApplicationUser in entire solution. Preserv only IdentityUser inheritance in ApplicationUser class.
Remove from Areas/identity/Pages/Account/Register.cs all things related to EmailSernder if you have no its implementation.
In order to check correctness of the roles system you may do as follows. In the end of ConfigureServices method in Startup.cs add this code:
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdministratorRole", policy => policy.RequireRole("Administrator"));
});
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeFolder("/Contact","RequireAdministratorRole");
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
If it does not worki then just add [Authorize(Roles = "Administrator")] to Contact Page model, so it will look something like this:
namespace Sobopedia.Pages
{
[Authorize(Roles = "Administrator")]
public class ContactModel : PageModel
{
public string Message { get; set; }
public void OnGet()
{
Message = "Your contact page.";
}
}
}
Now, in order to open Contact page you should be logged in with login someone#somewhere.com and password _AStrongP#ssword!123.
I have an MVC 5 application that allows users to download files that are stored in the database. I am using the FileContentResult action method to do this.
I can restrict access to this method throughout the application, but a smart user can figure out the action URL and paste something like this (localhost:50000/Home/FileDownload?id=13) into their browser and have access to download any file by just changing the parameter.
I want to restrict users from doing this. Only allow the Administrator role AND users that have a specific permission that can only be determined by a database call to download files.
What I am looking for is that If an user uses the URL to download a file and does not have the proper permissions, I want to redirect the user with a message.
I would like to do something like the code below or similar, but I get the following error: Cannot implicitly convert type 'System.Web.Mvc.RedirectToRouteResult' to 'System.Web.Mvc.FileContentResult'
I understand that I can not use return RedirectToAction("Index") here, just looking for some ideas on how to handle this problem.
public FileContentResult FileDownload(int id)
{
//Check user has file download permission
bool UserHasPermission = Convert.ToInt32(context.CheckUserHasFileDownloadPermission(id)) == 0 ? false : true;
if (User.IsInRole("Administrator") || UserHasPermission)
{
//declare byte array to get file content from database and string to store file name
byte[] fileData;
string fileName;
//create object of LINQ to SQL class
//using LINQ expression to get record from database for given id value
var record = from p in context.UploadedFiles
where p.Id == id
select p;
//only one record will be returned from database as expression uses condtion on primary field
//so get first record from returned values and retrive file content (binary) and filename
fileData = (byte[])record.First().FileData.ToArray();
fileName = record.First().FileName;
//return file and provide byte file content and file name
return File(fileData, "text", fileName);
}
else
{
TempData["Message"] = "Record not found";
return RedirectToAction("Index");
}
}
Since both FileContentResult and RedirectToRouteResult are inherited from ActionResult, simply use ActionResult instead of FileContentResult for your action's return type:
public ActionResult FileDownload(int id)
{
if(IsUserCanDownloadFile()) // your logic here
{
// fetch the file
return File(fileData, "text", fileName);
}
return RedirectToAction("Index");
}
Or if you prefer attributes, you could write your very own authorize attribute to check permissions:
public class FileAccessAttribute : AuthorizeAttribute
{
private string _keyName;
public FileAccessAttribute (string keyName)
{
_keyName = keyName;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// imagine you have a service which could check the Permission
return base.AuthorizeCore(httpContext)
|| (this.ContainsKey
&& _permissionService.CanDownload(httpContext.User.Identity.GetUserId(),
int.Parse(this.KeyValue.ToString()));
}
private bool ContainsKey
{
get
{
// for simplicity I just check route data
// in real world you might need to check query string too
return ((MvcHandler)HttpContext.Current.Handler).RequestContext
.RouteData.Values.ContainsKey(_keyName);
}
}
private object KeyValue
{
get
{
return ((MvcHandler)HttpContext.Current.Handler)
.RequestContext.RouteData.Values[_keyName];
}
}
}
Now you could decorate the custom attribute on your actions:
[FileAccess("id", Roles ="Administrator")]
public FileContentResult FileDownload(int id)
{
// fetch the file
return File(fileData, "text", fileName);
}
In my MVC 5 web app I have this (in AccountController.cs):
// Used for XSRF protection when adding external sign ins
private const string XsrfKey = "XsrfId";
and
public string SocialAccountProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, SocialAccountProvider);
}
How exactly is it being used for protection?
Should I set the value of XsrfKey to something more random?
Take a look at ManageController methods LinkLogin and LinkLoginCallback:
//
// POST: /Manage/LinkLogin
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LinkLogin(string provider)
{
// Request a redirect to the external login provider to link a login for the current user
return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId());
}
//
// GET: /Manage/LinkLoginCallback
public async Task<ActionResult> LinkLoginCallback()
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
if (loginInfo == null)
{
return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
}
var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
}
These are the methods that handle linking of external accounts (i.e. Google, Facebook, etc.). The flow goes like this:
User clicks "Link Account" button, which calls a POST to LinkLogin method.
LinkLogin returns ChallengeResult object, with callback url set to LinkLoginCallback method.
ChallengeResult.ExecuteResult is called by MVC framework, calls IAuthenticationManager.Challenge, which causes a redirect to the specific external login provider (let's say: google).
User authenticates with google, then google redirects to callback url.
The callback is handled with LinkLoginCallback. Here, we want to prevent XSRF and verify that the call was initiated by a user, from a page served by our server (and not by some malicious site).
Normally, if it was a simple GET-POST sequence, you would add a hidden <input> field with an anti-forgery token and compare it with a corresponding cookie value (that's how Asp.Net Anti-Forgery Tokens work).
Here, the request comes from external auth provider (google in our example). So we need to give the anti-forgery token to google and google should include it in the callback request. That's exactly what state parameter in OAuth2 was designed for.
Back to our XsrfKey: everything you put in AuthenticationProperties.Dictionary will be serialized and included in the state parameter of OAuth2 request - and consequentially, OAuth2 callback. Now, GetExternalLoginInfoAsync(this IAuthenticationManager manager, string xsrfKey, string expectedValue) will look for the XsrfKey in the received state Dictionary and compare it to the expectedValue. It will return an ExternalLoginInfo only if the values are equal.
So, answering your original question: you can set XsrfKey to anything you want, as long as the same key is used when setting and reading it. It doesn't make much sense to set it to anything random - the state parameter is encrypted, so no one expect you will be able to read it anyway.
Just leave it as is:
As the name of the member states it is a key:
private const string XsrfKey = "XsrfId";
It is defined in this manner to avoid "magic numbers" and then is used a little down in the scaffold code:
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
The value of the dictionary item is then set to the UserId property in the above code by using the XsrfKey member as the key.
IOW the code is already setting the XSRF dictionary item to the value of the user ID in the snippet. If you change the XsrfKey members value to anything else you will cause problems down the line, since the expected key "XsrfId" will have no value set.
If by changing it to something more random you are implying to change the value and not they key of the dictionary, or in other words, not set it to the user id then please see the following for an explanation of the anti forgery token inner workings.
http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages
I have a custom sharepoint workflow that I'm developing in Visual Studio. The workflow is running against a document library which has a custom content type connected to it. The content type includes a user lookup field ("owner").
I'm trying to have my workflow assign a task to the "owner" lookup field. However, I've only been able to get the display name for the user, not the account username.
Can anyone help?
Refer to this Article on how to get the User Details from the Field.
public static SPUser GetSPUser(SPListItem item, string key) {
SPFieldUser field = item.Fields[key] as SPFieldUser;
if( field != null) {
SPFieldUserValue fieldValue = field.GetFieldValue(item[key].ToString()) as SPFieldUserValue;
if(fieldValue != null)
return fieldValue.User;
}
return null;
}
Your Code should be like this
SPUser spUser=GetSPUser(splistItem,"Owner");
String sUserName=(spUser!=null)?spUser.UserName:null;
My solution:
public static SPUser GetSPUser(SPListItem item, string key)
{
SPUser user=null;
SPFieldUserValue userValue = new SPFieldUserValue(item.Web, item[key].ToString());
if (userValue != null)
{
SPUser user = userValue.User;
}
return user;
}
How To Call:
SPUser spUser=GetSPUser(splistItem,"Owner");
This is tested code and working fine.
I have built custom Membership and Role providers. Users are some clients that belong to the company and I am using Company as a Role.
I would like to create SharePoint Group and add more companies to it (for example type of industry) and then do redirecting and security by the SPGroup.
How do I retrieve SPGroup for the current logged in user ?
I would like to this in my custom Login page so another problem is how do I retrieve SPUser or SPGroup knowing login name ?
This is what I have now:
private List GetGroupsForUser(List roleAccounts)
{
List groups = new List();
SPSecurity.RunWithElevatedPrivileges(
delegate()
{
using (SPSite site = new SPSite(SPContext.Current.Web.Site.ID))
{
SPUserCollection users = site.RootWeb.SiteUsers;
foreach (string account in roleAccounts)
{
SPGroupCollection accGroups = users[account].Groups;
foreach (SPGroup spg in groups)
{
groups.Add(spg);
}
}
}
}
);
return groups;
}
private string GetRoleManagerName()
{
foreach (KeyValuePair setting in SPContext.Current.Site.WebApplication.IisSettings)
{
if (string.IsNullOrEmpty(setting.Value.RoleManager) == false)
return setting.Value.RoleManager.ToLower();
}
return null;
}
private List GetSpAccounts()
{
List roleAccounts = new List();
string roleProviderName = GetRoleManagerName();
foreach (string role in Roles.GetRolesForUser(login.UserName))
{
roleAccounts.Add(roleProviderName + ":" + role.ToLower());
}
return roleAccounts;
}
// and now I can use it
List roleAccounts = GetSpAccounts();
List groups = GetGroupsForUser(roleAccounts);
But I have a felling that I should not have to do this manually like this. How will Target Audience work if only role is added to the group ?
Use the OwnedGroups property of the SPUser class to return the collection of groups owned by a user.
Update misunderstood the question:
Get the currently logged in user: SPContext.Current.Web.CurrentUser
Add that use to a group: SPGroup.Users.Add([username],[email],[name],[notes]);
Update, third times the charm. So you want to find out what group the user is in based on the roles they have?
It's a bit of a combination of the above two attempts at answering it:
var matched = from r in SPContext.Current.Web.CurrentUser.Roles
where r.Name = [Role]
select r.Groups;
Important note that the Roles property won't work in the next version of SharePoint!
Personally I think SPContext.Current.Web.CurrentUser.Groups would be an easier way to figure out what groups the user is in, but it ignores your role requirementment.