ASP .NET 5 MVC 6 Identity 3 Roles Claims Groups [closed] - asp.net

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm currently looking for a solution to use an advanced Roles/Group Permission management in ASP .NET 5 MVC 6 with Identity 3. I started a new Preview Starter Web Project with a integrated easy login system.
Now I need a complex "users permission management" with following functions:
users can be in multiple groups/roles
a group/role have many access objects (e.g. CanAccessUser, CanEditUser...)
these access objects (maybe claims?) of each group/roles complement each other
(optional for the ultimate solution): additionally => access objects(maybe claims) can be assigned independently by a group to a user
I have seen that identity already broadly provides a fitting for me table structure . (e.g. AspNetUsers, AspNetUserRoles, AspNetRoles, AspNetRoleClaims),
But I'm missing a good example / documentation to use them.
For MVC 5, I used this example: Users have many groups, a group can have many roles (Roles are the Access Objects in source code for classes / functions)
ASP.NET Identity 2.0: Implementing Group-Based Permissions Management
Exists for these requirements already a working example that you do not have to reinvent the wheel.

We were in the same boat here, without much in terms of reading apart from the source of course...
We ended up implementing Policies. Policies being a group of Claims that are required for authorization to be satisfied. these Policies can then be applied to Controllers.
You can define your Policies in Startup.cs, ConfigureServices:
services.AddAuthorization(options =>
{
options.AddPolicy("SalesSenior", policy =>
{
policy.RequireClaim("department", "sales");
policy.RequireClaim("status", "senior");
});
});
We defined Roles, assigned 1 or more Claims to them and assigned Roles to Users allowing them to be checked against the appropriate Policy on hitting a Controller.
You can inject the IAuthorizationService into a Controller or Attribute as so:
public class SalesDashboardController: Controller
{
private readonly IAuthorizationService _authz;
public VarianceOverviewController(IAuthorizationService authz)
{
_authz = authz;
}
...
}
You can then use the IAuthorizationService to check the validity of a users claims...
if (await _authz.AuthorizeAsync(User, "SalesSenior"))
{
// User is authorized
}
This article was my main source for this stuff and was a great primer for me. Good luck!

If you are looking for a sample project there are not that many out there at the moment. The first place to look is on the aspnet GitHub project pages.
Luckily, the ASP.NET Identity sub-project has a sample project that you can take a look at here, however it may not cover all your requirements. Note that this is using the latest beta.

This thread helped me get something working, but it's sad that this is not better documented.
Here are my attempts at improving that. Asp.net.Identity (3.0.0.0-rc1-final)
in Startup.cs --> ConfigurationServices
//Define your policies here, they are strings associated with claims types, that have claim strings...
//they need to be in AspNetUserClaims table, user id, department, Dev to be allowed access to the Dev policy
//add the auth option, below that makes it work, and in the api controller, add the
//[Authorize("Dev")] attribute
services.AddAuthorization(
options =>
{
options.AddPolicy("Dev", policy => { policy.RequireClaim("department", "Dev"); });
});
services.AddMvc();

Related

Upgrading from MassTransit v5 to v8 and an AutoFac Extension method used by our Multi Tenanted application is no longer available

