Providing access to User Groups using Identity Server 3 - asp.net-mvc

The application I'm currently working on is a huge ASP.NET MVC web application which uses traditional Windows Authentication model. We are trying to migrate to Single Sign On model using Identity Server 3 and Open ID Connect.
Coming to my question, is there any way/work around to provide access on a user group basis when using Identity Server? The problem here is that the my user groups could either be role based or Active directory groups. I'm looking for something like InMemoryGroup (similar to InMemoryUser).
Something that mimicks the following for a Group of users that can be role based or not:
new InMemoryUser
{
Username = "harry",
Password = "thisispassword#123",
Subject = "1",
Claims = new Claim[]
{
new Claim(Constants.ClaimTypes.Name, "Harry Potter"),
new Claim(Constants.ClaimTypes.GivenName, "Harry"),
new Claim(Constants.ClaimTypes.FamilyName, "Potter"),
new Claim(Constants.ClaimTypes.Email, "harry.potter#hogwarts.com"),
new Claim(Constants.ClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
new Claim(Constants.ClaimTypes.Role, "Administrator"),
}
}
I'm relatively new to Identity Server and Open ID Connect and not able to find anything online and would really appreciate any leads.

To represent the fact that a user is a member of a group you just add a claim. You could add:
new Claim("Group", "Hogwarts Student")
to your in memory user. The claim indicates that Harry is a member of the "Hogwarts Student" group. There is a couple of things going on here you want to be aware of. The constructor being called is:
new Claim(string claimType, string claimValue)
There Identity Server provides some standard ones in the Constants class but you can make up your own. Also, you can have multiple group claims, so you could have
new Claim("Group", "Hogwarts Student"),
new Claim("Group", "Gryffindor House)
If you wanted to see if Harry was in the "Gryffindor House" group, you'd just search through is list of claims where the claim type is equal to "Group" and the claim value is equal to "Gryffindor House".
Finally, the difference between groups and roles is generally more a matter of application semantics that a physical difference in how they are stored. In general, the set of users that can perform the "Administrator" role for an application is just a group of users. It is the way that an application treats users of a group that makes the group a role.

Related

Setting up new default Roles in jhipster

How can I set up default roles in jhipster ? (using angularjs and spring).
I explain myself
in the registration page I want to specify the role for the registred user. let's say by a checkbox or a list. (for exemple human and animal )
How can I do that in the angular controller and in spring ?
What I can do now ?
I added the roles I need in the database and in angular and I can specify the roles for the new registred users , only through the Admin's users management page.
There is some work to do, to achieve that, so I will paste just the right parts with some small samples..
In general you must extend the API to become aware of a role selection, so this information can be provided explicitly. Then you change your angularJS frontend as you need.
for the backend
a registration happens by POSTing a ManagedUserVM to /api/account/register, so the first thing is to tell AccountResource.registerAccount(...) to pass a set of of strings (your roles) as additional parameter to userService.createUser
#Timed
public ResponseEntity registerAccount(#Valid #RequestBody ManagedUserVM managedUserVM) {
HttpHeaders textPlainHeaders = new HttpHeaders();
///...
User user = userService
.createUser(managedUserVM.getLogin(),
managedUserVM.getPassword(),
managedUserVM.getFirstName(),
managedUserVM.getLastName(),
managedUserVM.getEmail().toLowerCase(),
managedUserVM.getImageUrl(),
managedUserVM.getLangKey(),
//add authorities here
managedUserVM.getAuthorities()
);
mailService.sendActivationEmail(user);
//...
}
Then in UserService.createUser, you apply the set and add them to the user before saving it, by adding the Set<String> authorities to its parameters and
if (authorities != null) {
Set<Authority> authorities = new HashSet<>();
authorities.forEach(
authority -> authorities.add(authorityRepository.findOne(authority))
);
user.setAuthorities(authorities);
}
and this should be sufficient to pass authorities to /api/register/ and save them. You should be aware of users forbid to register themselves with ADMIN roles, but the security consideration is up to you and not part my answer.
apply to frontend
Knowing your API now can process also authorities, you could just pass them.
You just add some checkbox or selectbox with ng-model="vm.registerAccount.authorities" to src/main/webapp/app/account/register/register.html (if angularJS1) or
[(ngModel)]="registerAccount.authorities" tosrc/main/webapp/app/account/register/register.component.html` (if angular2).
AFAIK this should lead automatically to the angular services passing these authorities/roles to the API.
I hope my brief answer helps you to find the proper places! Feel free to ask in comments if you stuck

MVC Active Directory Authentication by Organizational Unit

I want to recycle AD security in my .NET MVC web application and have virtually no local security tables, if possible.
I can easily achieve this using the Authorize tag:
[Authorize(Roles="GoldDigger")]
public ActionResult Go(int companyKey)
{
var something = GetData(companyKey);
return something;
}
However, I have users who have access to multiple companies (Acme, StoreCo, etc.), and are GoldDiggers in some but not all of those companies. Let's say I create an Active Directory OU Container for each company, so I have the following AD role structure:
NTWRK\Acme\GoldDigger
NTWRK\StoreCo\GoldDigger
NTWRK\PetCo\GoldDigger
NTWRK\Megalomart\GoldDigger
To my knowledge I can no longer use the Authorize tag because the AD role required is determined by the value of the CompanyKey parameter.
What are my best options at this point to avoid adding the following to the top of every controller method? Is it possible to force the context of the authorization to a particular (non-hard-coded) organizational unit at the beginning or earlier in the session?
if (!AuthenticateAdRoleByCompany(companyKey, "Role Name Here"))
{
Explode();
return;
}

Best Practices for Roles vs. Claims in ASP.NET Identity

I am completely new to the use of claims in ASP.NETIdentity and want to get an idea of best practices in the use of Roles and/or Claims.
After all this reading, I still have questions like...
Q: Do we no longer use Roles?
Q: If so, why are Roles still offered?
Q: Should we only use Claims?
Q: Should we use Roles & Claims together?
My initial thought is that we "should" use them together. I see Claims as sub-categories to the Roles they support.
FOR EXAMPLE:
Role: Accounting
Claims: CanUpdateLedger, CanOnlyReadLedger, CanDeleteFromLedger
Q: Are they intended to be mutually exclusive?
Q: Or is it better to go Claims ONLY and "fully-qualify" you claims?
Q: So what are the best practices here?
EXAMPLE: Using Roles & Claims Together
Of course, you would have to write your own Attribute logic for this...
[Authorize(Roles="Accounting")]
[ClaimAuthorize(Permission="CanUpdateLedger")]
public ActionResult CreateAsset(Asset entity)
{
// Do stuff here
return View();
}
EXAMPLE: Fully-Qualifying Your Claims
[ClaimAuthorize(Permission="Accounting.Ledger.CanUpdate")]
public ActionResult CreateAsset(Asset entity)
{
// Do stuff here
return View();
}
A role is a symbolic category that collects together users who share the same levels of security privileges. Role-based authorization requires first identifying the user, then ascertaining the roles to which the user is assigned, and finally comparing those roles to the roles that are authorized to access a resource.
In contrast, a claim is not group based, rather it is identity based.
from Microsoft documentation:
When an identity is created it may be assigned one or more claims issued by a trusted party. A claim is a name value pair that represents what the subject is, not what the subject can do.
A security check can later determine the right to access a resource based on the value of one or more claims.
You can use both in concert, or use one type in some situations and the other in other situations. It mostly depends on the inter-operation with other systems and your management strategy. For example, it might be easier for a manager to manage a list of users assigned to a role than it is to manage who has a specific Claim assigned. Claims can be very useful in a RESTful scenario where you can assign a claim to a client, and the client can then present the claim for authorization rather than passing the Username and Password for every request.
As #Claies perfectly explained, claims could be a more descriptive and is a deep kind of role. I think about them as your role's ids. I have a gym Id, so I belong to the members role. I am also in the kickboxing lessons, so I have a kickboxing Id claim for them. My application would need the declaration of a new role to fit my membership rights. Instead, I have ids for each group class that I belong to, instead of lots of new membership types. That is why claims fit better for me.
There is a a great explanation video of Barry Dorrans, talking about the advantage of using claims over roles. He also states that roles, are still in .NET for backward compatibility. The video is very informative about the way claims, roles, policies, authorization and authentication works.
Or check a related session shared by Lafi
Having used various authentication and authorisation techniques over decades, my current MVC application uses the following methodology.
Claims are used for all authorisation. Users are assigned one role (multiple roles are possible but I do not need this) - more below.
As is common practice, A ClaimsAuthorize attribute class is used. Since most controller actions are CRUD, I have a routine in the code-first database generation that iterates all controller actions and creates claim types for each controller action attribute of Read/Edit/Create/Delete. E.g. from,
[ClaimsAuthorize("SomeController", "Edit")]
[HttpPost]
For use at in an MVC View, a base controller class presents view bag items
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// get user claims
var user = filterContext.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null)
{
// Get all user claims on this controller. In this controler base class, [this] still gets the descendant instance type, hence name
List<Claim> claims = user.Claims.Where(c => c.Type == this.GetType().Name).ToList();
// set Viewbag with default authorisations on this controller
ViewBag.ClaimRead = claims.Any(c => c.Value == "Read");
ViewBag.ClaimEdit = claims.Any(c => c.Value == "Edit");
ViewBag.ClaimCreate = claims.Any(c => c.Value == "Create");
ViewBag.ClaimDelete = claims.Any(c => c.Value == "Delete");
}
base.OnActionExecuting(filterContext);
}
For website menus and other non-controller actions, I have other claims. E.g. whether a user can view a particular monetary field.
bool UserHasSpecificClaim(string claimType, string claimValue)
{
// get user claims
var user = this.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null)
{
// Get the specific claim if any
return user.Claims.Any(c => c.Type == claimType && c.Value == claimValue);
}
return false;
}
public bool UserHasTradePricesReadClaim
{
get
{
return UserHasSpecificClaim("TradePrices", "Read");
}
}
So where do Roles fit in?
I have a table that links a Role to a (default) set of claims. When setting user authorisation, the default is to give the user the claims of their role. Each user can have more or less claims than the default. To make editing simple, the claims list is show by controller and actions (in a row), with other claims then listed. Buttons are used with a bit of Javascript to select a set of actions to minimise the "clicking" required to select claims. On Save, the users claims are deleted and all of the selected claims are added. The web application loads claims only once, so any changes must prompt a reload within this static data.
Managers can therefore select which claims are in each role and which claims a user has after setting them to a role and those default claims. The system has only a small number of users so managing this data is straightforward
To understand the difference between Roles and Claims you must face the limitation of roles and feel how claims come over these issues, so let me give you 2 scenarios to recognize the power of claims where role can't resolve these issues :
1- Your site has two modules (pages, service ..etc) the first module for children (under 18 years old) the other for adults (over 18 years old)
your user identity has a birthday claim
You need to create a policy on this claim so the authorization for each module will be given on this value and if the age of the user is over 18 years then he can go to the adult module and not before this age.
Role is Boolean data type you can have or not have the role, it doesn't have multi values.
2- Your site has role user and you want to prevent access of users to make some maintenance without changing the code.
In claims, you can create an UnderConstrain policy that if true the user can't view the page give property authorize for role user.
At the time of writing this answer we were at '.NET 5.0' with '.NET 6.0' just around the corner. And this is my understanding of what I've seen:
Q: Do we no longer use Roles?
Yep, you're not supposed to use Roles any longer (at least not the way you did it in the previous frameworks.
Q: If so, why are Roles still offered?
To make upgrading projects easier/faster?
Q: Should we only use Claims?
yes. But be sure to check out the video posted here in the answer by #Jonathan Ramos.
Q: Should we use Roles & Claims together?
No, but you can put a role into a claim ofcourse, but be sure to upgrade your project to use Claims only.
And you should not have to write you're own attributes, you should use policy for that, as it's the way of the newer framework. If you need you're own attributes you're "doing it wrong", just create your own Requirement(handler) that's what the whole 'new' policy is all about.
In the current framework the attribute ClaimAuthorize is not even available anymore.

finding user group name while logging with glassfish jdbcRealm

I know that while user logs in we can find the user name by
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
request.login(username, password);
Principal principal = request.getUserPrincipal();
principal.getName();
but how do i get the user Group (without doing any db query).
I tried the below but it doesn't work, it always returns false for all group.
context.getExternalContext().isUserInRole("USER")
request.isUserInRole("USER")
I want to point out that groups and roles are different concepts.
Suppose you have a web app where someone can write articles, someone can only comment and others can only read. So you have three roles: WRITER, COMMENTER and READER.
Now this web app is used internally to your organization. The organigram provides these groups: PROJECTMANAGER, ARCHITECT, SYSADMIN and DEVELOPER.
In few words roles are related to webapp, groups are related to your organigram.
In glassfish-web.xml you can bind groups and/or users to roles. For example PROJECTMANAGERs and ARCHITECTs are WRITERs, SYSADMINs are COMMENTERs and DEVELOPERs are READERs.
Thus in general there is no way to retrieve users's groups without a db query. Anyway a ploy is to create roles with the same name as groups (in glassfish-web.xml). Besides in the admin console there is a flag to automatically maps roles to groups.
A few thoughts to augment Alf's informative response:
A user may belong to multiple groups.
Each group may be have associated with it multiple roles. For GlassFish 3.1.2 the mapping between roles and groups is made in glassfish-web.xml, i.e:
<security-role-mapping>
<role-name>USER</role-name>
<group-name>USER</group-name>
</security-role-mapping>
Roles must be defined to your web-app, in web.xml:
<security-role>
<role-name>USER</role-name>
</security-role>
The above maps a group USER into a role USER in the web-app. Certainly you can choose names that differ - just keep the same value in the role-name elements for both.

Extending a member profile with two further layers - asp.net mvc

I have a modeling question related to profiles. Firstly, I have looked into using the SQLTableProvider and using the in built profiling system but didn't feel they were suitable. So, with that said, I have a membership scheme where every person has a profile, then that person can upgrade their profile to either an individual (additional fields) or a company account (additional fields again).
So I thought, use a Profile base class and then inherit from that for the Company account and Individual account. However, when it comes to implementing this in MVC I'm hitting a brick wall.
Since either the company or individual edit pages are effectively updating both the base Profile table and also the individual/company tables from the same page. How would I go about implementing this within the model (which is currently generated via LinqToSQL) and also at the view level?
Apologies if that wasn't very clear, tricky one to explain!
If you are using Linq to SQL, then you already have a model. Linq generates the entities and collections based on your database for you. The generated model is a shallow one, but is pretty solid and workable. The Linq to SQL model can be extended via partial classes allowing you to enhance entities or the context itself for additional functionality.
The controller can work directly against the generated model and pass entities or collections of entities to the view as needed.
I would suggest that, for what you appear to be trying to do, you might consider not using the built-in profile provider system at all. The profile providers in asp.net work well for simple personalization stuff, but it doesn't work well for concrete data like contact info and such. Also keep in mind that the profile provider systems tend to store object data as serialized strings in the database... this makes getting at profile data very difficult from admin tools and such. Performance starts to become a problem VERY fast in any case where you are needing multiple user's profile information (such as with an admin user editor).
For a when you are storing important personal details like the stuff you mentioned, what you are really storing are "account details" not "user profiles". You can extend a membership provider to expose your additional details, but I've generally found it much easier to just roll my own data model and access logic to deal with the additional account information.
My rule of thumb is this: if the information is ONLY needed during a request made by the user to whome the data belongs, then it goes in profiles. If I would need the data for one user to be read during another user's request, or if I would need a "list" of that data for different users, then it doesn't go in asp.net profiles.
Do you mean settings like choosing how many items to view on each page, and choosing some style sheet?
public class Profile
{
int? ItemsPerPage { get; set; }
string PreferredStyleSheet { get; set; }
}
The company selects some values that will work for users unless the users have chosen some other values for themselves. Is that what you have in mind?
In that case: I don't know how to do it together in ASP.NET Profile, but how about the following tables in the database:
TABLE Setting
(
SettingID int NOT NULL,
SettingName varchar(32) NOT NULL,
DefaultValue nvarchar(128) NULL
)
TABLE CompanySetting
(
CompanySettingID int NOT NULL,
RefSettingID int NOT NULL,
RefCompanyID int NOT NULL,
SettingValue nvarchar(128) NOT NULL
)
TABLE UserSetting
(
UserSettingID int NOT NULL,
RefSettingID int NOT NULL,
RefUserId uniqueidentifier NOT NULL,
SettingValue nvarchar(128) NOT NULL
)
And then make some joins for the present user. If the user setting is not given, take the company setting; if the company setting is not given, take the default value.

Resources