Is there built in methods into .net framework to do the following:
Get role GUID from user name/user GUID
Get role name from role GUID
So far I have been sending queries to the asp_roles and asp_users tables to obtain that information and I'm wondering if there is a nicer way of doing this?
I have the following methods that I store in the ASPUtilities class:
getRoleGUID(guid userGuid) { LINQ joins }
getRoleGuid(string userName) { LINQ joins }
getRoleName(guid roleGuid) { LINQ joins }
EDIT:
I have just looked into extending SQLMembershipProvider examples.
Few examples completely override the SQLMembershipProvider, but I think what I'm interested is just adding few extra methods to deal with the roles by using LINQ. Is this feasible?
If you extend the SQLMembership provider, it will do the exact same thing, send queries to the database to get that information since the roleID is not stored in session. If you don't want to go through that much trouble, you could do a few things.
Create a custom class with these methods that you can call and will return the ID for you of your role. Essentially, move all of your queries to one location.
Store the role ID in session on login. Call your method you created above once and don't requery everytime. Not 100% of the security risks with this one, however, since you are storing some possibly sensitive role information, the id, in session. Might just be overly cautious though :)
Related
Imagine we have the following db structure
Organization
{
Guid OrganizationId
//....
}
User
{
Guid UserId
}
OrganizationUsers
{
Guid OrganizationId
Guid UserId
}
When the edmx generated this class it abstracts away the OrganizationUsers into a many to many references. So no POCO class will be generated for it.
Say I'm loading data from my context, but to avoid Cartesian Production, I don't use an include I make two seperate queries.
using(var context = new EntitiesContext())
{
var organizationsQuery = context.Where(FilterByParent);
var organizations = organizationsQuery.ToList();
var users = organizationsQuery.SelectMany(x => x.Users).Load();
}
Is it safe to assume that the connected entitites are loaded?
Would this make any difference if I loaded the users directly from the DBSet?
From database point of view:
Is it safe to assume that the connected entitites are loaded?
Yes It's safe, because first organizations being tracked by EF Change Tracker and then by calling Load in next statement EF knows that results should be attach to tracked entities
Would this make any difference if I loaded the users directly from the DBSet?
In fact using Load this way does nothing better than Include!
If you use Include EF translate it to LEFT JOIN, if you use Load it will be translated to INNER JOIN, and if you fetch Users directly by their ids using Contains method it will be translated to IN on Sql side.
In Load and Contains cases you execute two query (in two pass) on Sql, but in Include case it's being done in one pass, so overally it's outperform your approach.
You can compare these approaches yourself using Sql Profiler tool.
Update:
Based on conversations I realized that the main issue of Johnny is just existence of OrganizationUsers object. So I suggest to change your approach from DB First to Code first then this object explicitly could be exist! See this to help you on this way
Also another approach that I guess maybe work is customizing T4 Template that seems harder but not impossible!
I am making an API with .NET Core 2.1 with SQL database and EF core.
My "Item" model contains a User because when an Item is created it belonges to a User.
How am I supposed to query Items for a User from det database in my API? I feel like its bad practice to pass the userID as a paramater in a GET request.
I think I need som kind of token authorization, but all I can find on the internet is about making access for roles. I need a user to only be able to access its own data.
I am pretty new to all of this, so I will appreciate an easy solution.
Here is my current code(Not good practice?):
[HttpGet("{id}/items")]
public IEnumerable<Item> GetUserItems([FromRoute] int id)
{
var items = Context.Items.Where(i => i.User.UserId == id);
return items;
}
If you need the items of the logged user, you can inject IHttpContextAccessor and in _httpContextAccessor.HttpContext.User you should find what you need.
Otherwise add a GUID "IdentityId" with an index to the user class and query using that:
context.Users.FirstOrDefault(u => u.IdentityId == guid)?.Items;
They are 2 different things.
Firstly, passing ID is considered bad for some people (not me). To fix this, you may want to add a GUID column to your user table, then use that GUID instead of ID.
Secondly, about allowing 1 user to access only his own data. This requires some work. But in general you need to have a look at authentication claim-based (https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-3.1). In that link, in the example, you can see they use "EmployeeNumber" claim, you can do same thing with your new GUID column.
From the question title you might guess what is this about. I'll try to describe what I currently have and what I want to archive.
Suppose an application that handles four entities: User, Team, Repository and Document. The relationships between those entities are:
Each user belong to zero or more teams.
Each document belong to one repository
An user may own zero or more repositories
Each repository can be created as public or private
The content of a public repository is visible to all users who share a team with the repository's owner.
A private repository is only visible to it's owner.
Accessing documents of an user is not a problem, those are all documents stored in repositories that he owns. But the thing get complicated because what I really need is all documents visible to an user, this is all it's documents plus those documents other people made public and share a team with him.
Currently I'm enforcing this authorization mechanism in the Data Access Layer. This implies fetching all documents and do some filtering following rules above. I'm aware that this implementation is not scalable and I wonder if I can improve my database model by moving the authorization logic to the database. This way the filtering will be done by the DB engine and only requested entities will be returned to the client code.
This question is not tied to an specific implementation, but I'll tag it for the specific tools I'm using. Maybe it can be useful for someone's answer.
First let me explain why using entity framework (or another ORM tool) is more elegant than using stored procedures.
Stored Procedures are evil. That's why. As the link explains in detail, stored procedures tend to grow as a second BL and are therefore difficult to maintain. A simple task as renaming a column will become a big task when this column is used in multiple stored procedures. When you use a ORM tool, visual studio will do most of the work for you.
That said brings me to the second advantage of entity framework. You can compose your query by using your favorite .net language. Entity framework will not execute your query directly. You control when the query will be executed as you can read here. When doing this entity framework will compile your Linq statements to a complete tsql statement and run this against the database. So there is absolutely no need to fetch all data and loop through each record.
Tip: Move your cursor over the variable name and ef will give you a preview of the TSQL statement it will compile.
So how should your Linq query look like? I composed a test database based on your description and made an entity framework (ef6) model of it which looks like:
This Linq query will do what you want, at least as I understood your question correctly.
private IEnumerable<Document> GetDocumentsOfUser(Guid userId)
{
using (var db = new DocumentRepositoryEntities())
{
// Get owned repositories by the user
var ownedRepositories = db.Repositories
.Where(r => r.Owner.UserId == userId);
// Get all users of teams the user belongs to
var userInOtherTeams =
db.Users.Where(u => u.UserId == userId)
.SelectMany(u => u.Teams)
.SelectMany(t => t.Users);
// Get the public repositories owned by the teammembers
var repositoriesOwnedByTeamMembers =
userInOtherTeams.Where(u => u.Repositories.Any())
.SelectMany(u => u.Repositories)
.Where(r => !r.Private);
// Combine (union) the 2 lists of repositories
var allRepositories = ownedRepositories.Concat(
repositoriesOwnedByTeamMembers);
// Get all the documents from the selected repositories
return allRepositories.SelectMany(r => r.Documents)
.Distinct()
.ToArray(); //query will be composed here!
}
}
Note that the linq statement will be compiled to a TSQL select statement when the call to .ToArray() is made.
Based on your description, the goal is to find all of the repositories that the user currently has access to, then retrieve the documents from each of those repositories.
If this were my implementation, I would add a stored procedure to the database that accepts the current user's ID, then gathers the list of accessible repositories into a local table variable, then select from the documents table where the repository for the document is in the list of accessible repositories.
DECLARE
#Teams TABLE (TeamID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY (TeamID))
DECLARE
#Repositories TABLE (RepositoryID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY (RepositoryID))
/* Get the list of teams the user is a member of */
INSERT INTO #Teams
SELECT Teams.TeamID
FROM Teams INNER JOIN TeamUsers ON Teams.ID = TeamUsers.TeamID
WHERE TeamUsers.UserID = #UserID
/* Get the list of repositories the user shares a team member with */
INSERT INTO #Repositories
SELECT RepositoryID
FROM Repositories
WHERE OwnerID = #UserID
OR (OwnerID IN (SELECT DISTINCT TeamUsers.UserID
FROM TeamUsers INNER JOIN #Teams ON TeamUsers.TeamID = #Teams.TeamID)
AND IsShared = 1)
/* Finally, retrieve the documents in the specified repositories */
SELECT Documents.*
FROM Documents INNER JOIN #Repositories ON Documents.RepositoryID = #Repositories.RepositoryID
While the answer competent_tech suggests is valid, and good if your need is a one-off, what you would ideally want to do is implement your authorization requirements in a dedicated layer, in an externalized fashion. Reasons to do this include:
easier to maintain a decoupled architecture
you can update your authorization without touching your application and/or database
you do not need SQL / stored procedure knowledge
you can report more easily on what authorization is applied where: this is important if you have auditors breathing down your neck.
To achieve externalized authorization (see here for a Gartner report on the topic), you need to consider attribute-based access control (ABAC - see here for a report on ABAC by NIST) and the eXtensible Access Control Markup Language (XACML - more info here) as a means to implement ABAC.
If you follow the ABAC approach you get:
a clean, decoupled architecture with the notion of
an enforcement point or interceptor that will sit between your application and your database (in the case of ABAC applied to databases)
an authorization decision engine that reaches decisions and will produce a filter statement (a WHERE clause in the case of a SQL database) that the enforcement point will append to the original SQL statement
a policy-based and attribute-based authorization model whereby you can write authorization requirements in easy-to-understand statements instead of procedures, PL-SQL or other SQL artefacts. Examples include:
*a user can edit a document they own
a user can view documents if the user's team == the document's team
a user can view documents of another team if and only if the documents are marked as public
a user with the role editor can edit documents that belong to their team if and only if the document state is draft*
In the above examples, the user type, the resource type (document), the action (view, edit), the document's team, the user's team, and the document's visibility (private or public) are all examples of attributes. Attributes are the lifeline, the building blocks of ABAC.
ABAC can easily help you implement your authorization requirements from the simplest ones to the more advanced ones (such as can be found in export regulations, compliance regulations, or other business rules).
One neat benefit of this approach is that it is not specific to databases. You can apply the same principle and policies to home-grown apps, APIs, web services, and more. That's what I call the any-depth architecture / approach to externalized authorization. The following diagram summarizes it well:
The PDP is your centralized authorization engine.
I'm looking at creating a custom membership provider in ASP.Net MVC3 and am struggling to see how it all fits together...
I'm really looking for some best practice approaches on how to do this.
I have a User model (represnting a Users table in my database). In order to use this with the MembershipProvider functionality, should this model inherit MembershipUser? There are a number of fields in MembershipUser that I do not care about - do these have to be in the underlying SQL table for this approach to work (obviously this seems redundant, as I'll never use the columns?)
For example - should I make my model inherit MembershipUser like this?
/// <summary>
/// Class representing a registered user based on the Users database table.
/// </summary>
public class User : MembershipUser
{
public int Id { get; set; }
//here I can access some other properties I will use which are already in MembershipUser...
//Addtional properties I need specific to my app.
public bool NotifyOfNewBlog { get; set; }
public bool NotifyOfNewWallPosts { get; set; }
//...plus many more.
}
When it comes to using Membership.GetUser() further down the line, do I then cast that object everytime back to my original User object to be able to access the additional properties?
Is this the approach I should be taking? Or do I a separate User model and then a CustomMembershipUser model which links back to the DB model?
Will EF be able to save/update/insert a User model if it doesn't have all the MembershipUser columns as objects in the table? Is this even anywhere near the correct approach? As you can see, I'm scratching my head a bit here.
Any advice/thoughts/ideas are much appreciated.
As far as inheriting the MembershipUser object goes, you could do that, and in your implementation of MembershipProvider, just cast up to your derived type, but I personally would not do this, simply because you are then at the mercy of future changes to this type breaking your derived type (although this could be said about most of the framework I guess). I would instead put these additional values into a profile, and roll your own ProfileProvider, (don't use the Sql one it is rubbish from my experience).
"There are a number of fields in MembershipUser that I do not care about - do these have to be in the underlying SQL table for this approach to work (obviously this seems redundant, as I'll never use the columns?)"
If you are rolling your own, you can just not save this in the Db. After all, you are implementing the MembershipProvider methods (GetUser etc etc) so what you do with the MembershipUser object passed to you, is up to you. You can just ignore these, and not validate or store them.
I had quite the same problem a while ago, and in the end i decided not to pollute my EF models with Membership logic. I have my data access tier in my application, and my EFMembershipProvider use that when he has to save/update data. If i have to GET user data in my application (other than in the membership itself), i don't use Membership (and i don't have to cast nothing).
I want to make clear that if you implement your own Membership Provider
public class EFMembershipProvider : MembershipProvider
you can abstract the underlying functionality of the membership facility to use your own models/repositories.
You can find an example of an implemented membership provider for EF in the MVC3 boilerplate
https://github.com/crdeutsch/MVC3-Boilerplate
Under Web/Infrastructure (though you probably want to modify large parts of it).
I'm using NHibernate to load some objects into my ASP.NET MVC application.
For example, a submission is submitted by a user, and I want to display the username (but only the username) of a user, like this:
<%= Html.Encode(item.User.UserName) %>
When I load a submission using NHibernate, the User is lazy-loaded from the database, which means that the actual SQL query (to load user information) will only be generated and executed when I call the above line of code (which is what I want).
The problem is that the SQL query also selects other information about the user, like it's password, email, etc. This information is obviously not needed and is discarded.
The SQL query looks like this :
SELECT id, username, password, email FROM User WHERE Id = 1;
I conclude that NHibernate only lazy-load references to other objects that are mapped to tables in my database. It does not seem to lazy-load basic, primitive types like strings, ints, etc.
Can I do that? When the above line a code is selected, I would like the SQL query look something like this:
SELECT username FROM User WHERE Id = 1;
Is this possible? How?
Is there a reason you don't want to load the complete object? Except in rare cases, there's no real performance difference.
I can understand not wanting to load the password into memory, although it should be encrypted and probably shouldn't be in your domain model anyway. What I would do in your case is subclass User into two classes, User and UserProfile (containing the password, etc.), so that you only work with the UserProfile object when you are managing the user account.
You'll need to use a resultTransformer to map the query result to the object you want to store it (which I understand is your normal User DTO class but minus all the other fields)
Check this out http://docs.jboss.org/hibernate/stable/core/reference/en/html/querysql.html (its Hibernate, not NHibernate, but it should still apply) specifically section 16.1.5