In a nutshell I'm in the process of upgrading a .NETStandard 2.1 app to .NET 6. Plus upgrading the various libraries accordingly, in particular MassTransit v5 to v8, and AutoFac 4.9.4 to 6.4.0.
This is a multi-tenant application where one instance is shared by multiple tenants, and each tenant has their own database.
The upgrade has gone well apart from one snag. The application uses the, no longer available, AutofacReceivedEndpointExtensions to setup the Tenant details in the Consumer, and I am struggling to find a way to replicate the functionally it provides.
Below is the key bit of code.
config.ReceiveEndpoint(host, azureBusConfig.QueueName, endpoint =>
{
ConfigureConsumer<MyConsumer>(endpoint, componentContext);
});
private static void ConfigureConsumer<TConsumer>(IServiceBusReceiveEndpointConfigurator endpoint, IComponentContext componentContext, Action<IConsumerConfigurator<TConsumer>> configure = null)
where TConsumer : class, IConsumer
{
endpoint.Consumer(componentContext, configure, configureScope: (container, context) =>
{
var tenantName = context.Headers.Get<string>("tenant");
var userId = context.Headers.Get<int>("userId");
container.RegisterInstance(new NamedTenantInfoProvider(tenantName, userId)).As<ITenantInfoProvider>();
});
}
The endpoint.Consumer method as shown is no longer provided.
The ITenantInfoProvider interface is injected into various constructors in the application e.g., to setup the dbContext for a tenant to point to the correct database.
public interface ITenantInfoProvider
{
string GetTenantName();
int? GetUserId();
}
There are two implementations of the ITenantInfoProvider. The NamedTenantInfoProvider which is used to set the Tenant from the received message, above.
There is also a RequestTenantInfoProvider, that gets the Tenant from the HttpRequest. e.g. via api call.
The RequestTenantInfoProvider is registered as follows
builder.RegisterType<RequestTenantInfoProvider>()
.As<ITenantInfoProvider>()
.InstancePerLifetimeScope();
So, what should happen is that the RequestTenantInfoProvider is injected into the constructors by default, but when a message is being consumed the NamedTenantInfoProvider instance is injected instead.
I have tried to register the NamedTenantInfoProvider as per the RequestTenantInfoProvider. Then inject an IEnumerable into the constructors. And set the Tenant in the consumer.ConfigureConsumer on the Named instance. Then use which ever instance has a Tenant set in the code. However, the NamedTenantInfoProvider instance is set after it is required in the other constructors e.g., dbContext.
The only way I can get the application to fully work is to hardcode a Tenant name in the NamedTenentInfoProvider class.
I was hoping that someone has already refactored some similiar code to replace the endpoint.ConfigureConsumer call and can advise a solution.
It may be that I'm missing a bit of knowledge regarding how scoping works with the Microsoft Dependency Injection/MassTransit configuration. Note: I didn't write the original application, and this is my first dabble with Mass Transit as well.
MassTransit v8 (and onward) only support IServiceCollection, which is part of Microsoft.Extensions.DependencyInjection. Third-party containers are no longer directly supported.
There is a Scoped Filter sample that might help you understand how scopes work with MSDI. The token concept is similar to that used by developers injecting "tenant info" into consumers.

Extending current User class to handle Identity

We are using forms authentication on our ASP.NET website but are wanting to upgrade to the new Identity Provider. Currently we are using the database first approach and are ultimately wanting to just extend our current User table (not aspnet_users) to use the new identity format. We are using StructureMap to inject our context into our business logic classes. For instance our User service currently has this as its constructor:
private readonly SiteModelContainer _context;
public UserService(SiteModelContainer context)
{
this._context = context;
}
And in our IoC registry we have this:
var ecsbuilder = new EntityConnectionStringBuilder();
ecsbuilder.Provider = "System.Data.SqlClient";
ecsbuilder.ProviderConnectionString = #"data source=***;initial catalog=***;persist security info=True;User ID=***;Password=***;multipleactiveresultsets=True;App=EntityFramework";
ecsbuilder.Metadata = #"res://*/Data.***.csdl|res://*/Data.***.ssdl|res://*/Data.***.msl";
string connectionString = ecsbuilder.ToString();
For<SiteModelContainer>().Use<SiteModelContainer>().Ctor<string>("connectionString").Is(connectionString);
For<IUserService>().Use<UserService>();
...all the rest of our services
We are also using database first with EDMX and entity framework. Previously we just used ASP.NET authentication as it came out the box and had a separate user table to store profile information, but would like to have everything working off one users class instead.
1)Is it possible to extend our userservice to handle everything related to using Identity? So that Identity uses the same context that we inject into our classes? If so, I am unable to find any articles about it?
2) Are we able to extend our User object if it is created in the EDMX file?
Thanks
I have migrated 2 fairly large projects from MembershipProvider into Asp.Net Identity and both of the times I ended up rewriting most parts of the user-management and everything that touched user. A fairly chunky rewrites.
What you ask for is possible, but hard and very time consuming. You may start from this question - the OP have got his db-first project running with identity. And we had a discussion in comments with some links that might help you.

Extending SimpleMembership to support Multi-Tenancy

I have a multi-tenant app that's using SimpleMembership. Each User in my system is linked to one or more Tenants. I've extended Users simply by adding the required fields to the User model (and Tenants):
public class User{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public virtual ICollection<Tenant> Tenants { get; set; }
}
This is working great. But now I'd like to have Roles be tenant-specific, where some role types MUST have a TenantId defined. This isn't as simple as the user problem, as each of the following will be affected:
Adding Roles, Checking Roles:
if (!Roles.Privider.RoleExists("Moderator")) // I now want to include TenantId here
{
roles.CreateRole("Moderator"); // and here
}
Assigning/Checking Roles Using Provider:
if (!Roles.IsUserInRole("Admin", "SystemAdministrator")) // and here
{
roles.AddUsersToRoles(new[] { "Admin" }, new[] { "SystemAdministrator" }); // and here
}
Role Attributes:
[System.Web.Http.Authorize(Roles = "SystemAdministrator")]
public class AdminApiController : BaseApiController
User.IsInRole:
if (User.IsInRole("Administrator"))
{
I'm pretty new to ASP.NET, so I'm not sure where to begin here. Should I be overriding the SimpleMembership Role Provider somehow, or should I look into writing my own Role columns, classes, etc? It would feel wrong to hand-code anything around authentication... Any pointers around this would be much appreciated.
The first problem I see with implementing this is the use of the AuthorizeAttribute because attributes require constant information defined at compile time. With your tenant-based approach I would think which tenant to check would need to be determined during run-time. So the first thing I would do is take the approach described in this article on Decoupling You Security Model From The Application Model With SimpleMembership. Now you decorate this attribute with a resource and operation (which will be static) and you can configure what roles are assigned to the resource/operation at run-time in the database. This gives you a lot more flexibility in designing your security model as you add tenants.
Changing the database model for anything but the UserProfile table in SimpleMembership is not possible (See this QA). So adding tenant ID's to roles is not possible without writing your own membership provider. If you want to stick with using SimpleMembership one solution is to handle this in your naming convention for roles, where you include the role name and tenant name or ID. For example, if you have two tenants that have the admin role you would have two roles that are named "Administrator_Tenant1" and "Administrator_Tenant2". If you need to display this to any users that assign roles you could clean up the name by stripping out the tenant ID/Name for viewing.
If this is a new project and you are not tied to SimpleMembership you may want to look at using at Microsoft's latest membership system called ASP.NET Identity. This membership system replaces SimpleMembership in MVC 5. ASP.NET Identity was built to be easily customized and you should be able to change the role model. There is an article on customizing ASP.NET Identity here.

Programming a Web Portal for Microsoft Dynamics CRM

I'm working on a web portal for customers that will connect to Microsoft Dynamics. I don't want to make Dynamics CRM directly a internet facing deployment (IFD), so I'd like to use a separate database that the web interface interacts with and then use web services to move the data between the web portal database and Dynamics CRM.
I'm just looking for thoughts on whether this is the best way to proceed and whether there are any good code examples, etc. that I can look at for implementing this?
I saw Microsoft has a Customer Portal but it looks like it requires (at a cursory glance) an IFD deployment - which I don't want.
First, after creating your ASP.NET project (WebForms or MVC 3), add the following references:
Microsoft.crm.sdk.proxy.
Microsoft.xrm.sdk.
System.Runtime. Serialization.
System.ServiceModel.
In your code-behind Create a class then add the following code:
private IOrganizationService GetCrmService(string userName, string password, string domain, Uri serviceUri)
{
OrganizationServiceProxy _serviceProxy;
ClientCredentials credentials = new ClientCredentials();
credentials.Windows.ClientCredential = new System.Net.NetworkCredential(userName, password, domain);
//credentials.UserName.UserName = userName; // uncomment in case you want to impersonate
//credentials.UserName.Password = password;
ClientCredentials deviceCredentials = new ClientCredentials();
using (_serviceProxy = new OrganizationServiceProxy(serviceUri,
null,
credentials,
deviceCredentials))
{
_serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
return (IOrganizationService)_serviceProxy;
}
}
If you want to retrieve multiple records:
string fetch = #"My Fetch goes here";
EntityCollection records = getCrmService().RetrieveMultiple(new FetchExpression(fetch));
I highly recommend to download the SDK or check this
You'll find many samples and walkthroughs which will help you to build good portals.
I think it's a good strategy because:
It allows you to asynchronously put the data entered on the website into the CRM. This decoupling ensures neither the CRM nor the Website will become eachother's bottleneck.
Only the intermediate service layer is internet facing, so you'll be in control over what CRM information would be disclosed/open for alteration if this service layer is compromised.
The architecture you're after is reminiscent of the way the CRM Asynchronous Service works (asynchronous plugins and workflows work this way).:
A job is put in a queue (table) in the CRM DB.
A scheduled service awakes every x seconds and fetches the latest y records from the queue table.
The service performs each job and writes the result (success, error message log) back to the queue table's records.
So the thing that is probably hardest is writing a good scheduled service that never throws an exception (but always digests it) and properly logs the results back to the DB.
To learn more about the Dynamics CRM's "Asynchronous Service Architecture", refer to the following: http://msdn.microsoft.com/en-us/library/gg334554.aspx
It looks like a good approach.
It will improve the performance of both the portal and CRM.
The data shown on portal is NEARLY realtime. i.e it is NOT realtime.
Throughout the development, you better keep checking that there is not TOO MUCH async processing to keep the CRM server busy all time.
I don't think, that the accelerators/portals REQUIRE CRM to be an IFD instance, I guess only the portal part needs to be Internate facing (of course to make it usable for the purpose!)
Anwar is right, SDK is a good lauchpad for such research.
Customer Portal Does not require IFD deployment. And if you do not like the Customer Portal you can always use SDK Extension for Portal development (microsoft.xrm.client.dll & microsoft.xrm.portal.dll and portalbase solution) which are all included in SDK.
There is a great resource regarding how to build portal by using SDK Portal Extenstion.
Dynamics CRM 2011 Portal Development

Multi-Tenant in windows azure asp.net MVC2

Anyone knows how can i start to develop a multitenant site in MVC2, in a way it run on Windows Azure?
I search a lot about this question, and i allways find theoric explanations, everybody says it can be easily done, but i dont find any sample...
Can someone explain me where to start?
Thanks,
João
It depends on how you plan on implementing multitenancy (eg. using authorization with common urls, subdomains, custom domains, or any combination). But you should be able to do just about any approach with Azure and MVC2. If you plan on using a custom domain for each tenant, versus a subdomain, you will need to be happy with using CNAME entries (not A records) to point each custom domain to Azure but that usually is not a problem.
MVC offers many extension points where you can implement multitenancy in its various flavors. The main goal is to uniquely identify the user by either a login or the url.
We have an MVC2 application running in Azure that parses the request url to differentiate the tenant. There are many ways to do this. We took the approach of extending the Controller class to provide our app with the unique tenant information so we could use it as needed to make appropriate repository calls to display the proper views etc.
Here is a sample of what a MultiTenant Controller might look like:
public class MultiTenantController : Controller {
public string TenantCode { get; set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
TenantCode = GetTenantCode(filterContext.HttpContext.Request);
}
private string GetTenantCode(System.Web.HttpRequestBase request) {
string host = new RequestParser(request.Url.AbsoluteUri).Host;
return _tenantService.GetTenantCodeByHostAddress(host);
}
}
NOTES:
The RequestParser function
above is just any implementation
that knows how to parse urls in a
safe manner.
_tenantService
can access some kind of persistent
store (Azure Tables in our case) to
get the TenantCode from the host
address in the url.
All of your controllers would inherit from the above class. Then, to differentiate between tenants you just refer to the TenantCode within your controller like so:
public class HomeController : MultiTenantController {
...
public ViewResult Index() {
var vm = _homeService.GetHomePageViewModelForTenant(TenantCode);
return View(vm);
}
}
Using the above implementation you could serve different sites or data to urls like the following:
http://subtenant1.yourdomain.com
http://subtenant2.yourdomain.com
http://www.customtenantdomain.com
Your backend store (eg. Table Storage) just needs to cross reference host names with the tenant like the table below. In the code above GetTenantCode would access the data.
HostName TenantCode
---------------------- --------------
subtenant1 Tenant1ID
subtenant2 Tenant2ID
www.customtenantdomain Tenant3ID
For www.customtenantdomain.com to work, the tenant needs a CNAME entry for www in their DNS records for customtenantdomain.com that points to your Azure Web Role's address.
Its hugely complex and not something to be taken on lightly. However take a look at the source code for Microsoft's Orchard project. This has full multi-tenancy capabilities if thats what you need: http://orchard.codeplex.com/
And they have a build that works in Azure too.
In this guide we cover aspects of this and it includes a full sample using MVC 2.
link text
First , all answers are very very helpful.It's changing your decision what you want setting up your multitenancy.I mean the most important thing is Identifying all tenant in your app so there is a lot of way for solution.For example you can hold your tenant via subdomains or URL surfing.And also maybe you can store your data multitenat database.
There are very very helpul posts are written by Steve Morgan.
I only help you for set startup multi- tenancy.Here are the blogs :
Identifying the Tenant in Multi-Tenant Azure Applications - Part 1
Identifying the Tenant in Multi-Tenant Azure Applications - Part 2
Identifying the Tenant in Multi-Tenant Azure Applications - Part 3
And here are the Multi-Tenant Data Strategies for Windows Azure :
Multi-Tenant Data Strategies for Windows Azure – Part 1
Multi-Tenant Data Strategies for Windows Azure – Part 2

Resources